diff --git a/go.mod b/go.mod index 7553cd31..d91a8d27 100644 --- a/go.mod +++ b/go.mod @@ -18,24 +18,25 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/jackc/pgx/v5 v5.6.0 github.com/jmoiron/sqlx v1.4.0 - github.com/mattn/go-runewidth v0.0.15 + github.com/mattn/go-runewidth v0.0.16 github.com/open-policy-agent/opa v0.66.0 github.com/spf13/cobra v1.8.1 ) require ( - github.com/DataDog/zstd v1.5.5 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/DeOne4eg/eth-unit-converter v0.2.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.13.0 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.11.3 // indirect - github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v1.1.1 // indirect github.com/cockroachdb/redact v1.1.5 // indirect @@ -47,35 +48,35 @@ require ( github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/ethereum/c-kzg-4844 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 // indirect github.com/fjl/memsize v0.0.2 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.4 // indirect - github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect - github.com/gdamore/encoding v1.0.1 // indirect - github.com/getsentry/sentry-go v0.28.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect + github.com/gdamore/encoding v1.0.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/gofrs/flock v0.12.0 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/hashicorp/go-bexpr v0.1.14 // indirect - github.com/holiman/billy v0.0.0-20240322075458-72a4e81ec6da // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect + github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -83,51 +84,49 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/pointerstructure v1.2.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.11.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect + github.com/rivo/uniseg v0.4.3 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/status-im/keycard-go v0.3.2 // indirect - github.com/supranational/blst v0.3.12 // indirect + github.com/status-im/keycard-go v0.2.0 // indirect + github.com/supranational/blst v0.3.11 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect - github.com/tklauser/go-sysconf v0.3.14 // indirect - github.com/tklauser/numcpus v0.8.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect - github.com/urfave/cli/v2 v2.27.2 // indirect + github.com/urfave/cli/v2 v2.25.7 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 // indirect - golang.org/x/net v0.27.0 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/sdk v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 5949bce1..159ca802 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,16 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= -github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DeOne4eg/eth-unit-converter v0.2.0 h1:EbizT70ocvhyTYzdtVWp92Q1njj0+0aWRFMPlsca/kE= github.com/DeOne4eg/eth-unit-converter v0.2.0/go.mod h1:XDLXgMOeUv4n8BkGn817q9yDoKOJxoNdnJ2MLsdkarI= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= @@ -28,10 +30,10 @@ github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE= github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= -github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= @@ -49,8 +51,8 @@ github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaY github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a h1:f52TdbU4D5nozMAhO9TvTJ2ZMCXtN4VIAmfrrZ0JXQ4= -github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= @@ -76,10 +78,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= @@ -88,8 +90,8 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/ethereum/c-kzg-4844 v1.0.2 h1:8tV84BCEiPeOkiVgW9mpYBeBUir2bkCNVqxPwwVeO+s= -github.com/ethereum/c-kzg-4844 v1.0.2/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= @@ -106,17 +108,16 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= -github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= -github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= -github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= -github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= @@ -128,7 +129,7 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -143,8 +144,8 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gofrs/flock v0.12.0 h1:xHW8t8GPAiGtqz7KxiSqfOEXwpOaqhpYZrTE2MQBgXY= -github.com/gofrs/flock v0.12.0/go.mod h1:FirDy1Ing0mI2+kB6wk+vyyAH+e6xiE+EYA0jnzV9jc= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -184,10 +185,10 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/hashicorp/go-bexpr v0.1.14 h1:uKDeyuOhWhT1r5CiMTjdVY4Aoxdxs6EtwgTGnlosyp4= -github.com/hashicorp/go-bexpr v0.1.14/go.mod h1:gN7hRKB3s7yT+YvTdnhZVLTENejvhlkZ8UE4YVBS+Q8= -github.com/holiman/billy v0.0.0-20240322075458-72a4e81ec6da h1:8qEhdMGSUx67L2s5aGQinJhOwLfIRKLRBHPQq8m6WxE= -github.com/holiman/billy v0.0.0-20240322075458-72a4e81ec6da/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= @@ -199,8 +200,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= @@ -211,8 +212,8 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -233,8 +234,9 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= @@ -242,16 +244,13 @@ github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55h github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= -github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -274,97 +273,94 @@ github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQ github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= -github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/status-im/keycard-go v0.3.2 h1:YusIF/bHx6YZis8UTOJrpZFnTs4IkRBdmJXqdiXkpFE= -github.com/status-im/keycard-go v0.3.2/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supranational/blst v0.3.12 h1:Vfas2U2CFHhniv2QkUm2OVa1+pGTdqtpqm9NnhUUbZ8= -github.com/supranational/blst v0.3.12/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= -github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= -github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= -github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= -github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 h1:Z+vTUQyBb738QmIhbJx3z4htsxDeI+rd0EHvNm8jHkg= -golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -375,8 +371,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -406,16 +402,18 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -432,8 +430,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -451,8 +449,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/makefile b/makefile index 0b30b077..46b45996 100644 --- a/makefile +++ b/makefile @@ -19,12 +19,12 @@ GOLANG := golang:1.22 NODE := node:16 -ALPINE := alpine:3.19 -CADDY := caddy:2.6-alpine -KIND := kindest/node:v1.29.2 +ALPINE := alpine:3.20 +CADDY := caddy:2.8-alpine +KIND := kindest/node:v1.30.0 BUSYBOX := busybox:stable GETH := ethereum/client-go:stable -POSTGRES := postgres:16.2 +POSTGRES := postgres:16.3 KIND_CLUSTER := liars-game-cluster NAMESPACE := liars-system @@ -48,14 +48,15 @@ dev-setup: brew list watch || brew instal watch dev-docker: - docker pull $(GOLANG) - docker pull $(NODE) - docker pull $(ALPINE) - docker pull $(CADDY) - docker pull $(KIND) - docker pull $(BUSYBOX) - docker pull $(GETH) - docker pull $(POSTGRES) + docker pull $(GOLANG) & \ + docker pull $(NODE) & \ + docker pull $(ALPINE) & \ + docker pull $(CADDY) & \ + docker pull $(KIND) & \ + docker pull $(BUSYBOX) & \ + docker pull $(GETH) & \ + docker pull $(POSTGRES) & \ + wait; # ============================================================================== # Game UI @@ -75,7 +76,7 @@ game-ui: # ============================================================================== # Building containers -all: game-engine +build: game-engine game-engine: docker build \ @@ -143,9 +144,9 @@ dev-apply: dev-restart: kubectl rollout restart deployment engine --namespace=liars-system -dev-update: all dev-load dev-restart +dev-update: build dev-load dev-restart -dev-update-apply: all dev-load dev-apply +dev-update-apply: build dev-load dev-apply dev-logs-init: kubectl logs --namespace=$(NAMESPACE) -l app=$(APP) -f --tail=100 -c init-ge-migrate diff --git a/vendor/github.com/DataDog/zstd/README.md b/vendor/github.com/DataDog/zstd/README.md index 64481445..03f2cf66 100644 --- a/vendor/github.com/DataDog/zstd/README.md +++ b/vendor/github.com/DataDog/zstd/README.md @@ -6,8 +6,8 @@ [C Zstd Homepage](https://github.com/facebook/zstd) -The current headers and C files are from *v1.5.0* (Commit -[10f0e699](https://github.com/facebook/zstd/releases/tag/v1.5.0)). +The current headers and C files are from *v1.4.4* (Commit +[10f0e699](https://github.com/facebook/zstd/releases/tag/v1.4.4)). ## Usage @@ -19,21 +19,6 @@ There are two main APIs: The compress/decompress APIs mirror that of lz4, while the streaming API was designed to be a drop-in replacement for zlib. -### Building against an external libzstd - -By default, zstd source code is vendored in this repository and the binding will be built with -the vendored source code bundled. - -If you want to build this binding against an external static or shared libzstd library, you can -use the `external_libzstd` build tag. This will look for the libzstd pkg-config file and extract -build and linking parameters from that pkg-config file. - -Note that it requires at least libzstd 1.4.0. - -```bash -go build -tags external_libzstd -``` - ### Simple `Compress/Decompress` @@ -75,9 +60,6 @@ NewWriterLevelDict(w io.Writer, level int, dict []byte) *Writer // Write compresses the input data and write it to the underlying writer (w *Writer) Write(p []byte) (int, error) -// Flush writes any unwritten data to the underlying writer -(w *Writer) Flush() error - // Close flushes the buffer and frees C zstd objects (w *Writer) Close() error ``` diff --git a/vendor/github.com/DataDog/zstd/ZSTD_LICENSE b/vendor/github.com/DataDog/zstd/ZSTD_LICENSE index 75800288..a793a802 100644 --- a/vendor/github.com/DataDog/zstd/ZSTD_LICENSE +++ b/vendor/github.com/DataDog/zstd/ZSTD_LICENSE @@ -2,7 +2,7 @@ BSD License For Zstandard software -Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -14,9 +14,9 @@ are permitted provided that the following conditions are met: this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name Facebook, nor Meta, nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. 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 diff --git a/vendor/github.com/DataDog/zstd/allocations.h b/vendor/github.com/DataDog/zstd/allocations.h deleted file mode 100644 index 5289f24d..00000000 --- a/vendor/github.com/DataDog/zstd/allocations.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/* This file provides custom allocation primitives - */ - -#define ZSTD_DEPS_NEED_MALLOC -#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */ - -#include "mem.h" /* MEM_STATIC */ -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" /* ZSTD_customMem */ - -#ifndef ZSTD_ALLOCATIONS_H -#define ZSTD_ALLOCATIONS_H - -/* custom memory allocation functions */ - -MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) -{ - if (customMem.customAlloc) - return customMem.customAlloc(customMem.opaque, size); - return ZSTD_malloc(size); -} - -MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) -{ - if (customMem.customAlloc) { - /* calloc implemented as malloc+memset; - * not as efficient as calloc, but next best guess for custom malloc */ - void* const ptr = customMem.customAlloc(customMem.opaque, size); - ZSTD_memset(ptr, 0, size); - return ptr; - } - return ZSTD_calloc(1, size); -} - -MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem) -{ - if (ptr!=NULL) { - if (customMem.customFree) - customMem.customFree(customMem.opaque, ptr); - else - ZSTD_free(ptr); - } -} - -#endif /* ZSTD_ALLOCATIONS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/bits.h b/vendor/github.com/DataDog/zstd/bits.h deleted file mode 100644 index 59856e46..00000000 --- a/vendor/github.com/DataDog/zstd/bits.h +++ /dev/null @@ -1,203 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_BITS_H -#define ZSTD_BITS_H - -#include "mem.h" - -MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) -{ - assert(val != 0); - { - static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, - 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, - 26, 12, 18, 6, 11, 5, 10, 9}; - return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; - } -} - -MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) -{ - assert(val != 0); -# if defined(_MSC_VER) -# if STATIC_BMI2 == 1 - return (unsigned)_tzcnt_u32(val); -# else - if (val != 0) { - unsigned long r; - _BitScanForward(&r, val); - return (unsigned)r; - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (unsigned)__builtin_ctz(val); -# else - return ZSTD_countTrailingZeros32_fallback(val); -# endif -} - -MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) { - assert(val != 0); - { - static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31}; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; - } -} - -MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) -{ - assert(val != 0); -# if defined(_MSC_VER) -# if STATIC_BMI2 == 1 - return (unsigned)_lzcnt_u32(val); -# else - if (val != 0) { - unsigned long r; - _BitScanReverse(&r, val); - return (unsigned)(31 - r); - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (unsigned)__builtin_clz(val); -# else - return ZSTD_countLeadingZeros32_fallback(val); -# endif -} - -MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) -{ - assert(val != 0); -# if defined(_MSC_VER) && defined(_WIN64) -# if STATIC_BMI2 == 1 - return (unsigned)_tzcnt_u64(val); -# else - if (val != 0) { - unsigned long r; - _BitScanForward64(&r, val); - return (unsigned)r; - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) - return (unsigned)__builtin_ctzll(val); -# else - { - U32 mostSignificantWord = (U32)(val >> 32); - U32 leastSignificantWord = (U32)val; - if (leastSignificantWord == 0) { - return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); - } else { - return ZSTD_countTrailingZeros32(leastSignificantWord); - } - } -# endif -} - -MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) -{ - assert(val != 0); -# if defined(_MSC_VER) && defined(_WIN64) -# if STATIC_BMI2 == 1 - return (unsigned)_lzcnt_u64(val); -# else - if (val != 0) { - unsigned long r; - _BitScanReverse64(&r, val); - return (unsigned)(63 - r); - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (unsigned)(__builtin_clzll(val)); -# else - { - U32 mostSignificantWord = (U32)(val >> 32); - U32 leastSignificantWord = (U32)val; - if (mostSignificantWord == 0) { - return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); - } else { - return ZSTD_countLeadingZeros32(mostSignificantWord); - } - } -# endif -} - -MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) -{ - if (MEM_isLittleEndian()) { - if (MEM_64bits()) { - return ZSTD_countTrailingZeros64((U64)val) >> 3; - } else { - return ZSTD_countTrailingZeros32((U32)val) >> 3; - } - } else { /* Big Endian CPU */ - if (MEM_64bits()) { - return ZSTD_countLeadingZeros64((U64)val) >> 3; - } else { - return ZSTD_countLeadingZeros32((U32)val) >> 3; - } - } -} - -MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ -{ - assert(val != 0); - return 31 - ZSTD_countLeadingZeros32(val); -} - -/* ZSTD_rotateRight_*(): - * Rotates a bitfield to the right by "count" bits. - * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts - */ -MEM_STATIC -U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { - assert(count < 64); - count &= 0x3F; /* for fickle pattern recognition */ - return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); -} - -MEM_STATIC -U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { - assert(count < 32); - count &= 0x1F; /* for fickle pattern recognition */ - return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); -} - -MEM_STATIC -U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { - assert(count < 16); - count &= 0x0F; /* for fickle pattern recognition */ - return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); -} - -#endif /* ZSTD_BITS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/bitstream.h b/vendor/github.com/DataDog/zstd/bitstream.h index 9d92f7b5..1c294b80 100644 --- a/vendor/github.com/DataDog/zstd/bitstream.h +++ b/vendor/github.com/DataDog/zstd/bitstream.h @@ -1,16 +1,35 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * bitstream - * Part of FSE library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + bitstream + Part of FSE library + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy ****************************************************************** */ #ifndef BITSTREAM_H_MODULE #define BITSTREAM_H_MODULE @@ -18,6 +37,7 @@ #if defined (__cplusplus) extern "C" { #endif + /* * This API consists of small unitary functions, which must be inlined for best performance. * Since link-time-optimization is not available for all compilers, @@ -28,21 +48,17 @@ extern "C" { * Dependencies ******************************************/ #include "mem.h" /* unaligned access routines */ -#include "compiler.h" /* UNLIKELY() */ #include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ #include "error_private.h" /* error codes and messages */ -#include "bits.h" /* ZSTD_highbit32 */ /*========================================= * Target specific =========================================*/ -#ifndef ZSTD_NO_INTRINSICS -# if (defined(__BMI__) || defined(__BMI2__)) && defined(__GNUC__) -# include /* support for bextr (experimental)/bzhi */ -# elif defined(__ICCARM__) -# include -# endif +#if defined(__BMI__) && defined(__GNUC__) +# include /* support for bextr (experimental) */ +#elif defined(__ICCARM__) +# include #endif #define STREAM_ACCUMULATOR_MIN_32 25 @@ -134,6 +150,39 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); /* faster, but works only if nbBits >= 1 */ + + +/*-************************************************************** +* Internal functions +****************************************************************/ +MEM_STATIC unsigned BIT_highbit32 (U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; +# endif + } +} + /*===== Local Constants =====*/ static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, @@ -163,26 +212,16 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, return 0; } -MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) -{ -#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS) - return _bzhi_u64(bitContainer, nbBits); -#else - assert(nbBits < BIT_MASK_SIZE); - return bitContainer & BIT_mask[nbBits]; -#endif -} - /*! BIT_addBits() : * can add up to 31 bits into `bitC`. * Note : does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { - DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); + MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); assert(nbBits < BIT_MASK_SIZE); assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); - bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos; + bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; bitC->bitPos += nbBits; } @@ -252,7 +291,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) { - if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } bitD->start = (const char*)srcBuffer; bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); @@ -261,7 +300,7 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); bitD->bitContainer = MEM_readLEST(bitD->ptr); { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } } else { bitD->ptr = bitD->start; @@ -269,27 +308,27 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si switch(srcSize) { case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); - ZSTD_FALLTHROUGH; + /* fall-through */ case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); - ZSTD_FALLTHROUGH; + /* fall-through */ case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); - ZSTD_FALLTHROUGH; + /* fall-through */ case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; - ZSTD_FALLTHROUGH; + /* fall-through */ case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; - ZSTD_FALLTHROUGH; + /* fall-through */ case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; - ZSTD_FALLTHROUGH; + /* fall-through */ default: break; } { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ } bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; @@ -298,26 +337,23 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si return srcSize; } -MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; } -MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { U32 const regMask = sizeof(bitContainer)*8 - 1; /* if start > regMask, bitstream is corrupted, and result is undefined */ assert(nbBits < BIT_MASK_SIZE); - /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better - * than accessing memory. When bmi2 instruction is not present, we consider - * such cpus old (pre-Haswell, 2013) and their performance is not of that - * importance. - */ -#if defined(__x86_64__) || defined(_M_X86) - return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); -#else return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; -#endif +} + +MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; } /*! BIT_lookBits() : @@ -326,7 +362,7 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 c * On 32-bits, maxNbBits==24. * On 64-bits, maxNbBits==56. * @return : value extracted */ -MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) { /* arbitrate between double-shift and shift+mask */ #if 1 @@ -349,7 +385,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); } -MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; } @@ -358,7 +394,7 @@ MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) * Read (consume) next n bits from local register and update. * Pay attention to not read more than nbBits contained into local register. * @return : extracted value. */ -MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBits(bitD, nbBits); BIT_skipBits(bitD, nbBits); @@ -366,7 +402,7 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned n } /*! BIT_readBitsFast() : - * unsafe version; only works if nbBits >= 1 */ + * unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBitsFast(bitD, nbBits); @@ -375,35 +411,21 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) return value; } -/*! BIT_reloadDStreamFast() : - * Similar to BIT_reloadDStream(), but with two differences: - * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! - * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this - * point you must use BIT_reloadDStream() to reload. - */ -MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) -{ - if (UNLIKELY(bitD->ptr < bitD->limitPtr)) - return BIT_DStream_overflow; - assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); - bitD->ptr -= bitD->bitsConsumed >> 3; - bitD->bitsConsumed &= 7; - bitD->bitContainer = MEM_readLEST(bitD->ptr); - return BIT_DStream_unfinished; -} - /*! BIT_reloadDStream() : * Refill `bitD` from buffer previously set in BIT_initDStream() . * This function is safe, it guarantees it will not read beyond src buffer. * @return : status of `BIT_DStream_t` internal register. * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ -MEM_STATIC FORCE_INLINE_ATTR BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) { if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ return BIT_DStream_overflow; if (bitD->ptr >= bitD->limitPtr) { - return BIT_reloadDStreamFast(bitD); + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; } if (bitD->ptr == bitD->start) { if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; @@ -436,5 +458,3 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) #endif #endif /* BITSTREAM_H_MODULE */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/clevels.h b/vendor/github.com/DataDog/zstd/clevels.h deleted file mode 100644 index 9215306c..00000000 --- a/vendor/github.com/DataDog/zstd/clevels.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_CLEVELS_H -#define ZSTD_CLEVELS_H - -#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ -#include "zstd.h" - -/*-===== Pre-defined compression levels =====-*/ - -#define ZSTD_MAX_CLEVEL 22 - -#ifdef __GNUC__ -__attribute__((__unused__)) -#endif - -static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { -{ /* "default" - for any srcSize > 256 KB */ - /* W, C, H, S, L, TL, strat */ - { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ - { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ - { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ - { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ - { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ - { 21, 18, 19, 3, 5, 2, ZSTD_greedy }, /* level 5 */ - { 21, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6 */ - { 21, 19, 20, 4, 5, 8, ZSTD_lazy }, /* level 7 */ - { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 8 */ - { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ - { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 10 */ - { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 11 */ - { 22, 22, 23, 6, 5, 32, ZSTD_lazy2 }, /* level 12 */ - { 22, 22, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ - { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ - { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ - { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ - { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ - { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ - { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ - { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ - { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ - { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ -}, -{ /* for srcSize <= 256 KB */ - /* W, C, H, S, L, T, strat */ - { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ - { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ - { 18, 16, 17, 3, 5, 2, ZSTD_greedy }, /* level 4.*/ - { 18, 17, 18, 5, 5, 2, ZSTD_greedy }, /* level 5.*/ - { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ - { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ - { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ - { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ - { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ - { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 128 KB */ - /* W, C, H, S, L, T, strat */ - { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ - { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ - { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ - { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ - { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 17, 16, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 17, 16, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 17, 16, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 17, 16, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ - { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ - { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ - { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ - { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ - { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 16 KB */ - /* W, C, H, S, L, T, strat */ - { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ - { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ - { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ - { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ - { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ - { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ - { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ - { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ - { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ - { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ - { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ - { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ - { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ - { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ - { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ - { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -}; - - - -#endif /* ZSTD_CLEVELS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/compiler.h b/vendor/github.com/DataDog/zstd/compiler.h index ffd66caf..1877a0c1 100644 --- a/vendor/github.com/DataDog/zstd/compiler.h +++ b/vendor/github.com/DataDog/zstd/compiler.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -12,15 +11,13 @@ #ifndef ZSTD_COMPILER_H #define ZSTD_COMPILER_H -#include "portability_macros.h" - /*-******************************************************* * Compiler specifics *********************************************************/ /* force inlining */ #if !defined(ZSTD_NO_INLINE) -#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ # define INLINE_KEYWORD inline #else # define INLINE_KEYWORD @@ -41,17 +38,6 @@ #endif -/** - On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). - This explicitly marks such functions as __cdecl so that the code will still compile - if a CC other than __cdecl has been made the default. -*/ -#if defined(_MSC_VER) -# define WIN_CDECL __cdecl -#else -# define WIN_CDECL -#endif - /** * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant * parameters. They must be inlined for the compiler to eliminate the constant @@ -93,19 +79,30 @@ # endif #endif - /* target attribute */ +#ifndef __has_attribute + #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif #if defined(__GNUC__) || defined(__ICCARM__) # define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) #else # define TARGET_ATTRIBUTE(target) #endif -/* Target attribute for BMI2 dynamic dispatch. - * Enable lzcnt, bmi, and bmi2. - * We test for bmi1 & bmi2. lzcnt is included in bmi1. +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. */ -#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X86)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif /* prefetch * can be disabled, by declaring NO_PREFETCH build macro */ @@ -120,9 +117,6 @@ # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) -# elif defined(__aarch64__) -# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) -# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) # else # define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ # define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ @@ -141,9 +135,8 @@ } /* vectorization - * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, - * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ -#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */ +#if !defined(__clang__) && defined(__GNUC__) # if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) # define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) # else @@ -153,25 +146,6 @@ # define DONT_VECTORIZE #endif -/* Tell the compiler that a branch is likely or unlikely. - * Only use these macros if it causes the compiler to generate better code. - * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc - * and clang, please do. - */ -#if defined(__GNUC__) -#define LIKELY(x) (__builtin_expect((x), 1)) -#define UNLIKELY(x) (__builtin_expect((x), 0)) -#else -#define LIKELY(x) (x) -#define UNLIKELY(x) (x) -#endif - -#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) -# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); } -#else -# define ZSTD_UNREACHABLE { assert(0); } -#endif - /* disable warnings */ #ifdef _MSC_VER /* Visual Studio */ # include /* For Visual 2005 */ @@ -182,180 +156,4 @@ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ #endif -/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ -#ifndef STATIC_BMI2 -# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) -# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 -# define STATIC_BMI2 1 -# endif -# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__) -# define STATIC_BMI2 1 -# endif -#endif - -#ifndef STATIC_BMI2 - #define STATIC_BMI2 0 -#endif - -/* compile time determination of SIMD support */ -#if !defined(ZSTD_NO_INTRINSICS) -# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) -# define ZSTD_ARCH_X86_SSE2 -# endif -# if defined(__ARM_NEON) || defined(_M_ARM64) -# define ZSTD_ARCH_ARM_NEON -# endif -# -# if defined(ZSTD_ARCH_X86_SSE2) -# include -# elif defined(ZSTD_ARCH_ARM_NEON) -# include -# endif -#endif - -/* C-language Attributes are added in C23. */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) -# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) -#else -# define ZSTD_HAS_C_ATTRIBUTE(x) 0 -#endif - -/* Only use C++ attributes in C++. Some compilers report support for C++ - * attributes when compiling with C. - */ -#if defined(__cplusplus) && defined(__has_cpp_attribute) -# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. - * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough - * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough - * - Else: __attribute__((__fallthrough__)) - */ -#ifndef ZSTD_FALLTHROUGH -# if ZSTD_HAS_C_ATTRIBUTE(fallthrough) -# define ZSTD_FALLTHROUGH [[fallthrough]] -# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough) -# define ZSTD_FALLTHROUGH [[fallthrough]] -# elif __has_attribute(__fallthrough__) -/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon - * gcc complains about: a label can only be part of a statement and a declaration is not a statement. - */ -# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__)) -# else -# define ZSTD_FALLTHROUGH -# endif -#endif - -/*-************************************************************** -* Alignment check -*****************************************************************/ - -/* this test was initially positioned in mem.h, - * but this file is removed (or replaced) for linux kernel - * so it's now hosted in compiler.h, - * which remains valid for both user & kernel spaces. - */ - -#ifndef ZSTD_ALIGNOF -# if defined(__GNUC__) || defined(_MSC_VER) -/* covers gcc, clang & MSVC */ -/* note : this section must come first, before C11, - * due to a limitation in the kernel source generator */ -# define ZSTD_ALIGNOF(T) __alignof(T) - -# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -/* C11 support */ -# include -# define ZSTD_ALIGNOF(T) alignof(T) - -# else -/* No known support for alignof() - imperfect backup */ -# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) - -# endif -#endif /* ZSTD_ALIGNOF */ - -/*-************************************************************** -* Sanitizer -*****************************************************************/ - -/* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an - * abundance of caution, disable our custom poisoning on mingw. */ -#ifdef __MINGW32__ -#ifndef ZSTD_ASAN_DONT_POISON_WORKSPACE -#define ZSTD_ASAN_DONT_POISON_WORKSPACE 1 -#endif -#ifndef ZSTD_MSAN_DONT_POISON_WORKSPACE -#define ZSTD_MSAN_DONT_POISON_WORKSPACE 1 -#endif -#endif - -#if ZSTD_MEMORY_SANITIZER && !defined(ZSTD_MSAN_DONT_POISON_WORKSPACE) -/* Not all platforms that support msan provide sanitizers/msan_interface.h. - * We therefore declare the functions we need ourselves, rather than trying to - * include the header file... */ -#include /* size_t */ -#define ZSTD_DEPS_NEED_STDINT -#include "zstd_deps.h" /* intptr_t */ - -/* Make memory region fully initialized (without changing its contents). */ -void __msan_unpoison(const volatile void *a, size_t size); - -/* Make memory region fully uninitialized (without changing its contents). - This is a legacy interface that does not update origin information. Use - __msan_allocated_memory() instead. */ -void __msan_poison(const volatile void *a, size_t size); - -/* Returns the offset of the first (at least partially) poisoned byte in the - memory range, or -1 if the whole range is good. */ -intptr_t __msan_test_shadow(const volatile void *x, size_t size); - -/* Print shadow and origin for the memory range to stderr in a human-readable - format. */ -void __msan_print_shadow(const volatile void *x, size_t size); -#endif - -#if ZSTD_ADDRESS_SANITIZER && !defined(ZSTD_ASAN_DONT_POISON_WORKSPACE) -/* Not all platforms that support asan provide sanitizers/asan_interface.h. - * We therefore declare the functions we need ourselves, rather than trying to - * include the header file... */ -#include /* size_t */ - -/** - * Marks a memory region ([addr, addr+size)) as unaddressable. - * - * This memory must be previously allocated by your program. Instrumented - * code is forbidden from accessing addresses in this region until it is - * unpoisoned. This function is not guaranteed to poison the entire region - - * it could poison only a subregion of [addr, addr+size) due to ASan - * alignment restrictions. - * - * \note This function is not thread-safe because no two threads can poison or - * unpoison memory in the same memory region simultaneously. - * - * \param addr Start of memory region. - * \param size Size of memory region. */ -void __asan_poison_memory_region(void const volatile *addr, size_t size); - -/** - * Marks a memory region ([addr, addr+size)) as addressable. - * - * This memory must be previously allocated by your program. Accessing - * addresses in this region is allowed until this region is poisoned again. - * This function could unpoison a super-region of [addr, addr+size) due - * to ASan alignment restrictions. - * - * \note This function is not thread-safe because no two threads can - * poison or unpoison memory in the same memory region simultaneously. - * - * \param addr Start of memory region. - * \param size Size of memory region. */ -void __asan_unpoison_memory_region(void const volatile *addr, size_t size); -#endif - #endif /* ZSTD_COMPILER_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/cover.c b/vendor/github.com/DataDog/zstd/cover.c index 330e33af..2e129dd9 100644 --- a/vendor/github.com/DataDog/zstd/cover.c +++ b/vendor/github.com/DataDog/zstd/cover.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -27,65 +26,47 @@ #include /* memset */ #include /* clock */ -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - #include "mem.h" /* read */ #include "pool.h" #include "threading.h" +#include "cover.h" #include "zstd_internal.h" /* includes zstd.h */ -#include "bits.h" /* ZSTD_highbit32 */ +#ifndef ZDICT_STATIC_LINKING_ONLY +#define ZDICT_STATIC_LINKING_ONLY +#endif #include "zdict.h" -#include "cover.h" /*-************************************* * Constants ***************************************/ -/** -* There are 32bit indexes used to ref samples, so limit samples size to 4GB -* on 64bit builds. -* For 32bit builds we choose 1 GB. -* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large -* contiguous buffer, so 1GB is already a high limit. -*/ #define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) -#define COVER_DEFAULT_SPLITPOINT 1.0 +#define DEFAULT_SPLITPOINT 1.0 /*-************************************* * Console display ***************************************/ -#ifndef LOCALDISPLAYLEVEL -static int g_displayLevel = 0; -#endif -#undef DISPLAY +static int g_displayLevel = 2; #define DISPLAY(...) \ { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } -#undef LOCALDISPLAYLEVEL #define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ if (displayLevel >= l) { \ DISPLAY(__VA_ARGS__); \ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ -#undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) -#ifndef LOCALDISPLAYUPDATE -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; -#endif -#undef LOCALDISPLAYUPDATE #define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ if (displayLevel >= l) { \ - if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ + if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \ g_time = clock(); \ DISPLAY(__VA_ARGS__); \ } \ } -#undef DISPLAYUPDATE #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) +static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; /*-************************************* * Hash table @@ -139,9 +120,9 @@ static int COVER_map_init(COVER_map_t *map, U32 size) { /** * Internal hash function */ -static const U32 COVER_prime4bytes = 2654435761U; +static const U32 prime4bytes = 2654435761U; static U32 COVER_map_hash(COVER_map_t *map, U32 key) { - return (key * COVER_prime4bytes) >> (32 - map->sizeLog); + return (key * prime4bytes) >> (32 - map->sizeLog); } /** @@ -234,7 +215,7 @@ typedef struct { } COVER_ctx_t; /* We need a global context for qsort... */ -static COVER_ctx_t *g_coverCtx = NULL; +static COVER_ctx_t *g_ctx = NULL; /*-************************************* * Helper functions @@ -277,11 +258,11 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { /** * Same as COVER_cmp() except ties are broken by pointer value - * NOTE: g_coverCtx must be set to call this function. A global is required because + * NOTE: g_ctx must be set to call this function. A global is required because * qsort doesn't take an opaque pointer. */ -static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) { - int result = COVER_cmp(g_coverCtx, lp, rp); +static int COVER_strict_cmp(const void *lp, const void *rp) { + int result = COVER_cmp(g_ctx, lp, rp); if (result == 0) { result = lp < rp ? -1 : 1; } @@ -290,8 +271,8 @@ static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) { /** * Faster version for d <= 8. */ -static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) { - int result = COVER_cmp8(g_coverCtx, lp, rp); +static int COVER_strict_cmp8(const void *lp, const void *rp) { + int result = COVER_cmp8(g_ctx, lp, rp); if (result == 0) { result = lp < rp ? -1 : 1; } @@ -543,7 +524,7 @@ static void COVER_ctx_destroy(COVER_ctx_t *ctx) { /** * Prepare a context for dictionary building. - * The context is only dependent on the parameter `d` and can be used multiple + * The context is only dependent on the parameter `d` and can used multiple * times. * Returns 0 on success or error code on error. * The context must be destroyed with `COVER_ctx_destroy()`. @@ -622,7 +603,7 @@ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, /* qsort doesn't take an opaque pointer, so pass as a global. * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is. */ - g_coverCtx = ctx; + g_ctx = ctx; #if defined(__OpenBSD__) mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); @@ -648,7 +629,7 @@ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel) { - const double ratio = (double)nbDmers / (double)maxDictSize; + const double ratio = (double)nbDmers / maxDictSize; if (ratio >= 10) { return; } @@ -744,7 +725,7 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover( COVER_map_t activeDmers; parameters.splitPoint = 1.0; /* Initialize global data */ - g_displayLevel = (int)parameters.zParams.notificationLevel; + g_displayLevel = parameters.zParams.notificationLevel; /* Checks */ if (!COVER_checkParameters(parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); @@ -952,17 +933,9 @@ void COVER_best_finish(COVER_best_t *best, ZDICT_cover_params_t parameters, } } -static COVER_dictSelection_t setDictSelection(BYTE* buf, size_t s, size_t csz) -{ - COVER_dictSelection_t ds; - ds.dictContent = buf; - ds.dictSize = s; - ds.totalCompressedSize = csz; - return ds; -} - COVER_dictSelection_t COVER_dictSelectionError(size_t error) { - return setDictSelection(NULL, 0, error); + COVER_dictSelection_t selection = { NULL, 0, error }; + return selection; } unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection) { @@ -973,7 +946,7 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection){ free(selection.dictContent); } -COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, +COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize) { @@ -981,8 +954,8 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBuffe size_t largestCompressed = 0; BYTE* customDictContentEnd = customDictContent + dictContentSize; - BYTE * largestDictbuffer = (BYTE *)malloc(dictBufferCapacity); - BYTE * candidateDictBuffer = (BYTE *)malloc(dictBufferCapacity); + BYTE * largestDictbuffer = (BYTE *)malloc(dictContentSize); + BYTE * candidateDictBuffer = (BYTE *)malloc(dictContentSize); double regressionTolerance = ((double)params.shrinkDictMaxRegression / 100.0) + 1.00; if (!largestDictbuffer || !candidateDictBuffer) { @@ -994,7 +967,7 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBuffe /* Initial dictionary size and compressed size */ memcpy(largestDictbuffer, customDictContent, dictContentSize); dictContentSize = ZDICT_finalizeDictionary( - largestDictbuffer, dictBufferCapacity, customDictContent, dictContentSize, + largestDictbuffer, dictContentSize, customDictContent, dictContentSize, samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); if (ZDICT_isError(dictContentSize)) { @@ -1015,8 +988,9 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBuffe } if (params.shrinkDict == 0) { + COVER_dictSelection_t selection = { largestDictbuffer, dictContentSize, totalCompressedSize }; free(candidateDictBuffer); - return setDictSelection(largestDictbuffer, dictContentSize, totalCompressedSize); + return selection; } largestDict = dictContentSize; @@ -1027,7 +1001,7 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBuffe while (dictContentSize < largestDict) { memcpy(candidateDictBuffer, largestDictbuffer, largestDict); dictContentSize = ZDICT_finalizeDictionary( - candidateDictBuffer, dictBufferCapacity, customDictContentEnd - dictContentSize, dictContentSize, + candidateDictBuffer, dictContentSize, customDictContentEnd - dictContentSize, dictContentSize, samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); if (ZDICT_isError(dictContentSize)) { @@ -1048,16 +1022,20 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBuffe return COVER_dictSelectionError(totalCompressedSize); } - if ((double)totalCompressedSize <= (double)largestCompressed * regressionTolerance) { + if (totalCompressedSize <= largestCompressed * regressionTolerance) { + COVER_dictSelection_t selection = { candidateDictBuffer, dictContentSize, totalCompressedSize }; free(largestDictbuffer); - return setDictSelection( candidateDictBuffer, dictContentSize, totalCompressedSize ); + return selection; } dictContentSize *= 2; } dictContentSize = largestDict; totalCompressedSize = largestCompressed; - free(candidateDictBuffer); - return setDictSelection( largestDictbuffer, dictContentSize, totalCompressedSize ); + { + COVER_dictSelection_t selection = { largestDictbuffer, dictContentSize, totalCompressedSize }; + free(candidateDictBuffer); + return selection; + } } /** @@ -1075,19 +1053,18 @@ typedef struct COVER_tryParameters_data_s { * This function is thread safe if zstd is compiled with multithreaded support. * It takes its parameters as an *OWNING* opaque pointer to support threading. */ -static void COVER_tryParameters(void *opaque) -{ +static void COVER_tryParameters(void *opaque) { /* Save parameters as local variables */ - COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t*)opaque; + COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque; const COVER_ctx_t *const ctx = data->ctx; const ZDICT_cover_params_t parameters = data->parameters; size_t dictBufferCapacity = data->dictBufferCapacity; size_t totalCompressedSize = ERROR(GENERIC); /* Allocate space for hash table, dict, and freqs */ COVER_map_t activeDmers; - BYTE* const dict = (BYTE*)malloc(dictBufferCapacity); + BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity); COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); - U32* const freqs = (U32*)malloc(ctx->suffixSize * sizeof(U32)); + U32 *freqs = (U32 *)malloc(ctx->suffixSize * sizeof(U32)); if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); goto _cleanup; @@ -1102,7 +1079,7 @@ static void COVER_tryParameters(void *opaque) { const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict, dictBufferCapacity, parameters); - selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, + selection = COVER_selectDict(dict + tail, dictBufferCapacity - tail, ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, totalCompressedSize); @@ -1117,18 +1094,19 @@ static void COVER_tryParameters(void *opaque) free(data); COVER_map_destroy(&activeDmers); COVER_dictSelectionFree(selection); - free(freqs); + if (freqs) { + free(freqs); + } } ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( - void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples, - ZDICT_cover_params_t* parameters) -{ + void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer, + const size_t *samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t *parameters) { /* constants */ const unsigned nbThreads = parameters->nbThreads; const double splitPoint = - parameters->splitPoint <= 0.0 ? COVER_DEFAULT_SPLITPOINT : parameters->splitPoint; + parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint; const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; @@ -1256,5 +1234,3 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( return dictSize; } } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/cover.h b/vendor/github.com/DataDog/zstd/cover.h index 5c739dab..d9e0636a 100644 --- a/vendor/github.com/DataDog/zstd/cover.h +++ b/vendor/github.com/DataDog/zstd/cover.h @@ -1,18 +1,3 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - #include /* fprintf */ #include /* malloc, free, qsort */ #include /* memset */ @@ -21,6 +6,9 @@ #include "pool.h" #include "threading.h" #include "zstd_internal.h" /* includes zstd.h */ +#ifndef ZDICT_STATIC_LINKING_ONLY +#define ZDICT_STATIC_LINKING_ONLY +#endif #include "zdict.h" /** @@ -154,8 +142,6 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection); * smallest dictionary within a specified regression of the compressed size * from the largest dictionary. */ - COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, + COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize); - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/cpu.h b/vendor/github.com/DataDog/zstd/cpu.h index 22b646ed..5f0923fc 100644 --- a/vendor/github.com/DataDog/zstd/cpu.h +++ b/vendor/github.com/DataDog/zstd/cpu.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2018-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,6 +16,8 @@ * https://github.com/facebook/folly/blob/master/folly/CpuId.h */ +#include + #include "mem.h" #ifdef _MSC_VER @@ -212,5 +213,3 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { #undef X #endif /* ZSTD_COMMON_CPU_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/debug.c b/vendor/github.com/DataDog/zstd/debug.c index d1dfc35b..3ebdd1cb 100644 --- a/vendor/github.com/DataDog/zstd/debug.c +++ b/vendor/github.com/DataDog/zstd/debug.c @@ -1,16 +1,35 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * debug - * Part of FSE library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + debug + Part of FSE library + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy ****************************************************************** */ @@ -23,5 +42,3 @@ #include "debug.h" int g_debuglevel = DEBUGLEVEL; - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/debug.h b/vendor/github.com/DataDog/zstd/debug.h index 110d55f4..b4fc89d4 100644 --- a/vendor/github.com/DataDog/zstd/debug.h +++ b/vendor/github.com/DataDog/zstd/debug.h @@ -1,16 +1,35 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * debug - * Part of FSE library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + debug + Part of FSE library + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy ****************************************************************** */ @@ -52,6 +71,15 @@ extern "C" { #endif +/* DEBUGFILE can be defined externally, + * typically through compiler command line. + * note : currently useless. + * Value must be stderr or stdout */ +#ifndef DEBUGFILE +# define DEBUGFILE stderr +#endif + + /* recommended values for DEBUGLEVEL : * 0 : release mode, no debug, all run-time checks disabled * 1 : enables assert() only, no display @@ -68,8 +96,7 @@ extern "C" { */ #if (DEBUGLEVEL>=1) -# define ZSTD_DEPS_NEED_ASSERT -# include "zstd_deps.h" +# include #else # ifndef assert /* assert may be already defined, due to prior #include */ # define assert(condition) ((void)0) /* disable assert (default) */ @@ -77,8 +104,7 @@ extern "C" { #endif #if (DEBUGLEVEL>=2) -# define ZSTD_DEPS_NEED_IO -# include "zstd_deps.h" +# include extern int g_debuglevel; /* the variable is only declared, it actually lives in debug.c, and is shared by the whole process. @@ -86,14 +112,14 @@ extern int g_debuglevel; /* the variable is only declared, It's useful when enabling very verbose levels on selective conditions (such as position in src) */ -# define RAWLOG(l, ...) { \ - if (l<=g_debuglevel) { \ - ZSTD_DEBUG_PRINT(__VA_ARGS__); \ +# define RAWLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + fprintf(stderr, __VA_ARGS__); \ } } -# define DEBUGLOG(l, ...) { \ - if (l<=g_debuglevel) { \ - ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \ - ZSTD_DEBUG_PRINT(" \n"); \ +# define DEBUGLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ + fprintf(stderr, " \n"); \ } } #else # define RAWLOG(l, ...) {} /* disabled */ @@ -106,5 +132,3 @@ extern int g_debuglevel; /* the variable is only declared, #endif #endif /* DEBUG_H_12987983217 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/divsufsort.c b/vendor/github.com/DataDog/zstd/divsufsort.c index 82e6a80f..ead92204 100644 --- a/vendor/github.com/DataDog/zstd/divsufsort.c +++ b/vendor/github.com/DataDog/zstd/divsufsort.c @@ -1,4 +1,3 @@ -#ifndef USE_EXTERNAL_ZSTD /* * divsufsort.c for libdivsufsort-lite * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. @@ -1577,7 +1576,7 @@ sort_typeBstar(const unsigned char *T, int *SA, /* Construct the inverse suffix array of type B* suffixes using trsort. */ trsort(ISAb, SA, m, 1); - /* Set the sorted order of type B* suffixes. */ + /* Set the sorted order of tyoe B* suffixes. */ for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } if(0 <= i) { @@ -1912,5 +1911,3 @@ divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * return pidx; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/divsufsort.h b/vendor/github.com/DataDog/zstd/divsufsort.h index 7f5033f5..5440994a 100644 --- a/vendor/github.com/DataDog/zstd/divsufsort.h +++ b/vendor/github.com/DataDog/zstd/divsufsort.h @@ -1,4 +1,3 @@ -#ifndef USE_EXTERNAL_ZSTD /* * divsufsort.h for libdivsufsort-lite * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. @@ -66,5 +65,3 @@ divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * #endif /* __cplusplus */ #endif /* _DIVSUFSORT_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/entropy_common.c b/vendor/github.com/DataDog/zstd/entropy_common.c index 1bfbb525..b12944e1 100644 --- a/vendor/github.com/DataDog/zstd/entropy_common.c +++ b/vendor/github.com/DataDog/zstd/entropy_common.c @@ -1,17 +1,36 @@ -#ifndef USE_EXTERNAL_ZSTD -/* ****************************************************************** - * Common functions of New Generation Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - Public forum : https://groups.google.com/forum/#!forum/lz4c - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. -****************************************************************** */ +/* + Common functions of New Generation Entropy library + Copyright (C) 2016, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +*************************************************************************** */ /* ************************************* * Dependencies @@ -20,8 +39,8 @@ #include "error_private.h" /* ERR_*, ERROR */ #define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ #include "fse.h" +#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */ #include "huf.h" -#include "bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */ /*=== Version ===*/ @@ -39,9 +58,8 @@ const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } /*-************************************************************** * FSE NCount encoding-decoding ****************************************************************/ -FORCE_INLINE_TEMPLATE -size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) +size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) { const BYTE* const istart = (const BYTE*) headerBuffer; const BYTE* const iend = istart + hbSize; @@ -52,23 +70,23 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne U32 bitStream; int bitCount; unsigned charnum = 0; - unsigned const maxSV1 = *maxSVPtr + 1; int previous0 = 0; - if (hbSize < 8) { - /* This function only works when hbSize >= 8 */ - char buffer[8] = {0}; - ZSTD_memcpy(buffer, headerBuffer, hbSize); + if (hbSize < 4) { + /* This function only works when hbSize >= 4 */ + char buffer[4]; + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, headerBuffer, hbSize); { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, buffer, sizeof(buffer)); if (FSE_isError(countSize)) return countSize; if (countSize > hbSize) return ERROR(corruption_detected); return countSize; } } - assert(hbSize >= 8); + assert(hbSize >= 4); /* init */ - ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ bitStream = MEM_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); @@ -79,58 +97,36 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne threshold = 1<1) & (charnum<=*maxSVPtr)) { if (previous0) { - /* Count the number of repeats. Each time the - * 2-bit repeat code is 0b11 there is another - * repeat. - * Avoid UB by setting the high bit to 1. - */ - int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; - while (repeats >= 12) { - charnum += 3 * 12; - if (LIKELY(ip <= iend-7)) { - ip += 3; + unsigned n0 = charnum; + while ((bitStream & 0xFFFF) == 0xFFFF) { + n0 += 24; + if (ip < iend-5) { + ip += 2; + bitStream = MEM_readLE32(ip) >> bitCount; } else { - bitCount -= (int)(8 * (iend - 7 - ip)); - bitCount &= 31; - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> bitCount; - repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; + bitStream >>= 16; + bitCount += 16; + } } + while ((bitStream & 3) == 3) { + n0 += 3; + bitStream >>= 2; + bitCount += 2; } - charnum += 3 * repeats; - bitStream >>= 2 * repeats; - bitCount += 2 * repeats; - - /* Add the final repeat which isn't 0b11. */ - assert((bitStream & 3) < 3); - charnum += bitStream & 3; + n0 += bitStream & 3; bitCount += 2; - - /* This is an error, but break and return an error - * at the end, because returning out of a loop makes - * it harder for the compiler to optimize. - */ - if (charnum >= maxSV1) break; - - /* We don't need to set the normalized count to 0 - * because we already memset the whole buffer to 0. - */ - - if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); + while (charnum < n0) normalizedCounter[charnum++] = 0; + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { assert((bitCount >> 3) <= 3); /* For first condition to work */ ip += bitCount>>3; bitCount &= 7; + bitStream = MEM_readLE32(ip) >> bitCount; } else { - bitCount -= (int)(8 * (iend - 4 - ip)); - bitCount &= 31; - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> bitCount; - } - { - int const max = (2*threshold-1) - remaining; + bitStream >>= 2; + } } + { int const max = (2*threshold-1) - remaining; int count; if ((bitStream & (threshold-1)) < (U32)max) { @@ -143,43 +139,24 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne } count--; /* extra accuracy */ - /* When it matters (small blocks), this is a - * predictable branch, because we don't use -1. - */ - if (count >= 0) { - remaining -= count; - } else { - assert(count == -1); - remaining += count; - } + remaining -= count < 0 ? -count : count; /* -1 means +1 */ normalizedCounter[charnum++] = (short)count; previous0 = !count; - - assert(threshold > 1); - if (remaining < threshold) { - /* This branch can be folded into the - * threshold update condition because we - * know that threshold > 1. - */ - if (remaining <= 1) break; - nbBits = ZSTD_highbit32(remaining) + 1; - threshold = 1 << (nbBits - 1); + while (remaining < threshold) { + nbBits--; + threshold >>= 1; } - if (charnum >= maxSV1) break; - if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { ip += bitCount>>3; bitCount &= 7; } else { bitCount -= (int)(8 * (iend - 4 - ip)); - bitCount &= 31; ip = iend - 4; } - bitStream = MEM_readLE32(ip) >> bitCount; - } } + bitStream = MEM_readLE32(ip) >> (bitCount & 31); + } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */ if (remaining != 1) return ERROR(corruption_detected); - /* Only possible when there are too many zeros. */ - if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); if (bitCount > 32) return ERROR(corruption_detected); *maxSVPtr = charnum-1; @@ -187,43 +164,6 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne return ip-istart; } -/* Avoids the FORCE_INLINE of the _body() function. */ -static size_t FSE_readNCount_body_default( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); -} - -#if DYNAMIC_BMI2 -BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); -} -#endif - -size_t FSE_readNCount_bmi2( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize, int bmi2) -{ -#if DYNAMIC_BMI2 - if (bmi2) { - return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); - } -#endif - (void)bmi2; - return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); -} - -size_t FSE_readNCount( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); -} - /*! HUF_readStats() : Read compact Huffman tree, saved by HUF_writeCTable(). @@ -235,17 +175,6 @@ size_t FSE_readNCount( size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, const void* src, size_t srcSize) -{ - U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; - return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* flags */ 0); -} - -FORCE_INLINE_TEMPLATE size_t -HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize, - int bmi2) { U32 weightTotal; const BYTE* ip = (const BYTE*) src; @@ -254,7 +183,7 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ oSize = iSize - 127; @@ -268,31 +197,31 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, huffWeight[n+1] = ip[n/2] & 15; } } } else { /* header compressed with FSE (normal case) */ + FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */ if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - /* max (hwSize-1) values decoded, as last one is implied */ - oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); + oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */ if (FSE_isError(oSize)) return oSize; } /* collect weight stats */ - ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); weightTotal = 0; { U32 n; for (n=0; n HUF_TABLELOG_MAX) return ERROR(corruption_detected); + if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; } } if (weightTotal == 0) return ERROR(corruption_detected); /* get last non-null symbol weight (implied, total must be 2^n) */ - { U32 const tableLog = ZSTD_highbit32(weightTotal) + 1; + { U32 const tableLog = BIT_highbit32(weightTotal) + 1; if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); *tableLogPtr = tableLog; /* determine last weight */ { U32 const total = 1 << tableLog; U32 const rest = total - weightTotal; - U32 const verif = 1 << ZSTD_highbit32(rest); - U32 const lastWeight = ZSTD_highbit32(rest) + 1; + U32 const verif = 1 << BIT_highbit32(rest); + U32 const lastWeight = BIT_highbit32(rest) + 1; if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ huffWeight[oSize] = (BYTE)lastWeight; rankStats[lastWeight]++; @@ -305,39 +234,3 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, *nbSymbolsPtr = (U32)(oSize+1); return iSize+1; } - -/* Avoids the FORCE_INLINE of the _body() function. */ -static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize) -{ - return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); -} - -#if DYNAMIC_BMI2 -static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize) -{ - return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); -} -#endif - -size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize, - int flags) -{ -#if DYNAMIC_BMI2 - if (flags & HUF_flags_bmi2) { - return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); - } -#endif - (void)flags; - return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); -} - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/error_private.c b/vendor/github.com/DataDog/zstd/error_private.c index 803cc7b9..7c1bb67a 100644 --- a/vendor/github.com/DataDog/zstd/error_private.c +++ b/vendor/github.com/DataDog/zstd/error_private.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -28,11 +27,9 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(version_unsupported): return "Version not supported"; case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; - case PREFIX(corruption_detected): return "Data corruption detected"; + case PREFIX(corruption_detected): return "Corrupted block detected"; case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; - case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification"; case PREFIX(parameter_unsupported): return "Unsupported parameter"; - case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters"; case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; case PREFIX(init_missing): return "Context should be init first"; case PREFIX(memory_allocation): return "Allocation error : not enough memory"; @@ -41,26 +38,17 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; - case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(dictionary_wrong): return "Dictionary mismatch"; case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; case PREFIX(srcSize_wrong): return "Src size is incorrect"; case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; - case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full"; - case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty"; /* following error codes are not stable and may be removed or changed in a future version */ case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; - case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; - case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; - case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; - case PREFIX(externalSequences_invalid): return "External sequences are not valid"; case PREFIX(maxCode): default: return notErrorCode; } #endif } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/error_private.h b/vendor/github.com/DataDog/zstd/error_private.h index 05ddbfa8..0d2fa7e3 100644 --- a/vendor/github.com/DataDog/zstd/error_private.h +++ b/vendor/github.com/DataDog/zstd/error_private.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -22,10 +21,8 @@ extern "C" { /* **************************************** * Dependencies ******************************************/ +#include /* size_t */ #include "zstd_errors.h" /* enum list */ -#include "compiler.h" -#include "debug.h" -#include "zstd_deps.h" /* size_t */ /* **************************************** @@ -52,7 +49,7 @@ typedef ZSTD_ErrorCode ERR_enum; /*-**************************************** * Error codes handling ******************************************/ -#undef ERROR /* already defined on Visual Studio */ +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ #define ERROR(name) ZSTD_ERROR(name) #define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) @@ -60,10 +57,6 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } -/* check and forward error code */ -#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e -#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } - /*-**************************************** * Error Strings @@ -76,87 +69,8 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) return ERR_getErrorString(ERR_getErrorCode(code)); } -/** - * Ignore: this is an internal helper. - * - * This is a helper function to help force C99-correctness during compilation. - * Under strict compilation modes, variadic macro arguments can't be empty. - * However, variadic function arguments can be. Using a function therefore lets - * us statically check that at least one (string) argument was passed, - * independent of the compilation flags. - */ -static INLINE_KEYWORD UNUSED_ATTR -void _force_has_format_string(const char *format, ...) { - (void)format; -} - -/** - * Ignore: this is an internal helper. - * - * We want to force this function invocation to be syntactically correct, but - * we don't want to force runtime evaluation of its arguments. - */ -#define _FORCE_HAS_FORMAT_STRING(...) \ - if (0) { \ - _force_has_format_string(__VA_ARGS__); \ - } - -#define ERR_QUOTE(str) #str - -/** - * Return the specified error if the condition evaluates to true. - * - * In debug modes, prints additional information. - * In order to do that (particularly, printing the conditional that failed), - * this can't just wrap RETURN_ERROR(). - */ -#define RETURN_ERROR_IF(cond, err, ...) \ - if (cond) { \ - RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ - __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } - -/** - * Unconditionally return the specified error. - * - * In debug modes, prints additional information. - */ -#define RETURN_ERROR(err, ...) \ - do { \ - RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ - __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } while(0); - -/** - * If the provided expression evaluates to an error code, returns that error code. - * - * In debug modes, prints additional information. - */ -#define FORWARD_IF_ERROR(err, ...) \ - do { \ - size_t const err_code = (err); \ - if (ERR_isError(err_code)) { \ - RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ - __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return err_code; \ - } \ - } while(0); - #if defined (__cplusplus) } #endif #endif /* ERROR_H_MODULE */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/errors.go b/vendor/github.com/DataDog/zstd/errors.go index dbeb8160..38db0d51 100644 --- a/vendor/github.com/DataDog/zstd/errors.go +++ b/vendor/github.com/DataDog/zstd/errors.go @@ -1,6 +1,7 @@ package zstd /* +#define ZSTD_STATIC_LINKING_ONLY #include "zstd.h" */ import "C" diff --git a/vendor/github.com/DataDog/zstd/external_zstd.go b/vendor/github.com/DataDog/zstd/external_zstd.go deleted file mode 100644 index fc4ceb24..00000000 --- a/vendor/github.com/DataDog/zstd/external_zstd.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build external_libzstd -// +build external_libzstd - -package zstd - -// #cgo CFLAGS: -DUSE_EXTERNAL_ZSTD -// #cgo pkg-config: libzstd -/* -#include -#if ZSTD_VERSION_NUMBER < 10400 -#error "ZSTD version >= 1.4 is required" -#endif -*/ -import "C" diff --git a/vendor/github.com/DataDog/zstd/fastcover.c b/vendor/github.com/DataDog/zstd/fastcover.c index 147ccbfc..941bb5a2 100644 --- a/vendor/github.com/DataDog/zstd/fastcover.c +++ b/vendor/github.com/DataDog/zstd/fastcover.c @@ -1,14 +1,3 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - /*-************************************* * Dependencies ***************************************/ @@ -17,33 +6,24 @@ #include /* memset */ #include /* clock */ -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - #include "mem.h" /* read */ #include "pool.h" #include "threading.h" +#include "cover.h" #include "zstd_internal.h" /* includes zstd.h */ -#include "zstd_compress_internal.h" /* ZSTD_hash*() */ +#ifndef ZDICT_STATIC_LINKING_ONLY +#define ZDICT_STATIC_LINKING_ONLY +#endif #include "zdict.h" -#include "cover.h" /*-************************************* * Constants ***************************************/ -/** -* There are 32bit indexes used to ref samples, so limit samples size to 4GB -* on 64bit builds. -* For 32bit builds we choose 1 GB. -* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large -* contiguous buffer, so 1GB is already a high limit. -*/ #define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) #define FASTCOVER_MAX_F 31 #define FASTCOVER_MAX_ACCEL 10 -#define FASTCOVER_DEFAULT_SPLITPOINT 0.75 +#define DEFAULT_SPLITPOINT 0.75 #define DEFAULT_F 20 #define DEFAULT_ACCEL 1 @@ -51,50 +31,50 @@ /*-************************************* * Console display ***************************************/ -#ifndef LOCALDISPLAYLEVEL -static int g_displayLevel = 0; -#endif -#undef DISPLAY +static int g_displayLevel = 2; #define DISPLAY(...) \ { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } -#undef LOCALDISPLAYLEVEL #define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ if (displayLevel >= l) { \ DISPLAY(__VA_ARGS__); \ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ -#undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) -#ifndef LOCALDISPLAYUPDATE -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; -#endif -#undef LOCALDISPLAYUPDATE #define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ if (displayLevel >= l) { \ - if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ + if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \ g_time = clock(); \ DISPLAY(__VA_ARGS__); \ } \ } -#undef DISPLAYUPDATE #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) +static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; /*-************************************* * Hash Functions ***************************************/ +static const U64 prime6bytes = 227718039650203ULL; +static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } +static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } + +static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; +static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } +static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } + + /** - * Hash the d-byte value pointed to by p and mod 2^f into the frequency vector + * Hash the d-byte value pointed to by p and mod 2^f */ -static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 f, unsigned d) { +static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 h, unsigned d) { if (d == 6) { - return ZSTD_hash6Ptr(p, f); + return ZSTD_hash6Ptr(p, h) & ((1 << h) - 1); } - return ZSTD_hash8Ptr(p, f); + return ZSTD_hash8Ptr(p, h) & ((1 << h) - 1); } @@ -305,7 +285,7 @@ FASTCOVER_computeFrequency(U32* freqs, const FASTCOVER_ctx_t* ctx) /** * Prepare a context for dictionary building. - * The context is only dependent on the parameter `d` and can be used multiple + * The context is only dependent on the parameter `d` and can used multiple * times. * Returns 0 on success or error code on error. * The context must be destroyed with `FASTCOVER_ctx_destroy()`. @@ -471,20 +451,20 @@ typedef struct FASTCOVER_tryParameters_data_s { * This function is thread safe if zstd is compiled with multithreaded support. * It takes its parameters as an *OWNING* opaque pointer to support threading. */ -static void FASTCOVER_tryParameters(void* opaque) +static void FASTCOVER_tryParameters(void *opaque) { /* Save parameters as local variables */ - FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t*)opaque; + FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t *)opaque; const FASTCOVER_ctx_t *const ctx = data->ctx; const ZDICT_cover_params_t parameters = data->parameters; size_t dictBufferCapacity = data->dictBufferCapacity; size_t totalCompressedSize = ERROR(GENERIC); /* Initialize array to keep track of frequency of dmer within activeSegment */ - U16* segmentFreqs = (U16*)calloc(((U64)1 << ctx->f), sizeof(U16)); + U16* segmentFreqs = (U16 *)calloc(((U64)1 << ctx->f), sizeof(U16)); /* Allocate space for hash table, dict, and freqs */ - BYTE *const dict = (BYTE*)malloc(dictBufferCapacity); + BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity); COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); - U32* freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); + U32 *freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); if (!segmentFreqs || !dict || !freqs) { DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); goto _cleanup; @@ -496,7 +476,7 @@ static void FASTCOVER_tryParameters(void* opaque) parameters, segmentFreqs); const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100); - selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, + selection = COVER_selectDict(dict + tail, dictBufferCapacity - tail, ctx->samples, ctx->samplesSizes, nbFinalizeSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, totalCompressedSize); @@ -557,7 +537,7 @@ ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, ZDICT_cover_params_t coverParams; FASTCOVER_accel_t accelParams; /* Initialize global data */ - g_displayLevel = (int)parameters.zParams.notificationLevel; + g_displayLevel = parameters.zParams.notificationLevel; /* Assign splitPoint and f if not provided */ parameters.splitPoint = 1.0; parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f; @@ -627,7 +607,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( /* constants */ const unsigned nbThreads = parameters->nbThreads; const double splitPoint = - parameters->splitPoint <= 0.0 ? FASTCOVER_DEFAULT_SPLITPOINT : parameters->splitPoint; + parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint; const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; @@ -640,7 +620,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( const unsigned accel = parameters->accel == 0 ? DEFAULT_ACCEL : parameters->accel; const unsigned shrinkDict = 0; /* Local variables */ - const int displayLevel = (int)parameters->zParams.notificationLevel; + const int displayLevel = parameters->zParams.notificationLevel; unsigned iteration = 1; unsigned d; unsigned k; @@ -724,7 +704,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( data->parameters.splitPoint = splitPoint; data->parameters.steps = kSteps; data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; + data->parameters.zParams.notificationLevel = g_displayLevel; /* Check the parameters */ if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity, data->ctx->f, accel)) { @@ -765,5 +745,3 @@ ZDICT_optimizeTrainFromBuffer_fastCover( } } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/fse.h b/vendor/github.com/DataDog/zstd/fse.h index 5d6e4c45..a7553e37 100644 --- a/vendor/github.com/DataDog/zstd/fse.h +++ b/vendor/github.com/DataDog/zstd/fse.h @@ -1,16 +1,35 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * FSE : Finite State Entropy codec - * Public Prototypes declaration - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + FSE : Finite State Entropy codec + Public Prototypes declaration + Copyright (C) 2013-2016, Yann Collet. + + BSD 2-Clause License (http://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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy ****************************************************************** */ #if defined (__cplusplus) @@ -24,7 +43,7 @@ extern "C" { /*-***************************************** * Dependencies ******************************************/ -#include "zstd_deps.h" /* size_t, ptrdiff_t */ +#include /* size_t, ptrdiff_t */ /*-***************************************** @@ -54,6 +73,34 @@ extern "C" { FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ +/*-**************************************** +* FSE simple functions +******************************************/ +/*! FSE_compress() : + Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'. + 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize). + @return : size of compressed data (<= dstCapacity). + Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead. + if FSE_isError(return), compression failed (more details using FSE_getErrorName()) +*/ +FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/*! FSE_decompress(): + Decompress FSE data from buffer 'cSrc', of size 'cSrcSize', + into already allocated destination buffer 'dst', of size 'dstCapacity'. + @return : size of regenerated data (<= maxDstSize), + or an error code, which can be tested using FSE_isError() . + + ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!! + Why ? : making this distinction requires a header. + Header management is intentionally delegated to the user layer, which can better manage special cases. +*/ +FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize); + + /*-***************************************** * Tool functions ******************************************/ @@ -64,6 +111,20 @@ FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */ +/*-***************************************** +* FSE advanced functions +******************************************/ +/*! FSE_compress2() : + Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog' + Both parameters can be defined as '0' to mean : use default value + @return : size of compressed data + Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression. + if FSE_isError(return), it's an error code. +*/ +FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); + + /*-***************************************** * FSE detailed API ******************************************/ @@ -96,16 +157,10 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize /*! FSE_normalizeCount(): normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). - useLowProbCount is a boolean parameter which trades off compressed size for - faster header decoding. When it is set to 1, the compressed data will be slightly - smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be - faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 - is a good default, since header deserialization makes a big speed difference. - Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. @return : tableLog, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, - const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); + const unsigned* count, size_t srcSize, unsigned maxSymbolValue); /*! FSE_NCountWriteBound(): Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. @@ -123,6 +178,8 @@ FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, /*! Constructor and Destructor of FSE_CTable. Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ +FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog); +FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct); /*! FSE_buildCTable(): Builds `ct`, which must be already allocated, using FSE_createCTable(). @@ -191,14 +248,23 @@ FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); -/*! FSE_readNCount_bmi2(): - * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. - */ -FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, - unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, - const void* rBuffer, size_t rBuffSize, int bmi2); - +/*! Constructor and Destructor of FSE_DTable. + Note that its size depends on 'tableLog' */ typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ +FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog); +FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt); + +/*! FSE_buildDTable(): + Builds 'dt', which must be already allocated, using FSE_createDTable(). + return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_decompress_usingDTable(): + Decompress compressed source `cSrc` of size `cSrcSize` using `dt` + into `dst` which must be already allocated. + @return : size of regenerated data (necessarily <= `dstCapacity`), + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt); /*! Tutorial : @@ -242,12 +308,12 @@ If there is an error, the function will return an error code, which can be teste *******************************************/ /* FSE buffer bounds */ #define FSE_NCOUNTBOUND 512 -#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ /* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ -#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2)) -#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog))) +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1< 12) ? (1 << (maxTableLog - 2)) : 1024) ) +size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); +/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */ + size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); /**< build a fake FSE_CTable, designed to compress always the same symbolValue */ /* FSE_buildCTable_wksp() : * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). - * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. - * See FSE_buildCTable_wksp() for breakdown of workspace usage. + * `wkspSize` must be >= `(1< FSE_MAX_MEMORY_USAGE) -# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" -#endif /*!FSE_MAX_SYMBOL_VALUE : * Maximum symbol value authorized. @@ -629,7 +697,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) # error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" #endif -#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) +#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3) #endif /* FSE_STATIC_LINKING_ONLY */ @@ -638,5 +706,3 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) #if defined (__cplusplus) } #endif - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/fse_compress.c b/vendor/github.com/DataDog/zstd/fse_compress.c index 41f56e06..68b47e10 100644 --- a/vendor/github.com/DataDog/zstd/fse_compress.c +++ b/vendor/github.com/DataDog/zstd/fse_compress.c @@ -1,21 +1,42 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * FSE : Finite State Entropy encoder - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - Public forum : https://groups.google.com/forum/#!forum/lz4c - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + FSE : Finite State Entropy encoder + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ /* ************************************************************** * Includes ****************************************************************/ +#include /* malloc, free, qsort */ +#include /* memcpy, memset */ #include "compiler.h" #include "mem.h" /* U32, U16, etc. */ #include "debug.h" /* assert, DEBUGLOG */ @@ -24,10 +45,6 @@ #define FSE_STATIC_LINKING_ONLY #include "fse.h" #include "error_private.h" -#define ZSTD_DEPS_NEED_MALLOC -#define ZSTD_DEPS_NEED_MATH64 -#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_free, ZSTD_memcpy, ZSTD_memset */ -#include "bits.h" /* ZSTD_highbit32 */ /* ************************************************************** @@ -77,85 +94,41 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ; FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); U32 const step = FSE_TABLESTEP(tableSize); - U32 const maxSV1 = maxSymbolValue+1; - - U16* cumul = (U16*)workSpace; /* size = maxSV1 */ - FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)(cumul + (maxSV1+1)); /* size = tableSize */ + U32 cumul[FSE_MAX_SYMBOL_VALUE+2]; + FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace; U32 highThreshold = tableSize-1; - assert(((size_t)workSpace & 1) == 0); /* Must be 2 bytes-aligned */ - if (FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) > wkspSize) return ERROR(tableLog_tooLarge); /* CTable header */ + if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge); tableU16[-2] = (U16) tableLog; tableU16[-1] = (U16) maxSymbolValue; assert(tableLog < 16); /* required for threshold strategy to work */ /* For explanations on how to distribute symbol values over the table : - * https://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ + * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ #ifdef __clang_analyzer__ - ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ + memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ #endif /* symbol start positions */ { U32 u; cumul[0] = 0; - for (u=1; u <= maxSV1; u++) { + for (u=1; u <= maxSymbolValue+1; u++) { if (normalizedCounter[u-1]==-1) { /* Low proba symbol */ cumul[u] = cumul[u-1] + 1; tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1); } else { - assert(normalizedCounter[u-1] >= 0); - cumul[u] = cumul[u-1] + (U16)normalizedCounter[u-1]; - assert(cumul[u] >= cumul[u-1]); /* no overflow */ + cumul[u] = cumul[u-1] + normalizedCounter[u-1]; } } - cumul[maxSV1] = (U16)(tableSize+1); + cumul[maxSymbolValue+1] = tableSize+1; } /* Spread symbols */ - if (highThreshold == tableSize - 1) { - /* Case for no low prob count symbols. Lay down 8 bytes at a time - * to reduce branch misses since we are operating on a small block - */ - BYTE* const spread = tableSymbol + tableSize; /* size = tableSize + 8 (may write beyond tableSize) */ - { U64 const add = 0x0101010101010101ull; - size_t pos = 0; - U64 sv = 0; - U32 s; - for (s=0; s=0); - pos += (size_t)n; - } - } - /* Spread symbols across the table. Lack of lowprob symbols means that - * we don't need variable sized inner loop, so we can unroll the loop and - * reduce branch misses. - */ - { size_t position = 0; - size_t s; - size_t const unroll = 2; /* Experimentally determined optimal unroll */ - assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ - for (s = 0; s < (size_t)tableSize; s += unroll) { - size_t u; - for (u = 0; u < unroll; ++u) { - size_t const uPosition = (position + (u * step)) & tableMask; - tableSymbol[uPosition] = spread[s + u]; - } - position = (position + (unroll * step)) & tableMask; - } - assert(position == 0); /* Must have initialized all positions */ - } - } else { - U32 position = 0; + { U32 position = 0; U32 symbol; - for (symbol=0; symbol highThreshold) position = (position + step) & tableMask; /* Low proba area */ } } + assert(position==0); /* Must have initialized all positions */ } @@ -187,17 +161,16 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, case -1: case 1: symbolTT[s].deltaNbBits = (tableLog << 16) - (1< 1); - { U32 const maxBitsOut = tableLog - ZSTD_highbit32 ((U32)normalizedCounter[s]-1); - U32 const minStatePlus = (U32)normalizedCounter[s] << maxBitsOut; + { + U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1); + U32 const minStatePlus = normalizedCounter[s] << maxBitsOut; symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus; - symbolTT[s].deltaFindState = (int)(total - (unsigned)normalizedCounter[s]); - total += (unsigned)normalizedCounter[s]; + symbolTT[s].deltaFindState = total - normalizedCounter[s]; + total += normalizedCounter[s]; } } } } #if 0 /* debug : symbol costs */ @@ -208,26 +181,31 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, symbol, normalizedCounter[symbol], FSE_getMaxNbBits(symbolTT, symbol), (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256); - } } + } + } #endif return 0; } +size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) +{ + FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */ + return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol)); +} + + #ifndef FSE_COMMONDEFS_ONLY + /*-************************************************************** * FSE NCount encoding ****************************************************************/ size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog) { - size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog - + 4 /* bitCount initialized at 4 */ - + 2 /* first two symbols may use one additional bit each */) / 8) - + 1 /* round up to whole nb bytes */ - + 2 /* additional two bytes for bitstream flush */; + size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3; return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */ } @@ -344,11 +322,21 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, * FSE Compression Code ****************************************************************/ +FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog) +{ + size_t size; + if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; + size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32); + return (FSE_CTable*)malloc(size); +} + +void FSE_freeCTable (FSE_CTable* ct) { free(ct); } + /* provides the minimum logSize to safely represent a distribution */ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) { - U32 minBitsSrc = ZSTD_highbit32((U32)(srcSize)) + 1; - U32 minBitsSymbols = ZSTD_highbit32(maxSymbolValue) + 2; + U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1; + U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2; U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols; assert(srcSize > 1); /* Not supported, RLE should be used instead */ return minBits; @@ -356,7 +344,7 @@ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus) { - U32 maxBitsSrc = ZSTD_highbit32((U32)(srcSize - 1)) - minus; + U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus; U32 tableLog = maxTableLog; U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue); assert(srcSize > 1); /* Not supported, RLE should be used instead */ @@ -373,10 +361,11 @@ unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2); } + /* Secondary normalization method. To be used when primary method fails. */ -static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue, short lowProbCount) +static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue) { short const NOT_YET_ASSIGNED = -2; U32 s; @@ -393,7 +382,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, continue; } if (count[s] <= lowThreshold) { - norm[s] = lowProbCount; + norm[s] = -1; distributed++; total -= count[s]; continue; @@ -445,7 +434,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, { U64 const vStepLog = 62 - tableLog; U64 const mid = (1ULL << (vStepLog-1)) - 1; - U64 const rStep = ZSTD_div64((((U64)1<> scale); @@ -501,7 +490,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, } } if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) { /* corner case, need another normalization method */ - size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue, lowProbCount); + size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue); if (FSE_isError(errorCode)) return errorCode; } else normalizedCounter[largest] += (short)stillToDistribute; @@ -524,6 +513,40 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, return tableLog; } + +/* fake FSE_CTable, for raw (uncompressed) input */ +size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) +{ + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSymbolValue = tableMask; + void* const ptr = ct; + U16* const tableU16 = ( (U16*) ptr) + 2; + void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */ + FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* header */ + tableU16[-2] = (U16) nbBits; + tableU16[-1] = (U16) maxSymbolValue; + + /* Build table */ + for (s=0; s not compressible */ + if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */ + } + + tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue); + CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) ); -#endif /* USE_EXTERNAL_ZSTD */ + /* Write table description header */ + { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); + op += nc_err; + } + + /* Compress */ + CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) ); + { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) ); + if (cSize == 0) return 0; /* not enough space for compressed data */ + op += cSize; + } + + /* check compressibility */ + if ( (size_t)(op-ostart) >= srcSize-1 ) return 0; + + return op-ostart; +} + +typedef struct { + FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; + BYTE scratchBuffer[1 << FSE_MAX_TABLELOG]; +} fseWkspMax_t; + +size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog) +{ + fseWkspMax_t scratchBuffer; + DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */ + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer)); +} + +size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG); +} + + +#endif /* FSE_COMMONDEFS_ONLY */ diff --git a/vendor/github.com/DataDog/zstd/fse_decompress.c b/vendor/github.com/DataDog/zstd/fse_decompress.c index e6aafaef..4f073789 100644 --- a/vendor/github.com/DataDog/zstd/fse_decompress.c +++ b/vendor/github.com/DataDog/zstd/fse_decompress.c @@ -1,31 +1,48 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * FSE : Finite State Entropy decoder - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - Public forum : https://groups.google.com/forum/#!forum/lz4c - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + FSE : Finite State Entropy decoder + Copyright (C) 2013-2015, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ /* ************************************************************** * Includes ****************************************************************/ -#include "debug.h" /* assert */ +#include /* malloc, free, qsort */ +#include /* memcpy, memset */ #include "bitstream.h" #include "compiler.h" #define FSE_STATIC_LINKING_ONLY #include "fse.h" #include "error_private.h" -#define ZSTD_DEPS_NEED_MALLOC -#include "zstd_deps.h" -#include "bits.h" /* ZSTD_highbit32 */ /* ************************************************************** @@ -34,6 +51,11 @@ #define FSE_isError ERR_isError #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ +/* check and forward error code */ +#ifndef CHECK_F +#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; } +#endif + /* ************************************************************** * Templates @@ -57,19 +79,30 @@ #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) -static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) + +/* Function templates */ +FSE_DTable* FSE_createDTable (unsigned tableLog) +{ + if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; + return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); +} + +void FSE_freeDTable (FSE_DTable* dt) +{ + free(dt); +} + +size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) { void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); - U16* symbolNext = (U16*)workSpace; - BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); + U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; U32 highThreshold = tableSize-1; /* Sanity Checks */ - if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); @@ -87,57 +120,11 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; symbolNext[s] = normalizedCounter[s]; } } } - ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - if (highThreshold == tableSize - 1) { - size_t const tableMask = tableSize-1; - size_t const step = FSE_TABLESTEP(tableSize); - /* First lay down the symbols in order. - * We use a uint64_t to lay down 8 bytes at a time. This reduces branch - * misses since small blocks generally have small table logs, so nearly - * all symbols have counts <= 8. We ensure we have 8 bytes at the end of - * our buffer to handle the over-write. - */ - { - U64 const add = 0x0101010101010101ull; - size_t pos = 0; - U64 sv = 0; - U32 s; - for (s=0; stableLog = 0; + DTableH->fastMode = 0; + + cell->newState = 0; + cell->symbol = symbolValue; + cell->nbBits = 0; + + return 0; +} + + +size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) +{ + void* ptr = dt; + FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; + void* dPtr = dt + 1; + FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSV1 = tableMask+1; + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* Build Decoding Table */ + DTableH->tableLog = (U16)nbBits; + DTableH->fastMode = 1; + for (s=0; sfastMode; -FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( - void* dst, size_t dstCapacity, - const void* cSrc, size_t cSrcSize, - unsigned maxLog, void* workSpace, size_t wkspSize, - int bmi2) + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); + return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); +} + + +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog) { const BYTE* const istart = (const BYTE*)cSrc; const BYTE* ip = istart; + short counting[FSE_MAX_SYMBOL_VALUE+1]; unsigned tableLog; unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; - FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; - - DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); - if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); /* normal FSE decoding mode */ - { - size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); - if (FSE_isError(NCountLength)) return NCountLength; - if (tableLog > maxLog) return ERROR(tableLog_tooLarge); - assert(NCountLength <= cSrcSize); - ip += NCountLength; - cSrcSize -= NCountLength; - } + size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); + if (FSE_isError(NCountLength)) return NCountLength; + //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */ + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + ip += NCountLength; + cSrcSize -= NCountLength; - if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); - assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize); - workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); - wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) ); - CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); + return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */ +} - { - const void* ptr = wksp->dtable; - const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; - const U32 fastMode = DTableH->fastMode; - /* select fast mode (static) */ - if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1); - return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0); - } -} +typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; -/* Avoids the FORCE_INLINE of the _body() function. */ -static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) { - return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); + DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ + return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG); } -#if DYNAMIC_BMI2 -BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) -{ - return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); -} -#endif -size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) -{ -#if DYNAMIC_BMI2 - if (bmi2) { - return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); - } -#endif - (void)bmi2; - return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); -} #endif /* FSE_COMMONDEFS_ONLY */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/hist.c b/vendor/github.com/DataDog/zstd/hist.c index 2d6eae8c..45b7babc 100644 --- a/vendor/github.com/DataDog/zstd/hist.c +++ b/vendor/github.com/DataDog/zstd/hist.c @@ -1,17 +1,36 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * hist : Histogram functions - * part of Finite State Entropy project - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - Public forum : https://groups.google.com/forum/#!forum/lz4c - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + hist : Histogram functions + part of Finite State Entropy project + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ /* --- dependencies --- */ @@ -35,7 +54,7 @@ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned largestCount=0; - ZSTD_memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); + memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } while (ip= HIST_WKSP_SIZE_U32. + * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32. * @return : largest histogram frequency, - * or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */ + * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */ static size_t HIST_count_parallel_wksp( unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, @@ -72,21 +91,22 @@ static size_t HIST_count_parallel_wksp( { const BYTE* ip = (const BYTE*)source; const BYTE* const iend = ip+sourceSize; - size_t const countSize = (*maxSymbolValuePtr + 1) * sizeof(*count); + unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned max=0; U32* const Counting1 = workSpace; U32* const Counting2 = Counting1 + 256; U32* const Counting3 = Counting2 + 256; U32* const Counting4 = Counting3 + 256; + memset(workSpace, 0, 4*256*sizeof(unsigned)); + /* safety checks */ - assert(*maxSymbolValuePtr <= 255); if (!sourceSize) { - ZSTD_memset(count, 0, countSize); + memset(count, 0, maxSymbolValue + 1); *maxSymbolValuePtr = 0; return 0; } - ZSTD_memset(workSpace, 0, 4*256*sizeof(unsigned)); + if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ /* by stripes of 16 bytes */ { U32 cached = MEM_read32(ip); ip += 4; @@ -118,18 +138,21 @@ static size_t HIST_count_parallel_wksp( /* finish last symbols */ while (ipmaxSymbolValue; s--) { Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; - if (Counting1[s] > max) max = Counting1[s]; + if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); } } - { unsigned maxSymbolValue = 255; - while (!Counting1[maxSymbolValue]) maxSymbolValue--; - if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall); - *maxSymbolValuePtr = maxSymbolValue; - ZSTD_memmove(count, Counting1, countSize); /* in case count & Counting1 are overlapping */ - } + { U32 s; + if (maxSymbolValue > 255) maxSymbolValue = 255; + for (s=0; s<=maxSymbolValue; s++) { + count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; + if (count[s] > max) max = count[s]; + } } + + while (!count[maxSymbolValue]) maxSymbolValue--; + *maxSymbolValuePtr = maxSymbolValue; return (size_t)max; } @@ -149,6 +172,14 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace); } +/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ +size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize) +{ + unsigned tmpCounters[HIST_WKSP_SIZE_U32]; + return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); +} + /* HIST_count_wksp() : * Same as HIST_count(), but using an externally provided scratch buffer. * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ @@ -164,21 +195,9 @@ size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize); } -#ifndef ZSTD_NO_UNUSED_FUNCTIONS -/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ -size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, - const void* source, size_t sourceSize) -{ - unsigned tmpCounters[HIST_WKSP_SIZE_U32]; - return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); -} - size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) { unsigned tmpCounters[HIST_WKSP_SIZE_U32]; return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters)); } -#endif - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/hist.h b/vendor/github.com/DataDog/zstd/hist.h index 410accc0..8b389358 100644 --- a/vendor/github.com/DataDog/zstd/hist.h +++ b/vendor/github.com/DataDog/zstd/hist.h @@ -1,21 +1,40 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * hist : Histogram functions - * part of Finite State Entropy project - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - Public forum : https://groups.google.com/forum/#!forum/lz4c - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + hist : Histogram functions + part of Finite State Entropy project + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ /* --- dependencies --- */ -#include "zstd_deps.h" /* size_t */ +#include /* size_t */ /* --- simple histogram functions --- */ @@ -74,5 +93,3 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, */ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/huf.h b/vendor/github.com/DataDog/zstd/huf.h index ad9a485c..6b572c44 100644 --- a/vendor/github.com/DataDog/zstd/huf.h +++ b/vendor/github.com/DataDog/zstd/huf.h @@ -1,16 +1,35 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * huff0 huffman codec, - * part of Finite State Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + huff0 huffman codec, + part of Finite State Entropy library + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy ****************************************************************** */ #if defined (__cplusplus) @@ -21,30 +40,105 @@ extern "C" { #define HUF_H_298734234 /* *** Dependencies *** */ -#include "zstd_deps.h" /* size_t */ -#include "mem.h" /* U32 */ -#define FSE_STATIC_LINKING_ONLY -#include "fse.h" +#include /* size_t */ + + +/* *** library symbols visibility *** */ +/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual, + * HUF symbols remain "private" (internal symbols for library only). + * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define HUF_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define HUF_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */ +#else +# define HUF_PUBLIC_API +#endif + + +/* ========================== */ +/* *** simple functions *** */ +/* ========================== */ + +/** HUF_compress() : + * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'. + * 'dst' buffer must be already allocated. + * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize). + * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB. + * @return : size of compressed data (<= `dstCapacity`). + * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + * if HUF_isError(return), compression failed (more details using HUF_getErrorName()) + */ +HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/** HUF_decompress() : + * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize', + * into already allocated buffer 'dst', of minimum size 'dstSize'. + * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data. + * Note : in contrast with FSE, HUF_decompress can regenerate + * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, + * because it knows size to regenerate (originalSize). + * @return : size of regenerated data (== originalSize), + * or an error code, which can be tested using HUF_isError() + */ +HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize); /* *** Tool functions *** */ -#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ -size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ +HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ /* Error Management */ -unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ -const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ +HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ + + +/* *** Advanced function *** */ + +/** HUF_compress2() : + * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`. + * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX . + * `tableLog` must be `<= HUF_TABLELOG_MAX` . */ +HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog); + +/** HUF_compress4X_wksp() : + * Same as HUF_compress2(), but uses externally allocated `workSpace`. + * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */ +#define HUF_WORKSPACE_SIZE (6 << 10) +#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32)) +HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize); + +#endif /* HUF_H_298734234 */ + +/* ****************************************************************** + * WARNING !! + * The following section contains advanced and experimental definitions + * which shall never be used in the context of a dynamic library, + * because they are not guaranteed to remain stable in the future. + * Only consider them in association with static linking. + * *****************************************************************/ +#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY) +#define HUF_H_HUF_STATIC_LINKING_ONLY +/* *** Dependencies *** */ +#include "mem.h" /* U32 */ -#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) -#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) /* *** Constants *** */ -#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */ #define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ #define HUF_SYMBOLVALUE_MAX 255 -#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ #if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) # error "HUF_TABLELOG_MAX is too large !" #endif @@ -59,12 +153,12 @@ const char* HUF_getErrorName(size_t code); /**< provides error code string (use #define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ /* static allocation of HUF's Compression Table */ -/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ -typedef size_t HUF_CElt; /* consider it an incomplete type */ -#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ -#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) +#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32)) #define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ - HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ + U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \ + void* name##hv = &(name##hb); \ + HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */ /* static allocation of HUF's DTable */ typedef U32 HUF_DTable; @@ -78,49 +172,25 @@ typedef U32 HUF_DTable; /* **************************************** * Advanced decompression functions ******************************************/ +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +#endif -/** - * Huffman flags bitset. - * For all flags, 0 is the default value. - */ -typedef enum { - /** - * If compiled with DYNAMIC_BMI2: Set flag only if the CPU supports BMI2 at runtime. - * Otherwise: Ignored. - */ - HUF_flags_bmi2 = (1 << 0), - /** - * If set: Test possible table depths to find the one that produces the smallest header + encoded size. - * If unset: Use heuristic to find the table depth. - */ - HUF_flags_optimalDepth = (1 << 1), - /** - * If set: If the previous table can encode the input, always reuse the previous table. - * If unset: If the previous table can encode the input, reuse the previous table if it results in a smaller output. - */ - HUF_flags_preferRepeat = (1 << 2), - /** - * If set: Sample the input and check if the sample is uncompressible, if it is then don't attempt to compress. - * If unset: Always histogram the entire input. - */ - HUF_flags_suspectUncompressible = (1 << 3), - /** - * If set: Don't use assembly implementations - * If unset: Allow using assembly implementations - */ - HUF_flags_disableAsm = (1 << 4), - /** - * If set: Don't use the fast decoding loop, always use the fallback decoding loop. - * If unset: Use the fast decoding loop when possible. - */ - HUF_flags_disableFast = (1 << 5) -} HUF_flags_e; +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif /* **************************************** * HUF detailed API * ****************************************/ -#define HUF_OPTIMAL_DEPTH_THRESHOLD ZSTD_btultra /*! HUF_compress() does the following: * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h") @@ -133,38 +203,33 @@ typedef enum { * For example, it's possible to compress several blocks using the same 'CTable', * or to save and regenerate 'CTable' using external methods. */ -unsigned HUF_minTableLog(unsigned symbolCardinality); -unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue); -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace, - size_t wkspSize, HUF_CElt* table, const unsigned* count, int flags); /* table is used as scratch space for building and testing tables, not a return value */ -size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); -size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); -size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); -int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); +typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ +size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); typedef enum { HUF_repeat_none, /**< Cannot use the previous table */ HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ } HUF_repeat; - /** HUF_compress4X_repeat() : * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. * If it uses hufTable it does not modify hufTable or repeat. * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. - * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ + * If preferRepeat then the old table will always be used if valid. */ size_t HUF_compress4X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int flags); + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); /** HUF_buildCTable_wksp() : * Same as HUF_buildCTable(), but using externally allocated scratch buffer. * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. */ -#define HUF_CTABLE_WORKSPACE_SIZE_U32 ((4 * (HUF_SYMBOLVALUE_MAX + 1)) + 192) +#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1) #define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, @@ -179,27 +244,15 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, const void* src, size_t srcSize); -/*! HUF_readStats_wksp() : - * Same as HUF_readStats() but takes an external workspace which must be - * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. - * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. - */ -#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) -#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) -size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, - U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workspace, size_t wkspSize, - int flags); - /** HUF_readCTable() : * Loading a CTable saved with HUF_writeCTable() */ -size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); -/** HUF_getNbBitsFromCTable() : +/** HUF_getNbBits() : * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX - * Note 1 : is not inlined, as HUF_CElt definition is private */ -U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); + * Note 1 : is not inlined, as HUF_CElt definition is private + * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */ +U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue); /* * HUF_decompress() does the following: @@ -225,52 +278,81 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); * a required workspace size greater than that specified in the following * macro. */ -#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) +#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10) #define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + /* ====================== */ /* single stream variants */ /* ====================== */ -size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); +size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); /** HUF_compress1X_repeat() : * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. * If it uses hufTable it does not modify hufTable or repeat. * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. - * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ + * If preferRepeat then the old table will always be used if valid. */ size_t HUF_compress1X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int flags); + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); -size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ #ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); /**< double-symbols decoder */ +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ #endif -/* BMI2 variants. - * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. - */ -size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); +size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); +size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); #ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ #endif -size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); -size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ #ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); +size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); #endif #ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); +size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); #endif -#endif /* HUF_H_298734234 */ +/* BMI2 variants. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); + +#endif /* HUF_STATIC_LINKING_ONLY */ #if defined (__cplusplus) } #endif - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/huf_compress.c b/vendor/github.com/DataDog/zstd/huf_compress.c index 7fb3c96a..f074f1e0 100644 --- a/vendor/github.com/DataDog/zstd/huf_compress.c +++ b/vendor/github.com/DataDog/zstd/huf_compress.c @@ -1,16 +1,35 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * Huffman encoder, part of New Generation Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - Public forum : https://groups.google.com/forum/#!forum/lz4c - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + Huffman encoder, part of New Generation Entropy library + Copyright (C) 2013-2016, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ /* ************************************************************** @@ -24,15 +43,16 @@ /* ************************************************************** * Includes ****************************************************************/ -#include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include /* memcpy, memset */ +#include /* printf (debug) */ #include "compiler.h" #include "bitstream.h" #include "hist.h" #define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */ #include "fse.h" /* header compression */ +#define HUF_STATIC_LINKING_ONLY #include "huf.h" #include "error_private.h" -#include "bits.h" /* ZSTD_highbit32 */ /* ************************************************************** @@ -40,114 +60,29 @@ ****************************************************************/ #define HUF_isError ERR_isError #define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ +#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e +#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } /* ************************************************************** -* Required declarations +* Utils ****************************************************************/ -typedef struct nodeElt_s { - U32 count; - U16 parent; - BYTE byte; - BYTE nbBits; -} nodeElt; - - -/* ************************************************************** -* Debug Traces -****************************************************************/ - -#if DEBUGLEVEL >= 2 - -static size_t showU32(const U32* arr, size_t size) +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) { - size_t u; - for (u=0; u= add) { - assert(add < align); - assert(((size_t)aligned & mask) == 0); - *workspaceSizePtr -= add; - return aligned; - } else { - *workspaceSizePtr = 0; - return NULL; - } -} - - /* HUF_compressWeights() : * Same as FSE_compress(), but dedicated to huff0's weights compression. * The use case needs much less stack memory. * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX. */ #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6 - -typedef struct { - FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; - U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)]; - unsigned count[HUF_TABLELOG_MAX+1]; - S16 norm[HUF_TABLELOG_MAX+1]; -} HUF_CompressWeightsWksp; - -static size_t -HUF_compressWeights(void* dst, size_t dstSize, - const void* weightTable, size_t wtSize, - void* workspace, size_t workspaceSize) +static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) { BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; @@ -155,103 +90,69 @@ HUF_compressWeights(void* dst, size_t dstSize, unsigned maxSymbolValue = HUF_TABLELOG_MAX; U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER; - HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - if (workspaceSize < sizeof(HUF_CompressWeightsWksp)) return ERROR(GENERIC); + FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; + BYTE scratchBuffer[1<count, &maxSymbolValue, weightTable, wtSize); /* never fails */ + { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */ if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ } tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue); - CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) ); + CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) ); /* Write table description header */ - { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) ); + { CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); op += hSize; } /* Compress */ - CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) ); - { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) ); + CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) ); + { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) ); if (cSize == 0) return 0; /* not enough space for compressed data */ op += cSize; } - return (size_t)(op-ostart); -} - -static size_t HUF_getNbBits(HUF_CElt elt) -{ - return elt & 0xFF; -} - -static size_t HUF_getNbBitsFast(HUF_CElt elt) -{ - return elt; -} - -static size_t HUF_getValue(HUF_CElt elt) -{ - return elt & ~(size_t)0xFF; + return op-ostart; } -static size_t HUF_getValueFast(HUF_CElt elt) -{ - return elt; -} -static void HUF_setNbBits(HUF_CElt* elt, size_t nbBits) -{ - assert(nbBits <= HUF_TABLELOG_ABSOLUTEMAX); - *elt = nbBits; -} +struct HUF_CElt_s { + U16 val; + BYTE nbBits; +}; /* typedef'd to HUF_CElt within "huf.h" */ -static void HUF_setValue(HUF_CElt* elt, size_t value) +/*! HUF_writeCTable() : + `CTable` : Huffman tree to save, using huf representation. + @return : size of saved CTable */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, + const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog) { - size_t const nbBits = HUF_getNbBits(*elt); - if (nbBits > 0) { - assert((value >> nbBits) == 0); - *elt |= value << (sizeof(HUF_CElt) * 8 - nbBits); - } -} - -typedef struct { - HUF_CompressWeightsWksp wksp; BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */ BYTE huffWeight[HUF_SYMBOLVALUE_MAX]; -} HUF_WriteCTableWksp; - -size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, - const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, - void* workspace, size_t workspaceSize) -{ - HUF_CElt const* const ct = CTable + 1; BYTE* op = (BYTE*)dst; U32 n; - HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE >= sizeof(HUF_WriteCTableWksp)); - - /* check conditions */ - if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC); + /* check conditions */ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); /* convert to weight */ - wksp->bitsToWeight[0] = 0; + bitsToWeight[0] = 0; for (n=1; nbitsToWeight[n] = (BYTE)(huffLog + 1 - n); + bitsToWeight[n] = (BYTE)(huffLog + 1 - n); for (n=0; nhuffWeight[n] = wksp->bitsToWeight[HUF_getNbBits(ct[n])]; + huffWeight[n] = bitsToWeight[CTable[n].nbBits]; /* attempt weights compression by FSE */ - if (maxDstSize < 1) return ERROR(dstSize_tooSmall); - { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) ); + { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) ); if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */ op[0] = (BYTE)hSize; return hSize+1; @@ -261,49 +162,45 @@ size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */ if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1)); - wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ + huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ for (n=0; nhuffWeight[n] << 4) + wksp->huffWeight[n+1]); + op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]); return ((maxSymbolValue+1)/2) + 1; } -size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights) +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) { BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */ U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ U32 tableLog = 0; U32 nbSymbols = 0; - HUF_CElt* const ct = CTable + 1; /* get symbol weights */ CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize)); - *hasZeroWeights = (rankVal[0] > 0); /* check result */ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall); - CTable[0] = tableLog; - /* Prepare base value per rank */ { U32 n, nextRankStart = 0; for (n=1; n<=tableLog; n++) { - U32 curr = nextRankStart; + U32 current = nextRankStart; nextRankStart += (rankVal[n] << (n-1)); - rankVal[n] = curr; + rankVal[n] = current; } } /* fill nbBits */ { U32 n; for (n=0; nn=tableLog+1 */ U16 valPerRank[HUF_TABLELOG_MAX+2] = {0}; - { U32 n; for (n=0; n>= 1; } } /* assign value within rank, symbol order */ - { U32 n; for (n=0; n @targetNbBits - * to employ @targetNbBits instead. Then it adjusts the tree - * so that it remains a valid canonical Huffman tree. - * - * @pre The sum of the ranks of each symbol == 2^largestBits, - * where largestBits == huffNode[lastNonNull].nbBits. - * @post The sum of the ranks of each symbol == 2^largestBits, - * where largestBits is the return value (expected <= targetNbBits). - * - * @param huffNode The Huffman tree modified in place to enforce targetNbBits. - * It's presumed sorted, from most frequent to rarest symbol. - * @param lastNonNull The symbol with the lowest count in the Huffman tree. - * @param targetNbBits The allowed number of bits, which the Huffman tree - * may not respect. After this function the Huffman tree will - * respect targetNbBits. - * @return The maximum number of bits of the Huffman tree after adjustment. - */ -static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits) +typedef struct nodeElt_s { + U32 count; + U16 parent; + BYTE byte; + BYTE nbBits; +} nodeElt; + +static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) { const U32 largestBits = huffNode[lastNonNull].nbBits; - /* early exit : no elt > targetNbBits, so the tree is already valid. */ - if (largestBits <= targetNbBits) return largestBits; - - DEBUGLOG(5, "HUF_setMaxHeight (targetNbBits = %u)", targetNbBits); + if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */ /* there are several too large elements (at least >= 2) */ { int totalCost = 0; - const U32 baseCost = 1 << (largestBits - targetNbBits); - int n = (int)lastNonNull; - - /* Adjust any ranks > targetNbBits to targetNbBits. - * Compute totalCost, which is how far the sum of the ranks is - * we are over 2^largestBits after adjust the offending ranks. - */ - while (huffNode[n].nbBits > targetNbBits) { + const U32 baseCost = 1 << (largestBits - maxNbBits); + U32 n = lastNonNull; + + while (huffNode[n].nbBits > maxNbBits) { totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); - huffNode[n].nbBits = (BYTE)targetNbBits; - n--; - } - /* n stops at huffNode[n].nbBits <= targetNbBits */ - assert(huffNode[n].nbBits <= targetNbBits); - /* n end at index of smallest symbol using < targetNbBits */ - while (huffNode[n].nbBits == targetNbBits) --n; + huffNode[n].nbBits = (BYTE)maxNbBits; + n --; + } /* n stops at huffNode[n].nbBits <= maxNbBits */ + while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */ - /* renorm totalCost from 2^largestBits to 2^targetNbBits - * note : totalCost is necessarily a multiple of baseCost */ - assert(((U32)totalCost & (baseCost - 1)) == 0); - totalCost >>= (largestBits - targetNbBits); - assert(totalCost > 0); + /* renorm totalCost */ + totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */ /* repay normalized cost */ { U32 const noSymbol = 0xF0F0F0F0; U32 rankLast[HUF_TABLELOG_MAX+2]; + int pos; - /* Get pos of last (smallest = lowest cum. count) symbol per rank */ - ZSTD_memset(rankLast, 0xF0, sizeof(rankLast)); - { U32 currentNbBits = targetNbBits; - int pos; + /* Get pos of last (smallest) symbol per rank */ + memset(rankLast, 0xF0, sizeof(rankLast)); + { U32 currentNbBits = maxNbBits; for (pos=n ; pos >= 0; pos--) { if (huffNode[pos].nbBits >= currentNbBits) continue; - currentNbBits = huffNode[pos].nbBits; /* < targetNbBits */ - rankLast[targetNbBits-currentNbBits] = (U32)pos; + currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ + rankLast[maxNbBits-currentNbBits] = pos; } } while (totalCost > 0) { - /* Try to reduce the next power of 2 above totalCost because we - * gain back half the rank. - */ - U32 nBitsToDecrease = ZSTD_highbit32((U32)totalCost) + 1; + U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1; for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { - U32 const highPos = rankLast[nBitsToDecrease]; - U32 const lowPos = rankLast[nBitsToDecrease-1]; + U32 highPos = rankLast[nBitsToDecrease]; + U32 lowPos = rankLast[nBitsToDecrease-1]; if (highPos == noSymbol) continue; - /* Decrease highPos if no symbols of lowPos or if it is - * not cheaper to remove 2 lowPos than highPos. - */ if (lowPos == noSymbol) break; { U32 const highTotal = huffNode[highPos].count; U32 const lowTotal = 2 * huffNode[lowPos].count; if (highTotal <= lowTotal) break; } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ - assert(rankLast[nBitsToDecrease] != noSymbol || nBitsToDecrease == 1); /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) - nBitsToDecrease++; - assert(rankLast[nBitsToDecrease] != noSymbol); - /* Increase the number of bits to gain back half the rank cost. */ + nBitsToDecrease ++; totalCost -= 1 << (nBitsToDecrease-1); - huffNode[rankLast[nBitsToDecrease]].nbBits++; - - /* Fix up the new rank. - * If the new rank was empty, this symbol is now its smallest. - * Otherwise, this symbol will be the largest in the new rank so no adjustment. - */ if (rankLast[nBitsToDecrease-1] == noSymbol) - rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; - /* Fix up the old rank. - * If the symbol was at position 0, meaning it was the highest weight symbol in the tree, - * it must be the only symbol in its rank, so the old rank now has no symbols. - * Otherwise, since the Huffman nodes are sorted by count, the previous position is now - * the smallest node in the rank. If the previous position belongs to a different rank, - * then the rank is now empty. - */ + rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */ + huffNode[rankLast[nBitsToDecrease]].nbBits ++; if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */ rankLast[nBitsToDecrease] = noSymbol; else { rankLast[nBitsToDecrease]--; - if (huffNode[rankLast[nBitsToDecrease]].nbBits != targetNbBits-nBitsToDecrease) + if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ - } - } /* while (totalCost > 0) */ - - /* If we've removed too much weight, then we have to add it back. - * To avoid overshooting again, we only adjust the smallest rank. - * We take the largest nodes from the lowest rank 0 and move them - * to rank 1. There's guaranteed to be enough rank 0 symbols because - * TODO. - */ + } } /* while (totalCost > 0) */ + while (totalCost < 0) { /* Sometimes, cost correction overshoot */ - /* special case : no rank 1 symbol (using targetNbBits-1); - * let's create one from largest rank 0 (using targetNbBits). - */ - if (rankLast[1] == noSymbol) { - while (huffNode[n].nbBits == targetNbBits) n--; + if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ + while (huffNode[n].nbBits == maxNbBits) n--; huffNode[n+1].nbBits--; - assert(n >= 0); - rankLast[1] = (U32)(n+1); + rankLast[1] = n+1; totalCost++; continue; } huffNode[ rankLast[1] + 1 ].nbBits--; rankLast[1]++; totalCost ++; - } - } /* repay normalized cost */ - } /* there are several too large elements (at least >= 2) */ + } } } /* there are several too large elements (at least >= 2) */ - return targetNbBits; + return maxNbBits; } -typedef struct { - U16 base; - U16 curr; -} rankPos; - -typedef nodeElt huffNodeTable[2 * (HUF_SYMBOLVALUE_MAX + 1)]; - -/* Number of buckets available for HUF_sort() */ -#define RANK_POSITION_TABLE_SIZE 192 typedef struct { - huffNodeTable huffNodeTbl; - rankPos rankPosition[RANK_POSITION_TABLE_SIZE]; -} HUF_buildCTable_wksp_tables; - -/* RANK_POSITION_DISTINCT_COUNT_CUTOFF == Cutoff point in HUF_sort() buckets for which we use log2 bucketing. - * Strategy is to use as many buckets as possible for representing distinct - * counts while using the remainder to represent all "large" counts. - * - * To satisfy this requirement for 192 buckets, we can do the following: - * Let buckets 0-166 represent distinct counts of [0, 166] - * Let buckets 166 to 192 represent all remaining counts up to RANK_POSITION_MAX_COUNT_LOG using log2 bucketing. - */ -#define RANK_POSITION_MAX_COUNT_LOG 32 -#define RANK_POSITION_LOG_BUCKETS_BEGIN ((RANK_POSITION_TABLE_SIZE - 1) - RANK_POSITION_MAX_COUNT_LOG - 1 /* == 158 */) -#define RANK_POSITION_DISTINCT_COUNT_CUTOFF (RANK_POSITION_LOG_BUCKETS_BEGIN + ZSTD_highbit32(RANK_POSITION_LOG_BUCKETS_BEGIN) /* == 166 */) - -/* Return the appropriate bucket index for a given count. See definition of - * RANK_POSITION_DISTINCT_COUNT_CUTOFF for explanation of bucketing strategy. - */ -static U32 HUF_getIndex(U32 const count) { - return (count < RANK_POSITION_DISTINCT_COUNT_CUTOFF) - ? count - : ZSTD_highbit32(count) + RANK_POSITION_LOG_BUCKETS_BEGIN; -} - -/* Helper swap function for HUF_quickSortPartition() */ -static void HUF_swapNodes(nodeElt* a, nodeElt* b) { - nodeElt tmp = *a; - *a = *b; - *b = tmp; -} - -/* Returns 0 if the huffNode array is not sorted by descending count */ -MEM_STATIC int HUF_isSorted(nodeElt huffNode[], U32 const maxSymbolValue1) { - U32 i; - for (i = 1; i < maxSymbolValue1; ++i) { - if (huffNode[i].count > huffNode[i-1].count) { - return 0; - } - } - return 1; -} - -/* Insertion sort by descending order */ -HINT_INLINE void HUF_insertionSort(nodeElt huffNode[], int const low, int const high) { - int i; - int const size = high-low+1; - huffNode += low; - for (i = 1; i < size; ++i) { - nodeElt const key = huffNode[i]; - int j = i - 1; - while (j >= 0 && huffNode[j].count < key.count) { - huffNode[j + 1] = huffNode[j]; - j--; - } - huffNode[j + 1] = key; - } -} - -/* Pivot helper function for quicksort. */ -static int HUF_quickSortPartition(nodeElt arr[], int const low, int const high) { - /* Simply select rightmost element as pivot. "Better" selectors like - * median-of-three don't experimentally appear to have any benefit. - */ - U32 const pivot = arr[high].count; - int i = low - 1; - int j = low; - for ( ; j < high; j++) { - if (arr[j].count > pivot) { - i++; - HUF_swapNodes(&arr[i], &arr[j]); - } - } - HUF_swapNodes(&arr[i + 1], &arr[high]); - return i + 1; -} - -/* Classic quicksort by descending with partially iterative calls - * to reduce worst case callstack size. - */ -static void HUF_simpleQuickSort(nodeElt arr[], int low, int high) { - int const kInsertionSortThreshold = 8; - if (high - low < kInsertionSortThreshold) { - HUF_insertionSort(arr, low, high); - return; - } - while (low < high) { - int const idx = HUF_quickSortPartition(arr, low, high); - if (idx - low < high - idx) { - HUF_simpleQuickSort(arr, low, idx - 1); - low = idx + 1; - } else { - HUF_simpleQuickSort(arr, idx + 1, high); - high = idx - 1; - } - } -} + U32 base; + U32 current; +} rankPos; -/** - * HUF_sort(): - * Sorts the symbols [0, maxSymbolValue] by count[symbol] in decreasing order. - * This is a typical bucket sorting strategy that uses either quicksort or insertion sort to sort each bucket. - * - * @param[out] huffNode Sorted symbols by decreasing count. Only members `.count` and `.byte` are filled. - * Must have (maxSymbolValue + 1) entries. - * @param[in] count Histogram of the symbols. - * @param[in] maxSymbolValue Maximum symbol value. - * @param rankPosition This is a scratch workspace. Must have RANK_POSITION_TABLE_SIZE entries. - */ -static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSymbolValue, rankPos rankPosition[]) { +static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue) +{ + rankPos rank[32]; U32 n; - U32 const maxSymbolValue1 = maxSymbolValue+1; - - /* Compute base and set curr to base. - * For symbol s let lowerRank = HUF_getIndex(count[n]) and rank = lowerRank + 1. - * See HUF_getIndex to see bucketing strategy. - * We attribute each symbol to lowerRank's base value, because we want to know where - * each rank begins in the output, so for rank R we want to count ranks R+1 and above. - */ - ZSTD_memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE); - for (n = 0; n < maxSymbolValue1; ++n) { - U32 lowerRank = HUF_getIndex(count[n]); - assert(lowerRank < RANK_POSITION_TABLE_SIZE - 1); - rankPosition[lowerRank].base++; - } - assert(rankPosition[RANK_POSITION_TABLE_SIZE - 1].base == 0); - /* Set up the rankPosition table */ - for (n = RANK_POSITION_TABLE_SIZE - 1; n > 0; --n) { - rankPosition[n-1].base += rankPosition[n].base; - rankPosition[n-1].curr = rankPosition[n-1].base; + memset(rank, 0, sizeof(rank)); + for (n=0; n<=maxSymbolValue; n++) { + U32 r = BIT_highbit32(count[n] + 1); + rank[r].base ++; } - - /* Insert each symbol into their appropriate bucket, setting up rankPosition table. */ - for (n = 0; n < maxSymbolValue1; ++n) { + for (n=30; n>0; n--) rank[n-1].base += rank[n].base; + for (n=0; n<32; n++) rank[n].current = rank[n].base; + for (n=0; n<=maxSymbolValue; n++) { U32 const c = count[n]; - U32 const r = HUF_getIndex(c) + 1; - U32 const pos = rankPosition[r].curr++; - assert(pos < maxSymbolValue1); + U32 const r = BIT_highbit32(c+1) + 1; + U32 pos = rank[r].current++; + while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) { + huffNode[pos] = huffNode[pos-1]; + pos--; + } huffNode[pos].count = c; huffNode[pos].byte = (BYTE)n; } - - /* Sort each bucket. */ - for (n = RANK_POSITION_DISTINCT_COUNT_CUTOFF; n < RANK_POSITION_TABLE_SIZE - 1; ++n) { - int const bucketSize = rankPosition[n].curr - rankPosition[n].base; - U32 const bucketStartIdx = rankPosition[n].base; - if (bucketSize > 1) { - assert(bucketStartIdx < maxSymbolValue1); - HUF_simpleQuickSort(huffNode + bucketStartIdx, 0, bucketSize-1); - } - } - - assert(HUF_isSorted(huffNode, maxSymbolValue1)); } /** HUF_buildCTable_wksp() : * Same as HUF_buildCTable(), but using externally allocated scratch buffer. - * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as sizeof(HUF_buildCTable_wksp_tables). + * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of HUF_CTABLE_WORKSPACE_SIZE_U32 unsigned. */ #define STARTNODE (HUF_SYMBOLVALUE_MAX+1) - -/* HUF_buildTree(): - * Takes the huffNode array sorted by HUF_sort() and builds an unlimited-depth Huffman tree. - * - * @param huffNode The array sorted by HUF_sort(). Builds the Huffman tree in this array. - * @param maxSymbolValue The maximum symbol value. - * @return The smallest node in the Huffman tree (by count). - */ -static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue) +typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32]; +size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) { - nodeElt* const huffNode0 = huffNode - 1; - int nonNullRank; + nodeElt* const huffNode0 = (nodeElt*)workSpace; + nodeElt* const huffNode = huffNode0+1; + U32 n, nonNullRank; int lowS, lowN; - int nodeNb = STARTNODE; - int n, nodeRoot; - DEBUGLOG(5, "HUF_buildTree (alphabet size = %u)", maxSymbolValue + 1); + U16 nodeNb = STARTNODE; + U32 nodeRoot; + + /* safety checks */ + if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ + if (wkspSize < sizeof(huffNodeTable)) return ERROR(workSpace_tooSmall); + if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; + if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); + memset(huffNode0, 0, sizeof(huffNodeTable)); + + /* sort, decreasing order */ + HUF_sort(huffNode, count, maxSymbolValue); + /* init for parents */ - nonNullRank = (int)maxSymbolValue; + nonNullRank = maxSymbolValue; while(huffNode[nonNullRank].count == 0) nonNullRank--; lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb; huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count; - huffNode[lowS].parent = huffNode[lowS-1].parent = (U16)nodeNb; + huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb; nodeNb++; lowS-=2; for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30); huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */ /* create parents */ while (nodeNb <= nodeRoot) { - int const n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; - int const n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; + U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; + U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count; - huffNode[n1].parent = huffNode[n2].parent = (U16)nodeNb; + huffNode[n1].parent = huffNode[n2].parent = nodeNb; nodeNb++; } @@ -688,406 +392,126 @@ static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue) for (n=0; n<=nonNullRank; n++) huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1; - DEBUGLOG(6, "Initial distribution of bits completed (%zu sorted symbols)", showHNodeBits(huffNode, maxSymbolValue+1)); + /* enforce maxTableLog */ + maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits); - return nonNullRank; -} + /* fill result into tree (val, nbBits) */ + { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; + U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; + if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ + for (n=0; n<=nonNullRank; n++) + nbPerRank[huffNode[n].nbBits]++; + /* determine stating value per rank */ + { U16 min = 0; + for (n=maxNbBits; n>0; n--) { + valPerRank[n] = min; /* get starting value within each rank */ + min += nbPerRank[n]; + min >>= 1; + } } + for (n=0; n<=maxSymbolValue; n++) + tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */ + for (n=0; n<=maxSymbolValue; n++) + tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */ + } -/** - * HUF_buildCTableFromTree(): - * Build the CTable given the Huffman tree in huffNode. - * - * @param[out] CTable The output Huffman CTable. - * @param huffNode The Huffman tree. - * @param nonNullRank The last and smallest node in the Huffman tree. - * @param maxSymbolValue The maximum symbol value. - * @param maxNbBits The exact maximum number of bits used in the Huffman tree. - */ -static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, int nonNullRank, U32 maxSymbolValue, U32 maxNbBits) -{ - HUF_CElt* const ct = CTable + 1; - /* fill result into ctable (val, nbBits) */ - int n; - U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; - U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; - int const alphabetSize = (int)(maxSymbolValue + 1); - for (n=0; n<=nonNullRank; n++) - nbPerRank[huffNode[n].nbBits]++; - /* determine starting value per rank */ - { U16 min = 0; - for (n=(int)maxNbBits; n>0; n--) { - valPerRank[n] = min; /* get starting value within each rank */ - min += nbPerRank[n]; - min >>= 1; - } } - for (n=0; nhuffNodeTbl; - nodeElt* const huffNode = huffNode0+1; - int nonNullRank; - - HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE == sizeof(HUF_buildCTable_wksp_tables)); - - DEBUGLOG(5, "HUF_buildCTable_wksp (alphabet size = %u)", maxSymbolValue+1); - - /* safety checks */ - if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) - return ERROR(workSpace_tooSmall); - if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; - if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) - return ERROR(maxSymbolValue_tooLarge); - ZSTD_memset(huffNode0, 0, sizeof(huffNodeTable)); - - /* sort, decreasing order */ - HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); - DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); - - /* build tree */ - nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); - - /* determine and enforce maxTableLog */ - maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); - if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ - - HUF_buildCTableFromTree(CTable, huffNode, nonNullRank, maxSymbolValue, maxNbBits); - - return maxNbBits; + huffNodeTable nodeTable; + return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, nodeTable, sizeof(nodeTable)); } -size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) +static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { - HUF_CElt const* ct = CTable + 1; size_t nbBits = 0; int s; for (s = 0; s <= (int)maxSymbolValue; ++s) { - nbBits += HUF_getNbBits(ct[s]) * count[s]; + nbBits += CTable[s].nbBits * count[s]; } return nbBits >> 3; } -int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { - HUF_CElt const* ct = CTable + 1; +static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { int bad = 0; int s; for (s = 0; s <= (int)maxSymbolValue; ++s) { - bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0); + bad |= (count[s] != 0) & (CTable[s].nbBits == 0); } return !bad; } size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); } -/** HUF_CStream_t: - * Huffman uses its own BIT_CStream_t implementation. - * There are three major differences from BIT_CStream_t: - * 1. HUF_addBits() takes a HUF_CElt (size_t) which is - * the pair (nbBits, value) in the format: - * format: - * - Bits [0, 4) = nbBits - * - Bits [4, 64 - nbBits) = 0 - * - Bits [64 - nbBits, 64) = value - * 2. The bitContainer is built from the upper bits and - * right shifted. E.g. to add a new value of N bits - * you right shift the bitContainer by N, then or in - * the new value into the N upper bits. - * 3. The bitstream has two bit containers. You can add - * bits to the second container and merge them into - * the first container. - */ - -#define HUF_BITS_IN_CONTAINER (sizeof(size_t) * 8) - -typedef struct { - size_t bitContainer[2]; - size_t bitPos[2]; - - BYTE* startPtr; - BYTE* ptr; - BYTE* endPtr; -} HUF_CStream_t; - -/**! HUF_initCStream(): - * Initializes the bitstream. - * @returns 0 or an error code. - */ -static size_t HUF_initCStream(HUF_CStream_t* bitC, - void* startPtr, size_t dstCapacity) -{ - ZSTD_memset(bitC, 0, sizeof(*bitC)); - bitC->startPtr = (BYTE*)startPtr; - bitC->ptr = bitC->startPtr; - bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer[0]); - if (dstCapacity <= sizeof(bitC->bitContainer[0])) return ERROR(dstSize_tooSmall); - return 0; -} - -/*! HUF_addBits(): - * Adds the symbol stored in HUF_CElt elt to the bitstream. - * - * @param elt The element we're adding. This is a (nbBits, value) pair. - * See the HUF_CStream_t docs for the format. - * @param idx Insert into the bitstream at this idx. - * @param kFast This is a template parameter. If the bitstream is guaranteed - * to have at least 4 unused bits after this call it may be 1, - * otherwise it must be 0. HUF_addBits() is faster when fast is set. - */ -FORCE_INLINE_TEMPLATE void HUF_addBits(HUF_CStream_t* bitC, HUF_CElt elt, int idx, int kFast) -{ - assert(idx <= 1); - assert(HUF_getNbBits(elt) <= HUF_TABLELOG_ABSOLUTEMAX); - /* This is efficient on x86-64 with BMI2 because shrx - * only reads the low 6 bits of the register. The compiler - * knows this and elides the mask. When fast is set, - * every operation can use the same value loaded from elt. - */ - bitC->bitContainer[idx] >>= HUF_getNbBits(elt); - bitC->bitContainer[idx] |= kFast ? HUF_getValueFast(elt) : HUF_getValue(elt); - /* We only read the low 8 bits of bitC->bitPos[idx] so it - * doesn't matter that the high bits have noise from the value. - */ - bitC->bitPos[idx] += HUF_getNbBitsFast(elt); - assert((bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); - /* The last 4-bits of elt are dirty if fast is set, - * so we must not be overwriting bits that have already been - * inserted into the bit container. - */ -#if DEBUGLEVEL >= 1 - { - size_t const nbBits = HUF_getNbBits(elt); - size_t const dirtyBits = nbBits == 0 ? 0 : ZSTD_highbit32((U32)nbBits) + 1; - (void)dirtyBits; - /* Middle bits are 0. */ - assert(((elt >> dirtyBits) << (dirtyBits + nbBits)) == 0); - /* We didn't overwrite any bits in the bit container. */ - assert(!kFast || (bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); - (void)dirtyBits; - } -#endif -} - -FORCE_INLINE_TEMPLATE void HUF_zeroIndex1(HUF_CStream_t* bitC) -{ - bitC->bitContainer[1] = 0; - bitC->bitPos[1] = 0; -} - -/*! HUF_mergeIndex1() : - * Merges the bit container @ index 1 into the bit container @ index 0 - * and zeros the bit container @ index 1. - */ -FORCE_INLINE_TEMPLATE void HUF_mergeIndex1(HUF_CStream_t* bitC) -{ - assert((bitC->bitPos[1] & 0xFF) < HUF_BITS_IN_CONTAINER); - bitC->bitContainer[0] >>= (bitC->bitPos[1] & 0xFF); - bitC->bitContainer[0] |= bitC->bitContainer[1]; - bitC->bitPos[0] += bitC->bitPos[1]; - assert((bitC->bitPos[0] & 0xFF) <= HUF_BITS_IN_CONTAINER); -} - -/*! HUF_flushBits() : -* Flushes the bits in the bit container @ index 0. -* -* @post bitPos will be < 8. -* @param kFast If kFast is set then we must know a-priori that -* the bit container will not overflow. -*/ -FORCE_INLINE_TEMPLATE void HUF_flushBits(HUF_CStream_t* bitC, int kFast) -{ - /* The upper bits of bitPos are noisy, so we must mask by 0xFF. */ - size_t const nbBits = bitC->bitPos[0] & 0xFF; - size_t const nbBytes = nbBits >> 3; - /* The top nbBits bits of bitContainer are the ones we need. */ - size_t const bitContainer = bitC->bitContainer[0] >> (HUF_BITS_IN_CONTAINER - nbBits); - /* Mask bitPos to account for the bytes we consumed. */ - bitC->bitPos[0] &= 7; - assert(nbBits > 0); - assert(nbBits <= sizeof(bitC->bitContainer[0]) * 8); - assert(bitC->ptr <= bitC->endPtr); - MEM_writeLEST(bitC->ptr, bitContainer); - bitC->ptr += nbBytes; - assert(!kFast || bitC->ptr <= bitC->endPtr); - if (!kFast && bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; - /* bitContainer doesn't need to be modified because the leftover - * bits are already the top bitPos bits. And we don't care about - * noise in the lower values. - */ -} - -/*! HUF_endMark() - * @returns The Huffman stream end mark: A 1-bit value = 1. - */ -static HUF_CElt HUF_endMark(void) -{ - HUF_CElt endMark; - HUF_setNbBits(&endMark, 1); - HUF_setValue(&endMark, 1); - return endMark; -} - -/*! HUF_closeCStream() : - * @return Size of CStream, in bytes, - * or 0 if it could not fit into dstBuffer */ -static size_t HUF_closeCStream(HUF_CStream_t* bitC) -{ - HUF_addBits(bitC, HUF_endMark(), /* idx */ 0, /* kFast */ 0); - HUF_flushBits(bitC, /* kFast */ 0); - { - size_t const nbBits = bitC->bitPos[0] & 0xFF; - if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ - return (size_t)(bitC->ptr - bitC->startPtr) + (nbBits > 0); - } -} - FORCE_INLINE_TEMPLATE void -HUF_encodeSymbol(HUF_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable, int idx, int fast) +HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable) { - HUF_addBits(bitCPtr, CTable[symbol], idx, fast); + BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits); } -FORCE_INLINE_TEMPLATE void -HUF_compress1X_usingCTable_internal_body_loop(HUF_CStream_t* bitC, - const BYTE* ip, size_t srcSize, - const HUF_CElt* ct, - int kUnroll, int kFastFlush, int kLastFast) -{ - /* Join to kUnroll */ - int n = (int)srcSize; - int rem = n % kUnroll; - if (rem > 0) { - for (; rem > 0; --rem) { - HUF_encodeSymbol(bitC, ip[--n], ct, 0, /* fast */ 0); - } - HUF_flushBits(bitC, kFastFlush); - } - assert(n % kUnroll == 0); +#define HUF_FLUSHBITS(s) BIT_flushBits(s) - /* Join to 2 * kUnroll */ - if (n % (2 * kUnroll)) { - int u; - for (u = 1; u < kUnroll; ++u) { - HUF_encodeSymbol(bitC, ip[n - u], ct, 0, 1); - } - HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, 0, kLastFast); - HUF_flushBits(bitC, kFastFlush); - n -= kUnroll; - } - assert(n % (2 * kUnroll) == 0); - - for (; n>0; n-= 2 * kUnroll) { - /* Encode kUnroll symbols into the bitstream @ index 0. */ - int u; - for (u = 1; u < kUnroll; ++u) { - HUF_encodeSymbol(bitC, ip[n - u], ct, /* idx */ 0, /* fast */ 1); - } - HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, /* idx */ 0, /* fast */ kLastFast); - HUF_flushBits(bitC, kFastFlush); - /* Encode kUnroll symbols into the bitstream @ index 1. - * This allows us to start filling the bit container - * without any data dependencies. - */ - HUF_zeroIndex1(bitC); - for (u = 1; u < kUnroll; ++u) { - HUF_encodeSymbol(bitC, ip[n - kUnroll - u], ct, /* idx */ 1, /* fast */ 1); - } - HUF_encodeSymbol(bitC, ip[n - kUnroll - kUnroll], ct, /* idx */ 1, /* fast */ kLastFast); - /* Merge bitstream @ index 1 into the bitstream @ index 0 */ - HUF_mergeIndex1(bitC); - HUF_flushBits(bitC, kFastFlush); - } - assert(n == 0); - -} - -/** - * Returns a tight upper bound on the output space needed by Huffman - * with 8 bytes buffer to handle over-writes. If the output is at least - * this large we don't need to do bounds checks during Huffman encoding. - */ -static size_t HUF_tightCompressBound(size_t srcSize, size_t tableLog) -{ - return ((srcSize * tableLog) >> 3) + 8; -} +#define HUF_FLUSHBITS_1(stream) \ + if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream) +#define HUF_FLUSHBITS_2(stream) \ + if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream) FORCE_INLINE_TEMPLATE size_t HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - U32 const tableLog = (U32)CTable[0]; - HUF_CElt const* ct = CTable + 1; const BYTE* ip = (const BYTE*) src; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; BYTE* op = ostart; - HUF_CStream_t bitC; + size_t n; + BIT_CStream_t bitC; /* init */ if (dstSize < 8) return 0; /* not enough space to compress */ - { size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op)); + { size_t const initErr = BIT_initCStream(&bitC, op, oend-op); if (HUF_isError(initErr)) return 0; } - if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11) - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ MEM_32bits() ? 2 : 4, /* kFast */ 0, /* kLastFast */ 0); - else { - if (MEM_32bits()) { - switch (tableLog) { - case 11: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 10: ZSTD_FALLTHROUGH; - case 9: ZSTD_FALLTHROUGH; - case 8: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - case 7: ZSTD_FALLTHROUGH; - default: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 3, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - } - } else { - switch (tableLog) { - case 11: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 10: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - case 9: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 6, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 8: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 7, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 7: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 8, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 6: ZSTD_FALLTHROUGH; - default: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 9, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - } - } + n = srcSize & ~3; /* join to mod 4 */ + switch (srcSize & 3) + { + case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable); + HUF_FLUSHBITS_2(&bitC); + /* fall-through */ + case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable); + HUF_FLUSHBITS_1(&bitC); + /* fall-through */ + case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable); + HUF_FLUSHBITS(&bitC); + /* fall-through */ + case 0 : /* fall-through */ + default: break; + } + + for (; n>0; n-=4) { /* note : n&3==0 at this stage */ + HUF_encodeSymbol(&bitC, ip[n- 1], CTable); + HUF_FLUSHBITS_1(&bitC); + HUF_encodeSymbol(&bitC, ip[n- 2], CTable); + HUF_FLUSHBITS_2(&bitC); + HUF_encodeSymbol(&bitC, ip[n- 3], CTable); + HUF_FLUSHBITS_1(&bitC); + HUF_encodeSymbol(&bitC, ip[n- 4], CTable); + HUF_FLUSHBITS(&bitC); } - assert(bitC.ptr <= bitC.endPtr); - return HUF_closeCStream(&bitC); + return BIT_closeCStream(&bitC); } #if DYNAMIC_BMI2 -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) @@ -1106,9 +530,9 @@ HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize, static size_t HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, const int flags) + const HUF_CElt* CTable, const int bmi2) { - if (flags & HUF_flags_bmi2) { + if (bmi2) { return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable); } return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable); @@ -1119,23 +543,24 @@ HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, static size_t HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, const int flags) + const HUF_CElt* CTable, const int bmi2) { - (void)flags; + (void)bmi2; return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable); } #endif -size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags) +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags); + return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); } + static size_t HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, int flags) + const HUF_CElt* CTable, int bmi2) { size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */ const BYTE* ip = (const BYTE*) src; @@ -1148,43 +573,41 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, if (srcSize < 12) return 0; /* no saving possible : too small input */ op += 6; /* jumpTable */ - assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) ); + if (cSize==0) return 0; + assert(cSize <= 65535); MEM_writeLE16(ostart, (U16)cSize); op += cSize; } ip += segmentSize; - assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) ); + if (cSize==0) return 0; + assert(cSize <= 65535); MEM_writeLE16(ostart+2, (U16)cSize); op += cSize; } ip += segmentSize; - assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) ); + if (cSize==0) return 0; + assert(cSize <= 65535); MEM_writeLE16(ostart+4, (U16)cSize); op += cSize; } ip += segmentSize; - assert(op <= oend); - assert(ip <= iend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, iend-ip, CTable, bmi2) ); + if (cSize==0) return 0; op += cSize; } - return (size_t)(op-ostart); + return op-ostart; } -size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags) +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags); + return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); } typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; @@ -1192,127 +615,44 @@ typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; static size_t HUF_compressCTable_internal( BYTE* const ostart, BYTE* op, BYTE* const oend, const void* src, size_t srcSize, - HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int flags) + HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2) { size_t const cSize = (nbStreams==HUF_singleStream) ? - HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags) : - HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags); + HUF_compress1X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2) : + HUF_compress4X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2); if (HUF_isError(cSize)) { return cSize; } if (cSize==0) { return 0; } /* uncompressible */ op += cSize; /* check compressibility */ - assert(op >= ostart); if ((size_t)(op-ostart) >= srcSize-1) { return 0; } - return (size_t)(op-ostart); + return op-ostart; } typedef struct { unsigned count[HUF_SYMBOLVALUE_MAX + 1]; - HUF_CElt CTable[HUF_CTABLE_SIZE_ST(HUF_SYMBOLVALUE_MAX)]; - union { - HUF_buildCTable_wksp_tables buildCTable_wksp; - HUF_WriteCTableWksp writeCTable_wksp; - U32 hist_wksp[HIST_WKSP_SIZE_U32]; - } wksps; + HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1]; + huffNodeTable nodeTable; } HUF_compress_tables_t; -#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096 -#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */ - -unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue) -{ - unsigned cardinality = 0; - unsigned i; - - for (i = 0; i < maxSymbolValue + 1; i++) { - if (count[i] != 0) cardinality += 1; - } - - return cardinality; -} - -unsigned HUF_minTableLog(unsigned symbolCardinality) -{ - U32 minBitsSymbols = ZSTD_highbit32(symbolCardinality) + 1; - return minBitsSymbols; -} - -unsigned HUF_optimalTableLog( - unsigned maxTableLog, - size_t srcSize, - unsigned maxSymbolValue, - void* workSpace, size_t wkspSize, - HUF_CElt* table, - const unsigned* count, - int flags) -{ - assert(srcSize > 1); /* Not supported, RLE should be used instead */ - assert(wkspSize >= sizeof(HUF_buildCTable_wksp_tables)); - - if (!(flags & HUF_flags_optimalDepth)) { - /* cheap evaluation, based on FSE */ - return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); - } - - { BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp); - size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp); - size_t maxBits, hSize, newSize; - const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue); - const unsigned minTableLog = HUF_minTableLog(symbolCardinality); - size_t optSize = ((size_t) ~0) - 1; - unsigned optLog = maxTableLog, optLogGuess; - - DEBUGLOG(6, "HUF_optimalTableLog: probing huf depth (srcSize=%zu)", srcSize); - - /* Search until size increases */ - for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) { - DEBUGLOG(7, "checking for huffLog=%u", optLogGuess); - maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize); - if (ERR_isError(maxBits)) continue; - - if (maxBits < optLogGuess && optLogGuess > minTableLog) break; - - hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize); - - if (ERR_isError(hSize)) continue; - - newSize = HUF_estimateCompressedSize(table, count, maxSymbolValue) + hSize; - - if (newSize > optSize + 1) { - break; - } - - if (newSize < optSize) { - optSize = newSize; - optLog = optLogGuess; - } - } - assert(optLog <= HUF_TABLELOG_MAX); - return optLog; - } -} - /* HUF_compress_internal() : - * `workSpace_align4` must be aligned on 4-bytes boundaries, - * and occupies the same space as a table of HUF_WORKSPACE_SIZE_U64 unsigned */ + * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ static size_t HUF_compress_internal (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, HUF_nbStreams_e nbStreams, void* workSpace, size_t wkspSize, - HUF_CElt* oldHufTable, HUF_repeat* repeat, int flags) + HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat, + const int bmi2) { - HUF_compress_tables_t* const table = (HUF_compress_tables_t*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(size_t)); + HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; BYTE* op = ostart; - DEBUGLOG(5, "HUF_compress_internal (srcSize=%zu)", srcSize); - HUF_STATIC_ASSERT(sizeof(*table) + HUF_WORKSPACE_MAX_ALIGNMENT <= HUF_WORKSPACE_SIZE); - /* checks & inits */ - if (wkspSize < sizeof(*table)) return ERROR(workSpace_tooSmall); + if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ + if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall); if (!srcSize) return 0; /* Uncompressed */ if (!dstSize) return 0; /* cannot fit anything within dst budget */ if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */ @@ -1322,34 +662,17 @@ HUF_compress_internal (void* dst, size_t dstSize, if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT; /* Heuristic : If old table is valid, use it for small inputs */ - if ((flags & HUF_flags_preferRepeat) && repeat && *repeat == HUF_repeat_valid) { + if (preferRepeat && repeat && *repeat == HUF_repeat_valid) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, flags); - } - - /* If uncompressible data is suspected, do a smaller sampling first */ - DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2); - if ((flags & HUF_flags_suspectUncompressible) && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) { - size_t largestTotal = 0; - DEBUGLOG(5, "input suspected incompressible : sampling to check"); - { unsigned maxSymbolValueBegin = maxSymbolValue; - CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); - largestTotal += largestBegin; - } - { unsigned maxSymbolValueEnd = maxSymbolValue; - CHECK_V_F(largestEnd, HIST_count_simple (table->count, &maxSymbolValueEnd, (const BYTE*)src + srcSize - SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); - largestTotal += largestEnd; - } - if (largestTotal <= ((2 * SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) >> 7)+4) return 0; /* heuristic : probably not compressible enough */ + nbStreams, oldHufTable, bmi2); } /* Scan input and build symbol stats */ - { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->wksps.hist_wksp, sizeof(table->wksps.hist_wksp)) ); + { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) ); if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */ } - DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); /* Check validity of previous table */ if ( repeat @@ -1358,31 +681,26 @@ HUF_compress_internal (void* dst, size_t dstSize, *repeat = HUF_repeat_none; } /* Heuristic : use existing table for small inputs */ - if ((flags & HUF_flags_preferRepeat) && repeat && *repeat != HUF_repeat_none) { + if (preferRepeat && repeat && *repeat != HUF_repeat_none) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, flags); + nbStreams, oldHufTable, bmi2); } /* Build Huffman Tree */ - huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, &table->wksps, sizeof(table->wksps), table->CTable, table->count, flags); + huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count, maxSymbolValue, huffLog, - &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp)); + table->nodeTable, sizeof(table->nodeTable)); CHECK_F(maxBits); huffLog = (U32)maxBits; - DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); - } - /* Zero unused symbols in CTable, so we can check it for validity */ - { - size_t const ctableSize = HUF_CTABLE_SIZE_ST(maxSymbolValue); - size_t const unusedSize = sizeof(table->CTable) - ctableSize * sizeof(HUF_CElt); - ZSTD_memset(table->CTable + ctableSize, 0, unusedSize); + /* Zero unused symbols in CTable, so we can check it for validity */ + memset(table->CTable + (maxSymbolValue + 1), 0, + sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt))); } /* Write table description header */ - { CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog, - &table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) ); + { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) ); /* Check if using previous huffman table is beneficial */ if (repeat && *repeat != HUF_repeat_none) { size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue); @@ -1390,7 +708,7 @@ HUF_compress_internal (void* dst, size_t dstSize, if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, flags); + nbStreams, oldHufTable, bmi2); } } /* Use the new huffman table */ @@ -1398,41 +716,83 @@ HUF_compress_internal (void* dst, size_t dstSize, op += hSize; if (repeat) { *repeat = HUF_repeat_none; } if (oldHufTable) - ZSTD_memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ + memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ } return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, table->CTable, flags); + nbStreams, table->CTable, bmi2); +} + + +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog, + void* workSpace, size_t wkspSize) +{ + return HUF_compress_internal(dst, dstSize, src, srcSize, + maxSymbolValue, huffLog, HUF_singleStream, + workSpace, wkspSize, + NULL, NULL, 0, 0 /*bmi2*/); } size_t HUF_compress1X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int flags) + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) { - DEBUGLOG(5, "HUF_compress1X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_singleStream, workSpace, wkspSize, hufTable, - repeat, flags); + repeat, preferRepeat, bmi2); +} + +size_t HUF_compress1X (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) +{ + unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; + return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); +} + +/* HUF_compress4X_repeat(): + * compress input using 4 streams. + * provide workspace to generate compression tables */ +size_t HUF_compress4X_wksp (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog, + void* workSpace, size_t wkspSize) +{ + return HUF_compress_internal(dst, dstSize, src, srcSize, + maxSymbolValue, huffLog, HUF_fourStreams, + workSpace, wkspSize, + NULL, NULL, 0, 0 /*bmi2*/); } /* HUF_compress4X_repeat(): * compress input using 4 streams. - * consider skipping quickly * re-use an existing huffman compression table */ size_t HUF_compress4X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int flags) + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) { - DEBUGLOG(5, "HUF_compress4X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, - hufTable, repeat, flags); + hufTable, repeat, preferRepeat, bmi2); +} + +size_t HUF_compress2 (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) +{ + unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; + return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); } -#endif /* USE_EXTERNAL_ZSTD */ +size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize) +{ + return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT); +} diff --git a/vendor/github.com/DataDog/zstd/huf_decompress.c b/vendor/github.com/DataDog/zstd/huf_decompress.c index da4d1845..bb2d0a96 100644 --- a/vendor/github.com/DataDog/zstd/huf_decompress.c +++ b/vendor/github.com/DataDog/zstd/huf_decompress.c @@ -1,35 +1,47 @@ -#ifndef USE_EXTERNAL_ZSTD /* ****************************************************************** - * huff0 huffman decoder, - * part of Finite State Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + huff0 huffman decoder, + part of Finite State Entropy library + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://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 : + - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy ****************************************************************** */ /* ************************************************************** * Dependencies ****************************************************************/ -#include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include /* memcpy, memset */ #include "compiler.h" #include "bitstream.h" /* BIT_* */ #include "fse.h" /* to compress headers */ +#define HUF_STATIC_LINKING_ONLY #include "huf.h" #include "error_private.h" -#include "zstd_internal.h" -#include "bits.h" /* ZSTD_highbit32, ZSTD_countTrailingZeros64 */ - -/* ************************************************************** -* Constants -****************************************************************/ - -#define HUF_DECODER_FAST_TABLELOG 11 /* ************************************************************** * Macros @@ -44,33 +56,14 @@ #error "Cannot force the use of the X1 and X2 decoders at the same time!" #endif -/* When DYNAMIC_BMI2 is enabled, fast decoders are only called when bmi2 is - * supported at runtime, so we can add the BMI2 target attribute. - * When it is disabled, we will still get BMI2 if it is enabled statically. - */ -#if DYNAMIC_BMI2 -# define HUF_FAST_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE -#else -# define HUF_FAST_BMI2_ATTRS -#endif - -#ifdef __cplusplus -# define HUF_EXTERN_C extern "C" -#else -# define HUF_EXTERN_C -#endif -#define HUF_ASM_DECL HUF_EXTERN_C - -#if DYNAMIC_BMI2 -# define HUF_NEED_BMI2_FUNCTION 1 -#else -# define HUF_NEED_BMI2_FUNCTION 0 -#endif /* ************************************************************** * Error Management ****************************************************************/ #define HUF_isError ERR_isError +#ifndef CHECK_F +#define CHECK_F(f) { size_t const err_ = (f); if (HUF_isError(err_)) return err_; } +#endif /* ************************************************************** @@ -83,11 +76,6 @@ /* ************************************************************** * BMI2 Variant Wrappers ****************************************************************/ -typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, - const void *cSrc, - size_t cSrcSize, - const HUF_DTable *DTable); - #if DYNAMIC_BMI2 #define HUF_DGEN(fn) \ @@ -100,7 +88,7 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ \ - static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ + static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \ void* dst, size_t dstSize, \ const void* cSrc, size_t cSrcSize, \ const HUF_DTable* DTable) \ @@ -109,9 +97,9 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, } \ \ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int flags) \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ { \ - if (flags & HUF_flags_bmi2) { \ + if (bmi2) { \ return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ @@ -121,9 +109,9 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, #define HUF_DGEN(fn) \ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int flags) \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ { \ - (void)flags; \ + (void)bmi2; \ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } @@ -138,359 +126,82 @@ typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) { DTableDesc dtd; - ZSTD_memcpy(&dtd, table, sizeof(dtd)); + memcpy(&dtd, table, sizeof(dtd)); return dtd; } -static size_t HUF_initFastDStream(BYTE const* ip) { - BYTE const lastByte = ip[7]; - size_t const bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; - size_t const value = MEM_readLEST(ip) | 1; - assert(bitsConsumed <= 8); - assert(sizeof(size_t) == 8); - return value << bitsConsumed; -} - - -/** - * The input/output arguments to the Huffman fast decoding loop: - * - * ip [in/out] - The input pointers, must be updated to reflect what is consumed. - * op [in/out] - The output pointers, must be updated to reflect what is written. - * bits [in/out] - The bitstream containers, must be updated to reflect the current state. - * dt [in] - The decoding table. - * ilimit [in] - The input limit, stop when any input pointer is below ilimit. - * oend [in] - The end of the output stream. op[3] must not cross oend. - * iend [in] - The end of each input stream. ip[i] may cross iend[i], - * as long as it is above ilimit, but that indicates corruption. - */ -typedef struct { - BYTE const* ip[4]; - BYTE* op[4]; - U64 bits[4]; - void const* dt; - BYTE const* ilimit; - BYTE* oend; - BYTE const* iend[4]; -} HUF_DecompressFastArgs; - -typedef void (*HUF_DecompressFastLoopFn)(HUF_DecompressFastArgs*); - -/** - * Initializes args for the fast decoding loop. - * @returns 1 on success - * 0 if the fallback implementation should be used. - * Or an error code on failure. - */ -static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) -{ - void const* dt = DTable + 1; - U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; - - const BYTE* const ilimit = (const BYTE*)src + 6 + 8; - - BYTE* const oend = (BYTE*)dst + dstSize; - - /* The fast decoding loop assumes 64-bit little-endian. - * This condition is false on x32. - */ - if (!MEM_isLittleEndian() || MEM_32bits()) - return 0; - - /* strict minimum : jump table + 1 byte per stream */ - if (srcSize < 10) - return ERROR(corruption_detected); - - /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. - * If table log is not correct at this point, fallback to the old decoder. - * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. - */ - if (dtLog != HUF_DECODER_FAST_TABLELOG) - return 0; - - /* Read the jump table. */ - { - const BYTE* const istart = (const BYTE*)src; - size_t const length1 = MEM_readLE16(istart); - size_t const length2 = MEM_readLE16(istart+2); - size_t const length3 = MEM_readLE16(istart+4); - size_t const length4 = srcSize - (length1 + length2 + length3 + 6); - args->iend[0] = istart + 6; /* jumpTable */ - args->iend[1] = args->iend[0] + length1; - args->iend[2] = args->iend[1] + length2; - args->iend[3] = args->iend[2] + length3; - - /* HUF_initFastDStream() requires this, and this small of an input - * won't benefit from the ASM loop anyways. - * length1 must be >= 16 so that ip[0] >= ilimit before the loop - * starts. - */ - if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8) - return 0; - if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ - } - /* ip[] contains the position that is currently loaded into bits[]. */ - args->ip[0] = args->iend[1] - sizeof(U64); - args->ip[1] = args->iend[2] - sizeof(U64); - args->ip[2] = args->iend[3] - sizeof(U64); - args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); - - /* op[] contains the output pointers. */ - args->op[0] = (BYTE*)dst; - args->op[1] = args->op[0] + (dstSize+3)/4; - args->op[2] = args->op[1] + (dstSize+3)/4; - args->op[3] = args->op[2] + (dstSize+3)/4; - - /* No point to call the ASM loop for tiny outputs. */ - if (args->op[3] >= oend) - return 0; - - /* bits[] is the bit container. - * It is read from the MSB down to the LSB. - * It is shifted left as it is read, and zeros are - * shifted in. After the lowest valid bit a 1 is - * set, so that CountTrailingZeros(bits[]) can be used - * to count how many bits we've consumed. - */ - args->bits[0] = HUF_initFastDStream(args->ip[0]); - args->bits[1] = HUF_initFastDStream(args->ip[1]); - args->bits[2] = HUF_initFastDStream(args->ip[2]); - args->bits[3] = HUF_initFastDStream(args->ip[3]); - - /* If ip[] >= ilimit, it is guaranteed to be safe to - * reload bits[]. It may be beyond its section, but is - * guaranteed to be valid (>= istart). - */ - args->ilimit = ilimit; - - args->oend = oend; - args->dt = dt; - - return 1; -} - -static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArgs const* args, int stream, BYTE* segmentEnd) -{ - /* Validate that we haven't overwritten. */ - if (args->op[stream] > segmentEnd) - return ERROR(corruption_detected); - /* Validate that we haven't read beyond iend[]. - * Note that ip[] may be < iend[] because the MSB is - * the next bit to read, and we may have consumed 100% - * of the stream, so down to iend[i] - 8 is valid. - */ - if (args->ip[stream] < args->iend[stream] - 8) - return ERROR(corruption_detected); - - /* Construct the BIT_DStream_t. */ - assert(sizeof(size_t) == 8); - bit->bitContainer = MEM_readLEST(args->ip[stream]); - bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]); - bit->start = (const char*)args->iend[0]; - bit->limitPtr = bit->start + sizeof(size_t); - bit->ptr = (const char*)args->ip[stream]; - - return 0; -} - #ifndef HUF_FORCE_DECOMPRESS_X2 /*-***************************/ /* single-symbol decoding */ /*-***************************/ -typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ +typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */ -/** - * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at - * a time. - */ -static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { - U64 D4; - if (MEM_isLittleEndian()) { - D4 = (U64)((symbol << 8) + nbBits); - } else { - D4 = (U64)(symbol + (nbBits << 8)); - } - assert(D4 < (1U << 16)); - D4 *= 0x0001000100010001ULL; - return D4; -} - -/** - * Increase the tableLog to targetTableLog and rescales the stats. - * If tableLog > targetTableLog this is a no-op. - * @returns New tableLog - */ -static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) -{ - if (tableLog > targetTableLog) - return tableLog; - if (tableLog < targetTableLog) { - U32 const scale = targetTableLog - tableLog; - U32 s; - /* Increase the weight for all non-zero probability symbols by scale. */ - for (s = 0; s < nbSymbols; ++s) { - huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); - } - /* Update rankVal to reflect the new weights. - * All weights except 0 get moved to weight + scale. - * Weights [1, scale] are empty. - */ - for (s = targetTableLog; s > scale; --s) { - rankVal[s] = rankVal[s - scale]; - } - for (s = scale; s > 0; --s) { - rankVal[s] = 0; - } - } - return targetTableLog; -} - -typedef struct { - U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; - U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; - U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; - BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; - BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; -} HUF_ReadDTableX1_Workspace; - -size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags) +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) { U32 tableLog = 0; U32 nbSymbols = 0; size_t iSize; void* const dtPtr = DTable + 1; HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; - HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; - DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); - if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); + U32* rankVal; + BYTE* huffWeight; + size_t spaceUsed32 = 0; + + rankVal = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1; + huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; + + if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); - /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), flags); + iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUF_isError(iSize)) return iSize; - /* Table header */ { DTableDesc dtd = HUF_getDTableDesc(DTable); - U32 const maxTableLog = dtd.maxTableLog + 1; - U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); - tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ dtd.tableType = 0; dtd.tableLog = (BYTE)tableLog; - ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + memcpy(DTable, &dtd, sizeof(dtd)); } - /* Compute symbols and rankStart given rankVal: - * - * rankVal already contains the number of values of each weight. - * - * symbols contains the symbols ordered by weight. First are the rankVal[0] - * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. - * symbols[0] is filled (but unused) to avoid a branch. - * - * rankStart contains the offset where each rank belongs in the DTable. - * rankStart[0] is not filled because there are no entries in the table for - * weight 0. - */ - { int n; - U32 nextRankStart = 0; - int const unroll = 4; - int const nLimit = (int)nbSymbols - unroll + 1; - for (n=0; n<(int)tableLog+1; n++) { - U32 const curr = nextRankStart; - nextRankStart += wksp->rankVal[n]; - wksp->rankStart[n] = curr; - } - for (n=0; n < nLimit; n += unroll) { - int u; - for (u=0; u < unroll; ++u) { - size_t const w = wksp->huffWeight[n+u]; - wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); - } - } - for (; n < (int)nbSymbols; ++n) { - size_t const w = wksp->huffWeight[n]; - wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; - } - } + /* Calculate starting value for each rank */ + { U32 n, nextRankStart = 0; + for (n=1; n> 1; + U32 u; + HUF_DEltX1 D; + D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w); + for (u = rankVal[w]; u < rankVal[w] + length; u++) + dt[u] = D; + rankVal[w] += length; + } } - /* fill DTable - * We fill all entries of each weight in order. - * That way length is a constant for each iteration of the outer loop. - * We can switch based on the length to a different inner loop which is - * optimized for that particular case. - */ - { U32 w; - int symbol = wksp->rankVal[0]; - int rankStart = 0; - for (w=1; wrankVal[w]; - int const length = (1 << w) >> 1; - int uStart = rankStart; - BYTE const nbBits = (BYTE)(tableLog + 1 - w); - int s; - int u; - switch (length) { - case 1: - for (s=0; ssymbols[symbol + s]; - D.nbBits = nbBits; - dt[uStart] = D; - uStart += 1; - } - break; - case 2: - for (s=0; ssymbols[symbol + s]; - D.nbBits = nbBits; - dt[uStart+0] = D; - dt[uStart+1] = D; - uStart += 2; - } - break; - case 4: - for (s=0; ssymbols[symbol + s], nbBits); - MEM_write64(dt + uStart, D4); - uStart += 4; - } - break; - case 8: - for (s=0; ssymbols[symbol + s], nbBits); - MEM_write64(dt + uStart, D4); - MEM_write64(dt + uStart + 4, D4); - uStart += 8; - } - break; - default: - for (s=0; ssymbols[symbol + s], nbBits); - for (u=0; u < length; u += 16) { - MEM_write64(dt + uStart + u + 0, D4); - MEM_write64(dt + uStart + u + 4, D4); - MEM_write64(dt + uStart + u + 8, D4); - MEM_write64(dt + uStart + u + 12, D4); - } - assert(u == length); - uStart += length; - } - break; - } - symbol += symbolCount; - rankStart += symbolCount * length; - } - } return iSize; } +size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX1_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + FORCE_INLINE_TEMPLATE BYTE HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog) { @@ -517,15 +228,11 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons BYTE* const pStart = p; /* up to 4 symbols at a time */ - if ((pEnd - p) > 3) { - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_1(p, bitDPtr); - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_0(p, bitDPtr); - } - } else { - BIT_reloadDStream(bitDPtr); + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); } /* [0-3] symbols remaining */ @@ -537,7 +244,7 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons while (p < pEnd) HUF_DECODE_SYMBOLX1_0(p, bitDPtr); - return (size_t)(pEnd-pStart); + return pEnd-pStart; } FORCE_INLINE_TEMPLATE size_t @@ -563,10 +270,6 @@ HUF_decompress1X1_usingDTable_internal_body( return dstSize; } -/* HUF_decompress4X1_usingDTable_internal_body(): - * Conditions : - * @dstSize >= 6 - */ FORCE_INLINE_TEMPLATE size_t HUF_decompress4X1_usingDTable_internal_body( void* dst, size_t dstSize, @@ -579,7 +282,6 @@ HUF_decompress4X1_usingDTable_internal_body( { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; BYTE* const oend = ostart + dstSize; - BYTE* const olimit = oend - 3; const void* const dtPtr = DTable + 1; const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; @@ -604,42 +306,39 @@ HUF_decompress4X1_usingDTable_internal_body( BYTE* op2 = opStart2; BYTE* op3 = opStart3; BYTE* op4 = opStart4; + U32 endSignal = BIT_DStream_unfinished; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; - U32 endSignal = 1; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ - if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ - if ((size_t)(oend - op4) >= sizeof(size_t)) { - for ( ; (endSignal) & (op4 < olimit) ; ) { - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_1(op1, &bitD1); - HUF_DECODE_SYMBOLX1_1(op2, &bitD2); - HUF_DECODE_SYMBOLX1_1(op3, &bitD3); - HUF_DECODE_SYMBOLX1_1(op4, &bitD4); - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_0(op1, &bitD1); - HUF_DECODE_SYMBOLX1_0(op2, &bitD2); - HUF_DECODE_SYMBOLX1_0(op3, &bitD3); - HUF_DECODE_SYMBOLX1_0(op4, &bitD4); - endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; - } + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + while ( (endSignal==BIT_DStream_unfinished) && (op4<(oend-3)) ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + BIT_reloadDStream(&bitD1); + BIT_reloadDStream(&bitD2); + BIT_reloadDStream(&bitD3); + BIT_reloadDStream(&bitD4); } /* check corruption */ @@ -665,230 +364,99 @@ HUF_decompress4X1_usingDTable_internal_body( } } -#if HUF_NEED_BMI2_FUNCTION -static BMI2_TARGET_ATTRIBUTE -size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); -} -#endif -static -size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); -} +typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, + const void *cSrc, + size_t cSrcSize, + const HUF_DTable *DTable); -#if ZSTD_ENABLE_ASM_X86_64_BMI2 +HUF_DGEN(HUF_decompress1X1_usingDTable_internal) +HUF_DGEN(HUF_decompress4X1_usingDTable_internal) -HUF_ASM_DECL void HUF_decompress4X1_usingDTable_internal_fast_asm_loop(HUF_DecompressFastArgs* args) ZSTDLIB_HIDDEN; -#endif -static HUF_FAST_BMI2_ATTRS -void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) +size_t HUF_decompress1X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) { - U64 bits[4]; - BYTE const* ip[4]; - BYTE* op[4]; - U16 const* const dtable = (U16 const*)args->dt; - BYTE* const oend = args->oend; - BYTE const* const ilimit = args->ilimit; - - /* Copy the arguments to local variables */ - ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); - ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); - ZSTD_memcpy(&op, &args->op, sizeof(op)); - - assert(MEM_isLittleEndian()); - assert(!MEM_32bits()); - - for (;;) { - BYTE* olimit; - int stream; - int symbol; - - /* Assert loop preconditions */ -#ifndef NDEBUG - for (stream = 0; stream < 4; ++stream) { - assert(op[stream] <= (stream == 3 ? oend : op[stream + 1])); - assert(ip[stream] >= ilimit); - } -#endif - /* Compute olimit */ - { - /* Each iteration produces 5 output symbols per stream */ - size_t const oiters = (size_t)(oend - op[3]) / 5; - /* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes - * per stream. - */ - size_t const iiters = (size_t)(ip[0] - ilimit) / 7; - /* We can safely run iters iterations before running bounds checks */ - size_t const iters = MIN(oiters, iiters); - size_t const symbols = iters * 5; - - /* We can simply check that op[3] < olimit, instead of checking all - * of our bounds, since we can't hit the other bounds until we've run - * iters iterations, which only happens when op[3] == olimit. - */ - olimit = op[3] + symbols; - - /* Exit fast decoding loop once we get close to the end. */ - if (op[3] + 20 > olimit) - break; - - /* Exit the decoding loop if any input pointer has crossed the - * previous one. This indicates corruption, and a precondition - * to our loop is that ip[i] >= ip[0]. - */ - for (stream = 1; stream < 4; ++stream) { - if (ip[stream] < ip[stream - 1]) - goto _out; - } - } - -#ifndef NDEBUG - for (stream = 1; stream < 4; ++stream) { - assert(ip[stream] >= ip[stream - 1]); - } -#endif - - do { - /* Decode 5 symbols in each of the 4 streams */ - for (symbol = 0; symbol < 5; ++symbol) { - for (stream = 0; stream < 4; ++stream) { - int const index = (int)(bits[stream] >> 53); - int const entry = (int)dtable[index]; - bits[stream] <<= (entry & 63); - op[stream][symbol] = (BYTE)((entry >> 8) & 0xFF); - } - } - /* Reload the bitstreams */ - for (stream = 0; stream < 4; ++stream) { - int const ctz = ZSTD_countTrailingZeros64(bits[stream]); - int const nbBits = ctz & 7; - int const nbBytes = ctz >> 3; - op[stream] += 5; - ip[stream] -= nbBytes; - bits[stream] = MEM_read64(ip[stream]) | 1; - bits[stream] <<= nbBits; - } - } while (op[3] < olimit); - } - -_out: - - /* Save the final values of each of the state variables back to args. */ - ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); - ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); - ZSTD_memcpy(&args->op, &op, sizeof(op)); + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -/** - * @returns @p dstSize on success (>= 6) - * 0 if the fallback implementation should be used - * An error if an error occurred - */ -static HUF_FAST_BMI2_ATTRS -size_t -HUF_decompress4X1_usingDTable_internal_fast( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable, - HUF_DecompressFastLoopFn loopFn) +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { - void const* dt = DTable + 1; - const BYTE* const iend = (const BYTE*)cSrc + 6; - BYTE* const oend = (BYTE*)dst + dstSize; - HUF_DecompressFastArgs args; - { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); - FORWARD_IF_ERROR(ret, "Failed to init fast loop args"); - if (ret == 0) - return 0; - } + const BYTE* ip = (const BYTE*) cSrc; - assert(args.ip[0] >= args.ilimit); - loopFn(&args); - - /* Our loop guarantees that ip[] >= ilimit and that we haven't - * overwritten any op[]. - */ - assert(args.ip[0] >= iend); - assert(args.ip[1] >= iend); - assert(args.ip[2] >= iend); - assert(args.ip[3] >= iend); - assert(args.op[3] <= oend); - (void)iend; - - /* finish bit streams one by one. */ - { size_t const segmentSize = (dstSize+3) / 4; - BYTE* segmentEnd = (BYTE*)dst; - int i; - for (i = 0; i < 4; ++i) { - BIT_DStream_t bit; - if (segmentSize <= (size_t)(oend - segmentEnd)) - segmentEnd += segmentSize; - else - segmentEnd = oend; - FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); - /* Decompress and validate that we've produced exactly the expected length. */ - args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); - if (args.op[i] != segmentEnd) return ERROR(corruption_detected); - } - } + size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; - /* decoded size */ - assert(dstSize != 0); - return dstSize; + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); } -HUF_DGEN(HUF_decompress1X1_usingDTable_internal) -static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable, int flags) +size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) { - HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X1_usingDTable_internal_default; - HUF_DecompressFastLoopFn loopFn = HUF_decompress4X1_usingDTable_internal_fast_c_loop; - -#if DYNAMIC_BMI2 - if (flags & HUF_flags_bmi2) { - fallbackFn = HUF_decompress4X1_usingDTable_internal_bmi2; -# if ZSTD_ENABLE_ASM_X86_64_BMI2 - if (!(flags & HUF_flags_disableAsm)) { - loopFn = HUF_decompress4X1_usingDTable_internal_fast_asm_loop; - } -# endif - } else { - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); - } -#endif + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} -#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) - if (!(flags & HUF_flags_disableAsm)) { - loopFn = HUF_decompress4X1_usingDTable_internal_fast_asm_loop; - } -#endif +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); +} - if (!(flags & HUF_flags_disableFast)) { - size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); - if (ret != 0) - return ret; - } - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); +size_t HUF_decompress4X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -static size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, +static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize, int bmi2) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); + size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} + +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0); +} + + +size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); } #endif /* HUF_FORCE_DECOMPRESS_X2 */ @@ -901,322 +469,209 @@ static size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t ds /* *************************/ typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ -typedef struct { BYTE symbol; } sortedSymbol_t; +typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; -/** - * Constructs a HUF_DEltX2 in a U32. - */ -static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) -{ - U32 seq; - DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); - DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); - DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); - DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); - if (MEM_isLittleEndian()) { - seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); - return seq + (nbBits << 16) + ((U32)level << 24); - } else { - seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); - return (seq << 16) + (nbBits << 8) + (U32)level; - } -} - -/** - * Constructs a HUF_DEltX2. - */ -static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) -{ - HUF_DEltX2 DElt; - U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); - DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); - ZSTD_memcpy(&DElt, &val, sizeof(val)); - return DElt; -} - -/** - * Constructs 2 HUF_DEltX2s and packs them into a U64. - */ -static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) -{ - U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); - return (U64)DElt + ((U64)DElt << 32); -} - -/** - * Fills the DTable rank with all the symbols from [begin, end) that are each - * nbBits long. - * - * @param DTableRank The start of the rank in the DTable. - * @param begin The first symbol to fill (inclusive). - * @param end The last symbol to fill (exclusive). - * @param nbBits Each symbol is nbBits long. - * @param tableLog The table log. - * @param baseSeq If level == 1 { 0 } else { the first level symbol } - * @param level The level in the table. Must be 1 or 2. - */ -static void HUF_fillDTableX2ForWeight( - HUF_DEltX2* DTableRank, - sortedSymbol_t const* begin, sortedSymbol_t const* end, - U32 nbBits, U32 tableLog, - U16 baseSeq, int const level) -{ - U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); - const sortedSymbol_t* ptr; - assert(level >= 1 && level <= 2); - switch (length) { - case 1: - for (ptr = begin; ptr != end; ++ptr) { - HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); - *DTableRank++ = DElt; - } - break; - case 2: - for (ptr = begin; ptr != end; ++ptr) { - HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); - DTableRank[0] = DElt; - DTableRank[1] = DElt; - DTableRank += 2; - } - break; - case 4: - for (ptr = begin; ptr != end; ++ptr) { - U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); - ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); - DTableRank += 4; - } - break; - case 8: - for (ptr = begin; ptr != end; ++ptr) { - U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); - ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); - DTableRank += 8; - } - break; - default: - for (ptr = begin; ptr != end; ++ptr) { - U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); - HUF_DEltX2* const DTableRankEnd = DTableRank + length; - for (; DTableRank != DTableRankEnd; DTableRank += 8) { - ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); - } - } - break; - } -} /* HUF_fillDTableX2Level2() : * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ -static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, - const U32* rankVal, const int minWeight, const int maxWeight1, - const sortedSymbol_t* sortedSymbols, U32 const* rankStart, +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed, + const U32* rankValOrigin, const int minWeight, + const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq) { - /* Fill skipped values (all positions up to rankVal[minWeight]). - * These are positions only get a single symbol because the combined weight - * is too large. - */ + HUF_DEltX2 DElt; + U32 rankVal[HUF_TABLELOG_MAX + 1]; + + /* get pre-calculated rankVal */ + memcpy(rankVal, rankValOrigin, sizeof(rankVal)); + + /* fill skipped values */ if (minWeight>1) { - U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); - U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); - int const skipSize = rankVal[minWeight]; - assert(length > 1); - assert((U32)skipSize < length); - switch (length) { - case 2: - assert(skipSize == 1); - ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); - break; - case 4: - assert(skipSize <= 4); - ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); - break; - default: - { - int i; - for (i = 0; i < skipSize; i += 8) { - ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); - } - } - } + U32 i, skipSize = rankVal[minWeight]; + MEM_writeLE16(&(DElt.sequence), baseSeq); + DElt.nbBits = (BYTE)(consumed); + DElt.length = 1; + for (i = 0; i < skipSize; i++) + DTable[i] = DElt; } - /* Fill each of the second level symbols by weight. */ - { - int w; - for (w = minWeight; w < maxWeight1; ++w) { - int const begin = rankStart[w]; - int const end = rankStart[w+1]; - U32 const nbBits = nbBitsBaseline - w; - U32 const totalBits = nbBits + consumedBits; - HUF_fillDTableX2ForWeight( - DTable + rankVal[w], - sortedSymbols + begin, sortedSymbols + end, - totalBits, targetLog, - baseSeq, /* level */ 2); - } - } + /* fill DTable */ + { U32 s; for (s=0; s= 1 */ + + rankVal[weight] += length; + } } } + static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, - const sortedSymbol_t* sortedList, - const U32* rankStart, rankValCol_t* rankValOrigin, const U32 maxWeight, + const sortedSymbol_t* sortedList, const U32 sortedListSize, + const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline) { - U32* const rankVal = rankValOrigin[0]; + U32 rankVal[HUF_TABLELOG_MAX + 1]; const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ const U32 minBits = nbBitsBaseline - maxWeight; - int w; - int const wEnd = (int)maxWeight + 1; - - /* Fill DTable in order of weight. */ - for (w = 1; w < wEnd; ++w) { - int const begin = (int)rankStart[w]; - int const end = (int)rankStart[w+1]; - U32 const nbBits = nbBitsBaseline - w; - - if (targetLog-nbBits >= minBits) { - /* Enough room for a second symbol. */ - int start = rankVal[w]; - U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); + U32 s; + + memcpy(rankVal, rankValOrigin, sizeof(rankVal)); + + /* fill DTable */ + for (s=0; s= minBits) { /* enough room for a second symbol */ + U32 sortedRank; int minWeight = nbBits + scaleLog; - int s; if (minWeight < 1) minWeight = 1; - /* Fill the DTable for every symbol of weight w. - * These symbols get at least 1 second symbol. - */ - for (s = begin; s != end; ++s) { - HUF_fillDTableX2Level2( - DTable + start, targetLog, nbBits, - rankValOrigin[nbBits], minWeight, wEnd, - sortedList, rankStart, - nbBitsBaseline, sortedList[s].symbol); - start += length; - } + sortedRank = rankStart[minWeight]; + HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits, + rankValOrigin[nbBits], minWeight, + sortedList+sortedRank, sortedListSize-sortedRank, + nbBitsBaseline, symbol); } else { - /* Only a single symbol. */ - HUF_fillDTableX2ForWeight( - DTable + rankVal[w], - sortedList + begin, sortedList + end, - nbBits, targetLog, - /* baseSeq */ 0, /* level */ 1); - } + HUF_DEltX2 DElt; + MEM_writeLE16(&(DElt.sequence), symbol); + DElt.nbBits = (BYTE)(nbBits); + DElt.length = 1; + { U32 const end = start + length; + U32 u; + for (u = start; u < end; u++) DTable[u] = DElt; + } } + rankVal[weight] += length; } } -typedef struct { - rankValCol_t rankVal[HUF_TABLELOG_MAX]; - U32 rankStats[HUF_TABLELOG_MAX + 1]; - U32 rankStart0[HUF_TABLELOG_MAX + 3]; - sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; - BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; - U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; -} HUF_ReadDTableX2_Workspace; - size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize) { - U32 tableLog, maxW, nbSymbols; + U32 tableLog, maxW, sizeOfSort, nbSymbols; DTableDesc dtd = HUF_getDTableDesc(DTable); - U32 maxTableLog = dtd.maxTableLog; + U32 const maxTableLog = dtd.maxTableLog; size_t iSize; void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; U32 *rankStart; - HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; - - if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); - - rankStart = wksp->rankStart0 + 1; - ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); - ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); + rankValCol_t* rankVal; + U32* rankStats; + U32* rankStart0; + sortedSymbol_t* sortedSymbol; + BYTE* weightList; + size_t spaceUsed32 = 0; + + rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2; + rankStats = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_MAX + 1; + rankStart0 = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_MAX + 2; + sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t); + spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2; + weightList = (BYTE *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; + + if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); + + rankStart = rankStart0 + 1; + memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1)); DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); - /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), flags); + iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUF_isError(iSize)) return iSize; /* check result */ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ - if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; /* find maxWeight */ - for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ /* Get start index of each weight */ { U32 w, nextRankStart = 0; for (w=1; wrankStats[w]; - rankStart[w] = curr; + U32 current = nextRankStart; + nextRankStart += rankStats[w]; + rankStart[w] = current; } rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ - rankStart[maxW+1] = nextRankStart; + sizeOfSort = nextRankStart; } /* sort symbols by weight */ { U32 s; for (s=0; sweightList[s]; + U32 const w = weightList[s]; U32 const r = rankStart[w]++; - wksp->sortedSymbol[r].symbol = (BYTE)s; + sortedSymbol[r].symbol = (BYTE)s; + sortedSymbol[r].weight = (BYTE)w; } rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ } /* Build rankVal */ - { U32* const rankVal0 = wksp->rankVal[0]; + { U32* const rankVal0 = rankVal[0]; { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ U32 nextRankVal = 0; U32 w; for (w=1; wrankStats[w] << (w+rescale); - rankVal0[w] = curr; + U32 current = nextRankVal; + nextRankVal += rankStats[w] << (w+rescale); + rankVal0[w] = current; } } { U32 const minBits = tableLog+1 - maxW; U32 consumed; for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { - U32* const rankValPtr = wksp->rankVal[consumed]; + U32* const rankValPtr = rankVal[consumed]; U32 w; for (w = 1; w < maxW+1; w++) { rankValPtr[w] = rankVal0[w] >> consumed; } } } } HUF_fillDTableX2(dt, maxTableLog, - wksp->sortedSymbol, - wksp->rankStart0, wksp->rankVal, maxW, + sortedSymbol, sizeOfSort, + rankStart0, rankVal, maxW, tableLog+1); dtd.tableLog = (BYTE)maxTableLog; dtd.tableType = 1; - ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + memcpy(DTable, &dtd, sizeof(dtd)); return iSize; } +size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX2_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + FORCE_INLINE_TEMPLATE U32 HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - ZSTD_memcpy(op, &dt[val].sequence, 2); + memcpy(op, dt+val, 2); BIT_skipBits(DStream, dt[val].nbBits); return dt[val].length; } @@ -1225,17 +680,15 @@ FORCE_INLINE_TEMPLATE U32 HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - ZSTD_memcpy(op, &dt[val].sequence, 1); - if (dt[val].length==1) { - BIT_skipBits(DStream, dt[val].nbBits); - } else { + memcpy(op, dt+val, 1); + if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits); + else { if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); - } - } + } } return 1; } @@ -1257,37 +710,19 @@ HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, BYTE* const pStart = p; /* up to 8 symbols at a time */ - if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { - if (dtLog <= 11 && MEM_64bits()) { - /* up to 10 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - } - } else { - /* up to 8 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_1(p, bitDPtr); - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - } - } - } else { - BIT_reloadDStream(bitDPtr); + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); } /* closer to end : up to 2 symbols at a time */ - if ((size_t)(pEnd - p) >= 2) { - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - while (p <= pEnd-2) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ - } + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ if (p < pEnd) p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); @@ -1322,10 +757,7 @@ HUF_decompress1X2_usingDTable_internal_body( return dstSize; } -/* HUF_decompress4X2_usingDTable_internal_body(): - * Conditions: - * @dstSize >= 6 - */ + FORCE_INLINE_TEMPLATE size_t HUF_decompress4X2_usingDTable_internal_body( void* dst, size_t dstSize, @@ -1337,7 +769,6 @@ HUF_decompress4X2_usingDTable_internal_body( { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; BYTE* const oend = ostart + dstSize; - BYTE* const olimit = oend - (sizeof(size_t)-1); const void* const dtPtr = DTable+1; const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; @@ -1362,66 +793,37 @@ HUF_decompress4X2_usingDTable_internal_body( BYTE* op2 = opStart2; BYTE* op3 = opStart3; BYTE* op4 = opStart4; - U32 endSignal = 1; + U32 endSignal; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ - if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* 16-32 symbols per loop (4-8 symbols per stream) */ - if ((size_t)(oend - op4) >= sizeof(size_t)) { - for ( ; (endSignal) & (op4 < olimit); ) { -#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; -#else - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal = (U32)LIKELY((U32) - (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) - & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) - & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) - & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); -#endif - } + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) { + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); } /* check corruption */ @@ -1445,279 +847,94 @@ HUF_decompress4X2_usingDTable_internal_body( } } -#if HUF_NEED_BMI2_FUNCTION -static BMI2_TARGET_ATTRIBUTE -size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); -} -#endif +HUF_DGEN(HUF_decompress1X2_usingDTable_internal) +HUF_DGEN(HUF_decompress4X2_usingDTable_internal) -static -size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +size_t HUF_decompress1X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -#if ZSTD_ENABLE_ASM_X86_64_BMI2 - -HUF_ASM_DECL void HUF_decompress4X2_usingDTable_internal_fast_asm_loop(HUF_DecompressFastArgs* args) ZSTDLIB_HIDDEN; - -#endif - -static HUF_FAST_BMI2_ATTRS -void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { - U64 bits[4]; - BYTE const* ip[4]; - BYTE* op[4]; - BYTE* oend[4]; - HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt; - BYTE const* const ilimit = args->ilimit; - - /* Copy the arguments to local registers. */ - ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); - ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); - ZSTD_memcpy(&op, &args->op, sizeof(op)); - - oend[0] = op[1]; - oend[1] = op[2]; - oend[2] = op[3]; - oend[3] = args->oend; - - assert(MEM_isLittleEndian()); - assert(!MEM_32bits()); - - for (;;) { - BYTE* olimit; - int stream; - int symbol; - - /* Assert loop preconditions */ -#ifndef NDEBUG - for (stream = 0; stream < 4; ++stream) { - assert(op[stream] <= oend[stream]); - assert(ip[stream] >= ilimit); - } -#endif - /* Compute olimit */ - { - /* Each loop does 5 table lookups for each of the 4 streams. - * Each table lookup consumes up to 11 bits of input, and produces - * up to 2 bytes of output. - */ - /* We can consume up to 7 bytes of input per iteration per stream. - * We also know that each input pointer is >= ip[0]. So we can run - * iters loops before running out of input. - */ - size_t iters = (size_t)(ip[0] - ilimit) / 7; - /* Each iteration can produce up to 10 bytes of output per stream. - * Each output stream my advance at different rates. So take the - * minimum number of safe iterations among all the output streams. - */ - for (stream = 0; stream < 4; ++stream) { - size_t const oiters = (size_t)(oend[stream] - op[stream]) / 10; - iters = MIN(iters, oiters); - } - - /* Each iteration produces at least 5 output symbols. So until - * op[3] crosses olimit, we know we haven't executed iters - * iterations yet. This saves us maintaining an iters counter, - * at the expense of computing the remaining # of iterations - * more frequently. - */ - olimit = op[3] + (iters * 5); - - /* Exit the fast decoding loop if we are too close to the end. */ - if (op[3] + 10 > olimit) - break; - - /* Exit the decoding loop if any input pointer has crossed the - * previous one. This indicates corruption, and a precondition - * to our loop is that ip[i] >= ip[0]. - */ - for (stream = 1; stream < 4; ++stream) { - if (ip[stream] < ip[stream - 1]) - goto _out; - } - } + const BYTE* ip = (const BYTE*) cSrc; -#ifndef NDEBUG - for (stream = 1; stream < 4; ++stream) { - assert(ip[stream] >= ip[stream - 1]); - } -#endif + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; - do { - /* Do 5 table lookups for each of the first 3 streams */ - for (symbol = 0; symbol < 5; ++symbol) { - for (stream = 0; stream < 3; ++stream) { - int const index = (int)(bits[stream] >> 53); - HUF_DEltX2 const entry = dtable[index]; - MEM_write16(op[stream], entry.sequence); - bits[stream] <<= (entry.nbBits); - op[stream] += (entry.length); - } - } - /* Do 1 table lookup from the final stream */ - { - int const index = (int)(bits[3] >> 53); - HUF_DEltX2 const entry = dtable[index]; - MEM_write16(op[3], entry.sequence); - bits[3] <<= (entry.nbBits); - op[3] += (entry.length); - } - /* Do 4 table lookups from the final stream & reload bitstreams */ - for (stream = 0; stream < 4; ++stream) { - /* Do a table lookup from the final stream. - * This is interleaved with the reloading to reduce register - * pressure. This shouldn't be necessary, but compilers can - * struggle with codegen with high register pressure. - */ - { - int const index = (int)(bits[3] >> 53); - HUF_DEltX2 const entry = dtable[index]; - MEM_write16(op[3], entry.sequence); - bits[3] <<= (entry.nbBits); - op[3] += (entry.length); - } - /* Reload the bistreams. The final bitstream must be reloaded - * after the 5th symbol was decoded. - */ - { - int const ctz = ZSTD_countTrailingZeros64(bits[stream]); - int const nbBits = ctz & 7; - int const nbBytes = ctz >> 3; - ip[stream] -= nbBytes; - bits[stream] = MEM_read64(ip[stream]) | 1; - bits[stream] <<= nbBits; - } - } - } while (op[3] < olimit); - } + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); +} -_out: - /* Save the final values of each of the state variables back to args. */ - ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); - ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); - ZSTD_memcpy(&args->op, &op, sizeof(op)); +size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); } +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} -static HUF_FAST_BMI2_ATTRS size_t -HUF_decompress4X2_usingDTable_internal_fast( +size_t HUF_decompress4X2_usingDTable( void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable, - HUF_DecompressFastLoopFn loopFn) { - void const* dt = DTable + 1; - const BYTE* const iend = (const BYTE*)cSrc + 6; - BYTE* const oend = (BYTE*)dst + dstSize; - HUF_DecompressFastArgs args; - { - size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); - FORWARD_IF_ERROR(ret, "Failed to init asm args"); - if (ret == 0) - return 0; - } - - assert(args.ip[0] >= args.ilimit); - loopFn(&args); - - /* note : op4 already verified within main loop */ - assert(args.ip[0] >= iend); - assert(args.ip[1] >= iend); - assert(args.ip[2] >= iend); - assert(args.ip[3] >= iend); - assert(args.op[3] <= oend); - (void)iend; - - /* finish bitStreams one by one */ - { - size_t const segmentSize = (dstSize+3) / 4; - BYTE* segmentEnd = (BYTE*)dst; - int i; - for (i = 0; i < 4; ++i) { - BIT_DStream_t bit; - if (segmentSize <= (size_t)(oend - segmentEnd)) - segmentEnd += segmentSize; - else - segmentEnd = oend; - FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); - args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); - if (args.op[i] != segmentEnd) - return ERROR(corruption_detected); - } - } - - /* decoded size */ - return dstSize; -} - -static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable, int flags) + const HUF_DTable* DTable) { - HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X2_usingDTable_internal_default; - HUF_DecompressFastLoopFn loopFn = HUF_decompress4X2_usingDTable_internal_fast_c_loop; - -#if DYNAMIC_BMI2 - if (flags & HUF_flags_bmi2) { - fallbackFn = HUF_decompress4X2_usingDTable_internal_bmi2; -# if ZSTD_ENABLE_ASM_X86_64_BMI2 - if (!(flags & HUF_flags_disableAsm)) { - loopFn = HUF_decompress4X2_usingDTable_internal_fast_asm_loop; - } -# endif - } else { - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); - } -#endif - -#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) - if (!(flags & HUF_flags_disableAsm)) { - loopFn = HUF_decompress4X2_usingDTable_internal_fast_asm_loop; - } -#endif - - if (!(flags & HUF_flags_disableFast)) { - size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); - if (ret != 0) - return ret; - } - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -HUF_DGEN(HUF_decompress1X2_usingDTable_internal) - -size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, +static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize, int bmi2) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, - workSpace, wkspSize, flags); + size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, flags); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); } -static size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize) { - const BYTE* ip = (const BYTE*) cSrc; + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0); +} - size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, - workSpace, wkspSize, flags); - if (HUF_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; cSrcSize -= hSize; - return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); } #endif /* HUF_FORCE_DECOMPRESS_X1 */ @@ -1727,28 +944,66 @@ static size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t ds /* Universal decompression selectors */ /* ***********************************/ +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + #if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; -static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = +static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = { /* single, double, quad */ - {{0,0}, {1,1}}, /* Q==0 : impossible */ - {{0,0}, {1,1}}, /* Q==1 : impossible */ - {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ - {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ - {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ - {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ - {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ - {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ - {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ - {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ - {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ - {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ - {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ - {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ - {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ - {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ + {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */ + {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */ + {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ + {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ + {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ + {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ + {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ + {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ + {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ + {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ + {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ + {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ + {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ + {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */ + {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */ + {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */ }; #endif @@ -1775,92 +1030,188 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) U32 const D256 = (U32)(dstSize >> 8); U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); - DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ + DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */ return DTime1 < DTime0; } #endif } + +typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); + +size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) + static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; +#endif + + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); +#else + return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); +#endif + } +} + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#else + return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : + HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; +#endif + } +} + +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + + +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, + size_t dstSize, const void* cSrc, + size_t cSrcSize, void* workSpace, + size_t wkspSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#endif + } +} + size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)algoNb; assert(algoNb == 0); return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags); + cSrcSize, workSpace, wkspSize); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)algoNb; assert(algoNb == 1); return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags); + cSrcSize, workSpace, wkspSize); #else return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags): + cSrcSize, workSpace, wkspSize): HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags); + cSrcSize, workSpace, wkspSize); #endif } } +size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} -size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) + +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) { DTableDesc const dtd = HUF_getDTableDesc(DTable); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)dtd; assert(dtd.tableType == 0); - return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)dtd; assert(dtd.tableType == 1); - return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #else - return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : - HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #endif } #ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); + size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); } #endif -size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) { DTableDesc const dtd = HUF_getDTableDesc(DTable); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)dtd; assert(dtd.tableType == 0); - return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)dtd; assert(dtd.tableType == 1); - return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #else - return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : - HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #endif } -size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); @@ -1870,16 +1221,14 @@ size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize #if defined(HUF_FORCE_DECOMPRESS_X1) (void)algoNb; assert(algoNb == 0); - return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)algoNb; assert(algoNb == 1); - return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); #else - return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags) : - HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); + return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) : + HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); #endif } } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/huf_decompress_amd64.S b/vendor/github.com/DataDog/zstd/huf_decompress_amd64.S deleted file mode 100644 index e5dc9a6d..00000000 --- a/vendor/github.com/DataDog/zstd/huf_decompress_amd64.S +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#include "portability_macros.h" - -/* Stack marking - * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart - */ -#if defined(__ELF__) && defined(__GNUC__) -.section .note.GNU-stack,"",%progbits -#endif - -#if ZSTD_ENABLE_ASM_X86_64_BMI2 - -/* Calling convention: - * - * %rdi contains the first argument: HUF_DecompressAsmArgs*. - * %rbp isn't maintained (no frame pointer). - * %rsp contains the stack pointer that grows down. - * No red-zone is assumed, only addresses >= %rsp are used. - * All register contents are preserved. - * - * TODO: Support Windows calling convention. - */ - -ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X1_usingDTable_internal_fast_asm_loop) -ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X2_usingDTable_internal_fast_asm_loop) -ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X2_usingDTable_internal_fast_asm_loop) -ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X1_usingDTable_internal_fast_asm_loop) -.global HUF_decompress4X1_usingDTable_internal_fast_asm_loop -.global HUF_decompress4X2_usingDTable_internal_fast_asm_loop -.global _HUF_decompress4X1_usingDTable_internal_fast_asm_loop -.global _HUF_decompress4X2_usingDTable_internal_fast_asm_loop -.text - -/* Sets up register mappings for clarity. - * op[], bits[], dtable & ip[0] each get their own register. - * ip[1,2,3] & olimit alias var[]. - * %rax is a scratch register. - */ - -#define op0 rsi -#define op1 rbx -#define op2 rcx -#define op3 rdi - -#define ip0 r8 -#define ip1 r9 -#define ip2 r10 -#define ip3 r11 - -#define bits0 rbp -#define bits1 rdx -#define bits2 r12 -#define bits3 r13 -#define dtable r14 -#define olimit r15 - -/* var[] aliases ip[1,2,3] & olimit - * ip[1,2,3] are saved every iteration. - * olimit is only used in compute_olimit. - */ -#define var0 r15 -#define var1 r9 -#define var2 r10 -#define var3 r11 - -/* 32-bit var registers */ -#define vard0 r15d -#define vard1 r9d -#define vard2 r10d -#define vard3 r11d - -/* Calls X(N) for each stream 0, 1, 2, 3. */ -#define FOR_EACH_STREAM(X) \ - X(0); \ - X(1); \ - X(2); \ - X(3) - -/* Calls X(N, idx) for each stream 0, 1, 2, 3. */ -#define FOR_EACH_STREAM_WITH_INDEX(X, idx) \ - X(0, idx); \ - X(1, idx); \ - X(2, idx); \ - X(3, idx) - -/* Define both _HUF_* & HUF_* symbols because MacOS - * C symbols are prefixed with '_' & Linux symbols aren't. - */ -_HUF_decompress4X1_usingDTable_internal_fast_asm_loop: -HUF_decompress4X1_usingDTable_internal_fast_asm_loop: - ZSTD_CET_ENDBRANCH - /* Save all registers - even if they are callee saved for simplicity. */ - push %rax - push %rbx - push %rcx - push %rdx - push %rbp - push %rsi - push %rdi - push %r8 - push %r9 - push %r10 - push %r11 - push %r12 - push %r13 - push %r14 - push %r15 - - /* Read HUF_DecompressAsmArgs* args from %rax */ - movq %rdi, %rax - movq 0(%rax), %ip0 - movq 8(%rax), %ip1 - movq 16(%rax), %ip2 - movq 24(%rax), %ip3 - movq 32(%rax), %op0 - movq 40(%rax), %op1 - movq 48(%rax), %op2 - movq 56(%rax), %op3 - movq 64(%rax), %bits0 - movq 72(%rax), %bits1 - movq 80(%rax), %bits2 - movq 88(%rax), %bits3 - movq 96(%rax), %dtable - push %rax /* argument */ - push 104(%rax) /* ilimit */ - push 112(%rax) /* oend */ - push %olimit /* olimit space */ - - subq $24, %rsp - -.L_4X1_compute_olimit: - /* Computes how many iterations we can do safely - * %r15, %rax may be clobbered - * rbx, rdx must be saved - * op3 & ip0 mustn't be clobbered - */ - movq %rbx, 0(%rsp) - movq %rdx, 8(%rsp) - - movq 32(%rsp), %rax /* rax = oend */ - subq %op3, %rax /* rax = oend - op3 */ - - /* r15 = (oend - op3) / 5 */ - movabsq $-3689348814741910323, %rdx - mulq %rdx - movq %rdx, %r15 - shrq $2, %r15 - - movq %ip0, %rax /* rax = ip0 */ - movq 40(%rsp), %rdx /* rdx = ilimit */ - subq %rdx, %rax /* rax = ip0 - ilimit */ - movq %rax, %rbx /* rbx = ip0 - ilimit */ - - /* rdx = (ip0 - ilimit) / 7 */ - movabsq $2635249153387078803, %rdx - mulq %rdx - subq %rdx, %rbx - shrq %rbx - addq %rbx, %rdx - shrq $2, %rdx - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - /* r15 = r15 * 5 */ - leaq (%r15, %r15, 4), %r15 - - /* olimit = op3 + r15 */ - addq %op3, %olimit - - movq 8(%rsp), %rdx - movq 0(%rsp), %rbx - - /* If (op3 + 20 > olimit) */ - movq %op3, %rax /* rax = op3 */ - addq $20, %rax /* rax = op3 + 20 */ - cmpq %rax, %olimit /* op3 + 20 > olimit */ - jb .L_4X1_exit - - /* If (ip1 < ip0) go to exit */ - cmpq %ip0, %ip1 - jb .L_4X1_exit - - /* If (ip2 < ip1) go to exit */ - cmpq %ip1, %ip2 - jb .L_4X1_exit - - /* If (ip3 < ip2) go to exit */ - cmpq %ip2, %ip3 - jb .L_4X1_exit - -/* Reads top 11 bits from bits[n] - * Loads dt[bits[n]] into var[n] - */ -#define GET_NEXT_DELT(n) \ - movq $53, %var##n; \ - shrxq %var##n, %bits##n, %var##n; \ - movzwl (%dtable,%var##n,2),%vard##n - -/* var[n] must contain the DTable entry computed with GET_NEXT_DELT - * Moves var[n] to %rax - * bits[n] <<= var[n] & 63 - * op[n][idx] = %rax >> 8 - * %ah is a way to access bits [8, 16) of %rax - */ -#define DECODE_FROM_DELT(n, idx) \ - movq %var##n, %rax; \ - shlxq %var##n, %bits##n, %bits##n; \ - movb %ah, idx(%op##n) - -/* Assumes GET_NEXT_DELT has been called. - * Calls DECODE_FROM_DELT then GET_NEXT_DELT - */ -#define DECODE_AND_GET_NEXT(n, idx) \ - DECODE_FROM_DELT(n, idx); \ - GET_NEXT_DELT(n) \ - -/* // ctz & nbBytes is stored in bits[n] - * // nbBits is stored in %rax - * ctz = CTZ[bits[n]] - * nbBits = ctz & 7 - * nbBytes = ctz >> 3 - * op[n] += 5 - * ip[n] -= nbBytes - * // Note: x86-64 is little-endian ==> no bswap - * bits[n] = MEM_readST(ip[n]) | 1 - * bits[n] <<= nbBits - */ -#define RELOAD_BITS(n) \ - bsfq %bits##n, %bits##n; \ - movq %bits##n, %rax; \ - andq $7, %rax; \ - shrq $3, %bits##n; \ - leaq 5(%op##n), %op##n; \ - subq %bits##n, %ip##n; \ - movq (%ip##n), %bits##n; \ - orq $1, %bits##n; \ - shlx %rax, %bits##n, %bits##n - - /* Store clobbered variables on the stack */ - movq %olimit, 24(%rsp) - movq %ip1, 0(%rsp) - movq %ip2, 8(%rsp) - movq %ip3, 16(%rsp) - - /* Call GET_NEXT_DELT for each stream */ - FOR_EACH_STREAM(GET_NEXT_DELT) - - .p2align 6 - -.L_4X1_loop_body: - /* Decode 5 symbols in each of the 4 streams (20 total) - * Must have called GET_NEXT_DELT for each stream - */ - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 0) - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 1) - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 2) - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 3) - FOR_EACH_STREAM_WITH_INDEX(DECODE_FROM_DELT, 4) - - /* Load ip[1,2,3] from stack (var[] aliases them) - * ip[] is needed for RELOAD_BITS - * Each will be stored back to the stack after RELOAD - */ - movq 0(%rsp), %ip1 - movq 8(%rsp), %ip2 - movq 16(%rsp), %ip3 - - /* Reload each stream & fetch the next table entry - * to prepare for the next iteration - */ - RELOAD_BITS(0) - GET_NEXT_DELT(0) - - RELOAD_BITS(1) - movq %ip1, 0(%rsp) - GET_NEXT_DELT(1) - - RELOAD_BITS(2) - movq %ip2, 8(%rsp) - GET_NEXT_DELT(2) - - RELOAD_BITS(3) - movq %ip3, 16(%rsp) - GET_NEXT_DELT(3) - - /* If op3 < olimit: continue the loop */ - cmp %op3, 24(%rsp) - ja .L_4X1_loop_body - - /* Reload ip[1,2,3] from stack */ - movq 0(%rsp), %ip1 - movq 8(%rsp), %ip2 - movq 16(%rsp), %ip3 - - /* Re-compute olimit */ - jmp .L_4X1_compute_olimit - -#undef GET_NEXT_DELT -#undef DECODE_FROM_DELT -#undef DECODE -#undef RELOAD_BITS -.L_4X1_exit: - addq $24, %rsp - - /* Restore stack (oend & olimit) */ - pop %rax /* olimit */ - pop %rax /* oend */ - pop %rax /* ilimit */ - pop %rax /* arg */ - - /* Save ip / op / bits */ - movq %ip0, 0(%rax) - movq %ip1, 8(%rax) - movq %ip2, 16(%rax) - movq %ip3, 24(%rax) - movq %op0, 32(%rax) - movq %op1, 40(%rax) - movq %op2, 48(%rax) - movq %op3, 56(%rax) - movq %bits0, 64(%rax) - movq %bits1, 72(%rax) - movq %bits2, 80(%rax) - movq %bits3, 88(%rax) - - /* Restore registers */ - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %r11 - pop %r10 - pop %r9 - pop %r8 - pop %rdi - pop %rsi - pop %rbp - pop %rdx - pop %rcx - pop %rbx - pop %rax - ret - -_HUF_decompress4X2_usingDTable_internal_fast_asm_loop: -HUF_decompress4X2_usingDTable_internal_fast_asm_loop: - ZSTD_CET_ENDBRANCH - /* Save all registers - even if they are callee saved for simplicity. */ - push %rax - push %rbx - push %rcx - push %rdx - push %rbp - push %rsi - push %rdi - push %r8 - push %r9 - push %r10 - push %r11 - push %r12 - push %r13 - push %r14 - push %r15 - - movq %rdi, %rax - movq 0(%rax), %ip0 - movq 8(%rax), %ip1 - movq 16(%rax), %ip2 - movq 24(%rax), %ip3 - movq 32(%rax), %op0 - movq 40(%rax), %op1 - movq 48(%rax), %op2 - movq 56(%rax), %op3 - movq 64(%rax), %bits0 - movq 72(%rax), %bits1 - movq 80(%rax), %bits2 - movq 88(%rax), %bits3 - movq 96(%rax), %dtable - push %rax /* argument */ - push %rax /* olimit */ - push 104(%rax) /* ilimit */ - - movq 112(%rax), %rax - push %rax /* oend3 */ - - movq %op3, %rax - push %rax /* oend2 */ - - movq %op2, %rax - push %rax /* oend1 */ - - movq %op1, %rax - push %rax /* oend0 */ - - /* Scratch space */ - subq $8, %rsp - -.L_4X2_compute_olimit: - /* Computes how many iterations we can do safely - * %r15, %rax may be clobbered - * rdx must be saved - * op[1,2,3,4] & ip0 mustn't be clobbered - */ - movq %rdx, 0(%rsp) - - /* We can consume up to 7 input bytes each iteration. */ - movq %ip0, %rax /* rax = ip0 */ - movq 40(%rsp), %rdx /* rdx = ilimit */ - subq %rdx, %rax /* rax = ip0 - ilimit */ - movq %rax, %r15 /* r15 = ip0 - ilimit */ - - /* rdx = rax / 7 */ - movabsq $2635249153387078803, %rdx - mulq %rdx - subq %rdx, %r15 - shrq %r15 - addq %r15, %rdx - shrq $2, %rdx - - /* r15 = (ip0 - ilimit) / 7 */ - movq %rdx, %r15 - - /* r15 = min(r15, min(oend0 - op0, oend1 - op1, oend2 - op2, oend3 - op3) / 10) */ - movq 8(%rsp), %rax /* rax = oend0 */ - subq %op0, %rax /* rax = oend0 - op0 */ - movq 16(%rsp), %rdx /* rdx = oend1 */ - subq %op1, %rdx /* rdx = oend1 - op1 */ - - cmpq %rax, %rdx - cmova %rax, %rdx /* rdx = min(%rdx, %rax) */ - - movq 24(%rsp), %rax /* rax = oend2 */ - subq %op2, %rax /* rax = oend2 - op2 */ - - cmpq %rax, %rdx - cmova %rax, %rdx /* rdx = min(%rdx, %rax) */ - - movq 32(%rsp), %rax /* rax = oend3 */ - subq %op3, %rax /* rax = oend3 - op3 */ - - cmpq %rax, %rdx - cmova %rax, %rdx /* rdx = min(%rdx, %rax) */ - - movabsq $-3689348814741910323, %rax - mulq %rdx - shrq $3, %rdx /* rdx = rdx / 10 */ - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - /* olimit = op3 + 5 * r15 */ - movq %r15, %rax - leaq (%op3, %rax, 4), %olimit - addq %rax, %olimit - - movq 0(%rsp), %rdx - - /* If (op3 + 10 > olimit) */ - movq %op3, %rax /* rax = op3 */ - addq $10, %rax /* rax = op3 + 10 */ - cmpq %rax, %olimit /* op3 + 10 > olimit */ - jb .L_4X2_exit - - /* If (ip1 < ip0) go to exit */ - cmpq %ip0, %ip1 - jb .L_4X2_exit - - /* If (ip2 < ip1) go to exit */ - cmpq %ip1, %ip2 - jb .L_4X2_exit - - /* If (ip3 < ip2) go to exit */ - cmpq %ip2, %ip3 - jb .L_4X2_exit - -#define DECODE(n, idx) \ - movq %bits##n, %rax; \ - shrq $53, %rax; \ - movzwl 0(%dtable,%rax,4),%r8d; \ - movzbl 2(%dtable,%rax,4),%r15d; \ - movzbl 3(%dtable,%rax,4),%eax; \ - movw %r8w, (%op##n); \ - shlxq %r15, %bits##n, %bits##n; \ - addq %rax, %op##n - -#define RELOAD_BITS(n) \ - bsfq %bits##n, %bits##n; \ - movq %bits##n, %rax; \ - shrq $3, %bits##n; \ - andq $7, %rax; \ - subq %bits##n, %ip##n; \ - movq (%ip##n), %bits##n; \ - orq $1, %bits##n; \ - shlxq %rax, %bits##n, %bits##n - - - movq %olimit, 48(%rsp) - - .p2align 6 - -.L_4X2_loop_body: - /* We clobber r8, so store it on the stack */ - movq %r8, 0(%rsp) - - /* Decode 5 symbols from each of the 4 streams (20 symbols total). */ - FOR_EACH_STREAM_WITH_INDEX(DECODE, 0) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 1) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 2) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 3) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 4) - - /* Reload r8 */ - movq 0(%rsp), %r8 - - FOR_EACH_STREAM(RELOAD_BITS) - - cmp %op3, 48(%rsp) - ja .L_4X2_loop_body - jmp .L_4X2_compute_olimit - -#undef DECODE -#undef RELOAD_BITS -.L_4X2_exit: - addq $8, %rsp - /* Restore stack (oend & olimit) */ - pop %rax /* oend0 */ - pop %rax /* oend1 */ - pop %rax /* oend2 */ - pop %rax /* oend3 */ - pop %rax /* ilimit */ - pop %rax /* olimit */ - pop %rax /* arg */ - - /* Save ip / op / bits */ - movq %ip0, 0(%rax) - movq %ip1, 8(%rax) - movq %ip2, 16(%rax) - movq %ip3, 24(%rax) - movq %op0, 32(%rax) - movq %op1, 40(%rax) - movq %op2, 48(%rax) - movq %op3, 56(%rax) - movq %bits0, 64(%rax) - movq %bits1, 72(%rax) - movq %bits2, 80(%rax) - movq %bits3, 88(%rax) - - /* Restore registers */ - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %r11 - pop %r10 - pop %r9 - pop %r8 - pop %rdi - pop %rsi - pop %rbp - pop %rdx - pop %rcx - pop %rbx - pop %rax - ret - -#endif diff --git a/vendor/github.com/DataDog/zstd/mem.h b/vendor/github.com/DataDog/zstd/mem.h index a6007c93..530d30c8 100644 --- a/vendor/github.com/DataDog/zstd/mem.h +++ b/vendor/github.com/DataDog/zstd/mem.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -19,10 +18,8 @@ extern "C" { /*-**************************************** * Dependencies ******************************************/ -#include /* size_t, ptrdiff_t */ -#include "compiler.h" /* __has_builtin */ -#include "debug.h" /* DEBUG_STATIC_ASSERT */ -#include "zstd_deps.h" /* ZSTD_memcpy */ +#include /* size_t, ptrdiff_t */ +#include /* memcpy */ /*-**************************************** @@ -42,18 +39,94 @@ extern "C" { # define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ #endif +#ifndef __has_builtin +# define __has_builtin(x) 0 /* compat. with non-clang compilers */ +#endif + +/* code only tested on 32 and 64 bits systems */ +#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; } +MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + +/* detects whether we are being compiled under msan */ +#if defined (__has_feature) +# if __has_feature(memory_sanitizer) +# define MEMORY_SANITIZER 1 +# endif +#endif + +#if defined (MEMORY_SANITIZER) +/* Not all platforms that support msan provide sanitizers/msan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ + +#include /* intptr_t */ + +/* Make memory region fully initialized (without changing its contents). */ +void __msan_unpoison(const volatile void *a, size_t size); + +/* Make memory region fully uninitialized (without changing its contents). + This is a legacy interface that does not update origin information. Use + __msan_allocated_memory() instead. */ +void __msan_poison(const volatile void *a, size_t size); + +/* Returns the offset of the first (at least partially) poisoned byte in the + memory range, or -1 if the whole range is good. */ +intptr_t __msan_test_shadow(const volatile void *x, size_t size); +#endif + +/* detects whether we are being compiled under asan */ +#if defined (__has_feature) +# if __has_feature(address_sanitizer) +# define ADDRESS_SANITIZER 1 +# endif +#elif defined(__SANITIZE_ADDRESS__) +# define ADDRESS_SANITIZER 1 +#endif + +#if defined (ADDRESS_SANITIZER) +/* Not all platforms that support asan provide sanitizers/asan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ + +/** + * Marks a memory region ([addr, addr+size)) as unaddressable. + * + * This memory must be previously allocated by your program. Instrumented + * code is forbidden from accessing addresses in this region until it is + * unpoisoned. This function is not guaranteed to poison the entire region - + * it could poison only a subregion of [addr, addr+size) due to ASan + * alignment restrictions. + * + * \note This function is not thread-safe because no two threads can poison or + * unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_poison_memory_region(void const volatile *addr, size_t size); + +/** + * Marks a memory region ([addr, addr+size)) as addressable. + * + * This memory must be previously allocated by your program. Accessing + * addresses in this region is allowed until this region is poisoned again. + * This function could unpoison a super-region of [addr, addr+size) due + * to ASan alignment restrictions. + * + * \note This function is not thread-safe because no two threads can + * poison or unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#endif + + /*-************************************************************** * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; - typedef uint8_t U8; - typedef int8_t S8; typedef uint16_t U16; typedef int16_t S16; typedef uint32_t U32; @@ -66,8 +139,6 @@ extern "C" { # error "this implementation requires char to be exactly 8-bit type" #endif typedef unsigned char BYTE; - typedef unsigned char U8; - typedef signed char S8; #if USHRT_MAX != 65535 # error "this implementation requires short to be exactly 16-bit type" #endif @@ -86,63 +157,25 @@ extern "C" { /*-************************************************************** -* Memory I/O API -*****************************************************************/ -/*=== Static platform detection ===*/ -MEM_STATIC unsigned MEM_32bits(void); -MEM_STATIC unsigned MEM_64bits(void); -MEM_STATIC unsigned MEM_isLittleEndian(void); - -/*=== Native unaligned read/write ===*/ -MEM_STATIC U16 MEM_read16(const void* memPtr); -MEM_STATIC U32 MEM_read32(const void* memPtr); -MEM_STATIC U64 MEM_read64(const void* memPtr); -MEM_STATIC size_t MEM_readST(const void* memPtr); - -MEM_STATIC void MEM_write16(void* memPtr, U16 value); -MEM_STATIC void MEM_write32(void* memPtr, U32 value); -MEM_STATIC void MEM_write64(void* memPtr, U64 value); - -/*=== Little endian unaligned read/write ===*/ -MEM_STATIC U16 MEM_readLE16(const void* memPtr); -MEM_STATIC U32 MEM_readLE24(const void* memPtr); -MEM_STATIC U32 MEM_readLE32(const void* memPtr); -MEM_STATIC U64 MEM_readLE64(const void* memPtr); -MEM_STATIC size_t MEM_readLEST(const void* memPtr); - -MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); -MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); -MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); -MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); -MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); - -/*=== Big endian unaligned read/write ===*/ -MEM_STATIC U32 MEM_readBE32(const void* memPtr); -MEM_STATIC U64 MEM_readBE64(const void* memPtr); -MEM_STATIC size_t MEM_readBEST(const void* memPtr); - -MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); -MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); -MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); - -/*=== Byteswap ===*/ -MEM_STATIC U32 MEM_swap32(U32 in); -MEM_STATIC U64 MEM_swap64(U64 in); -MEM_STATIC size_t MEM_swapST(size_t in); - - -/*-************************************************************** -* Memory I/O Implementation +* Memory I/O *****************************************************************/ -/* MEM_FORCE_MEMORY_ACCESS : For accessing unaligned memory: - * Method 0 : always use `memcpy()`. Safe and portable. - * Method 1 : Use compiler extension to set unaligned access. +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. * Method 2 : direct access. This method is portable but violate C standard. * It can generate buggy code on targets depending on alignment. - * Default : method 1 if supported, else method 0 + * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# ifdef __GNUC__ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -152,22 +185,8 @@ MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } MEM_STATIC unsigned MEM_isLittleEndian(void) { -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - return 1; -#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - return 0; -#elif defined(__clang__) && __LITTLE_ENDIAN__ - return 1; -#elif defined(__clang__) && __BIG_ENDIAN__ - return 0; -#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) - return 1; -#elif defined(__DMC__) && defined(_M_IX86) - return 1; -#else const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; -#endif } #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) @@ -185,19 +204,30 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) -typedef __attribute__((aligned(1))) U16 unalign16; -typedef __attribute__((aligned(1))) U32 unalign32; -typedef __attribute__((aligned(1))) U64 unalign64; -typedef __attribute__((aligned(1))) size_t unalignArch; +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) + __pragma( pack(push, 1) ) + typedef struct { U16 v; } unalign16; + typedef struct { U32 v; } unalign32; + typedef struct { U64 v; } unalign64; + typedef struct { size_t v; } unalignArch; + __pragma( pack(pop) ) +#else + typedef struct { U16 v; } __attribute__((packed)) unalign16; + typedef struct { U32 v; } __attribute__((packed)) unalign32; + typedef struct { U64 v; } __attribute__((packed)) unalign64; + typedef struct { size_t v; } __attribute__((packed)) unalignArch; +#endif -MEM_STATIC U16 MEM_read16(const void* ptr) { return *(const unalign16*)ptr; } -MEM_STATIC U32 MEM_read32(const void* ptr) { return *(const unalign32*)ptr; } -MEM_STATIC U64 MEM_read64(const void* ptr) { return *(const unalign64*)ptr; } -MEM_STATIC size_t MEM_readST(const void* ptr) { return *(const unalignArch*)ptr; } +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } +MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } -MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(unalign16*)memPtr = value; } -MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(unalign32*)memPtr = value; } -MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = value; } +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } #else @@ -206,49 +236,41 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = val MEM_STATIC U16 MEM_read16(const void* memPtr) { - U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U32 MEM_read32(const void* memPtr) { - U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U64 MEM_read64(const void* memPtr) { - U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + U64 val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC size_t MEM_readST(const void* memPtr) { - size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + size_t val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { - ZSTD_memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { - ZSTD_memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write64(void* memPtr, U64 value) { - ZSTD_memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } #endif /* MEM_FORCE_MEMORY_ACCESS */ -MEM_STATIC U32 MEM_swap32_fallback(U32 in) -{ - return ((in << 24) & 0xff000000 ) | - ((in << 8) & 0x00ff0000 ) | - ((in >> 8) & 0x0000ff00 ) | - ((in >> 24) & 0x000000ff ); -} - MEM_STATIC U32 MEM_swap32(U32 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -257,22 +279,13 @@ MEM_STATIC U32 MEM_swap32(U32 in) || (defined(__clang__) && __has_builtin(__builtin_bswap32)) return __builtin_bswap32(in); #else - return MEM_swap32_fallback(in); + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); #endif } -MEM_STATIC U64 MEM_swap64_fallback(U64 in) -{ - return ((in << 56) & 0xff00000000000000ULL) | - ((in << 40) & 0x00ff000000000000ULL) | - ((in << 24) & 0x0000ff0000000000ULL) | - ((in << 8) & 0x000000ff00000000ULL) | - ((in >> 8) & 0x00000000ff000000ULL) | - ((in >> 24) & 0x0000000000ff0000ULL) | - ((in >> 40) & 0x000000000000ff00ULL) | - ((in >> 56) & 0x00000000000000ffULL); -} - MEM_STATIC U64 MEM_swap64(U64 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -281,7 +294,14 @@ MEM_STATIC U64 MEM_swap64(U64 in) || (defined(__clang__) && __has_builtin(__builtin_bswap64)) return __builtin_bswap64(in); #else - return MEM_swap64_fallback(in); + return ((in << 56) & 0xff00000000000000ULL) | + ((in << 40) & 0x00ff000000000000ULL) | + ((in << 24) & 0x0000ff0000000000ULL) | + ((in << 8) & 0x000000ff00000000ULL) | + ((in >> 8) & 0x00000000ff000000ULL) | + ((in >> 24) & 0x0000000000ff0000ULL) | + ((in >> 40) & 0x000000000000ff00ULL) | + ((in >> 56) & 0x00000000000000ffULL); #endif } @@ -318,7 +338,7 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) MEM_STATIC U32 MEM_readLE24(const void* memPtr) { - return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); + return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); } MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) @@ -425,14 +445,9 @@ MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) MEM_writeBE64(memPtr, (U64)val); } -/* code only tested on 32 and 64 bits systems */ -MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } - #if defined (__cplusplus) } #endif #endif /* MEM_H_MODULE */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/pool.c b/vendor/github.com/DataDog/zstd/pool.c index d067ac36..f5759350 100644 --- a/vendor/github.com/DataDog/zstd/pool.c +++ b/vendor/github.com/DataDog/zstd/pool.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,9 +10,9 @@ /* ====== Dependencies ======= */ -#include "allocations.h" /* ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd_deps.h" /* size_t */ +#include /* size_t */ #include "debug.h" /* assert */ +#include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */ #include "pool.h" /* ====== Compiler specifics ====== */ @@ -87,7 +86,7 @@ static void* POOL_thread(void* opaque) { { POOL_job const job = ctx->queue[ctx->queueHead]; ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; ctx->numThreadsBusy++; - ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); + ctx->queueEmpty = ctx->queueHead == ctx->queueTail; /* Unlock the mutex, signal a pusher, and run the job */ ZSTD_pthread_cond_signal(&ctx->queuePushCond); ZSTD_pthread_mutex_unlock(&ctx->queueMutex); @@ -97,37 +96,33 @@ static void* POOL_thread(void* opaque) { /* If the intended queue size was 0, signal after finishing job */ ZSTD_pthread_mutex_lock(&ctx->queueMutex); ctx->numThreadsBusy--; - ZSTD_pthread_cond_signal(&ctx->queuePushCond); + if (ctx->queueSize == 1) { + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + } ZSTD_pthread_mutex_unlock(&ctx->queueMutex); } } /* for (;;) */ assert(0); /* Unreachable */ } -/* ZSTD_createThreadPool() : public access point */ -POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { - return POOL_create (numThreads, 0); -} - POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); } POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, - ZSTD_customMem customMem) -{ + ZSTD_customMem customMem) { POOL_ctx* ctx; /* Check parameters */ if (!numThreads) { return NULL; } /* Allocate the context and zero initialize */ - ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); + ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem); if (!ctx) { return NULL; } /* Initialize the job queue. * It needs one extra space since one space is wasted to differentiate * empty and full queues. */ ctx->queueSize = queueSize + 1; - ctx->queue = (POOL_job*)ZSTD_customCalloc(ctx->queueSize * sizeof(POOL_job), customMem); + ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem); ctx->queueHead = 0; ctx->queueTail = 0; ctx->numThreadsBusy = 0; @@ -141,7 +136,7 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, } ctx->shutdown = 0; /* Allocate space for the thread handles */ - ctx->threads = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); + ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem); ctx->threadCapacity = 0; ctx->customMem = customMem; /* Check for errors */ @@ -174,7 +169,7 @@ static void POOL_join(POOL_ctx* ctx) { /* Join all of the threads */ { size_t i; for (i = 0; i < ctx->threadCapacity; ++i) { - ZSTD_pthread_join(ctx->threads[i]); /* note : could fail */ + ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */ } } } @@ -184,27 +179,14 @@ void POOL_free(POOL_ctx *ctx) { ZSTD_pthread_mutex_destroy(&ctx->queueMutex); ZSTD_pthread_cond_destroy(&ctx->queuePushCond); ZSTD_pthread_cond_destroy(&ctx->queuePopCond); - ZSTD_customFree(ctx->queue, ctx->customMem); - ZSTD_customFree(ctx->threads, ctx->customMem); - ZSTD_customFree(ctx, ctx->customMem); + ZSTD_free(ctx->queue, ctx->customMem); + ZSTD_free(ctx->threads, ctx->customMem); + ZSTD_free(ctx, ctx->customMem); } -/*! POOL_joinJobs() : - * Waits for all queued jobs to finish executing. - */ -void POOL_joinJobs(POOL_ctx* ctx) { - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - while(!ctx->queueEmpty || ctx->numThreadsBusy > 0) { - ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); - } - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); -} -void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { - POOL_free (pool); -} -size_t POOL_sizeof(const POOL_ctx* ctx) { +size_t POOL_sizeof(POOL_ctx *ctx) { if (ctx==NULL) return 0; /* supports sizeof NULL */ return sizeof(*ctx) + ctx->queueSize * sizeof(POOL_job) @@ -221,11 +203,11 @@ static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) return 0; } /* numThreads > threadCapacity */ - { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); + { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); if (!threadPool) return 1; /* replace existing thread pool */ - ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); - ZSTD_customFree(ctx->threads, ctx->customMem); + memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); + ZSTD_free(ctx->threads, ctx->customMem); ctx->threads = threadPool; /* Initialize additional threads */ { size_t threadId; @@ -269,12 +251,9 @@ static int isQueueFull(POOL_ctx const* ctx) { } -static void -POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) +static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) { - POOL_job job; - job.function = function; - job.opaque = opaque; + POOL_job const job = {function, opaque}; assert(ctx != NULL); if (ctx->shutdown) return; @@ -322,28 +301,21 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) struct POOL_ctx_s { int dummy; }; -static POOL_ctx g_poolCtx; +static POOL_ctx g_ctx; POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); } -POOL_ctx* -POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) -{ +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { (void)numThreads; (void)queueSize; (void)customMem; - return &g_poolCtx; + return &g_ctx; } void POOL_free(POOL_ctx* ctx) { - assert(!ctx || ctx == &g_poolCtx); - (void)ctx; -} - -void POOL_joinJobs(POOL_ctx* ctx){ - assert(!ctx || ctx == &g_poolCtx); + assert(!ctx || ctx == &g_ctx); (void)ctx; } @@ -363,12 +335,10 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { return 1; } -size_t POOL_sizeof(const POOL_ctx* ctx) { +size_t POOL_sizeof(POOL_ctx* ctx) { if (ctx==NULL) return 0; /* supports sizeof NULL */ - assert(ctx == &g_poolCtx); + assert(ctx == &g_ctx); return sizeof(*ctx); } #endif /* ZSTD_MULTITHREAD */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/pool.h b/vendor/github.com/DataDog/zstd/pool.h index 7dcf4959..458d37f1 100644 --- a/vendor/github.com/DataDog/zstd/pool.h +++ b/vendor/github.com/DataDog/zstd/pool.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,7 +16,7 @@ extern "C" { #endif -#include "zstd_deps.h" +#include /* size_t */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ #include "zstd.h" @@ -39,12 +38,6 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, */ void POOL_free(POOL_ctx* ctx); - -/*! POOL_joinJobs() : - * Waits for all queued jobs to finish executing. - */ -void POOL_joinJobs(POOL_ctx* ctx); - /*! POOL_resize() : * Expands or shrinks pool's number of threads. * This is more efficient than releasing + creating a new context, @@ -60,7 +53,7 @@ int POOL_resize(POOL_ctx* ctx, size_t numThreads); * @return threadpool memory usage * note : compatible with NULL (returns 0 in this case) */ -size_t POOL_sizeof(const POOL_ctx* ctx); +size_t POOL_sizeof(POOL_ctx* ctx); /*! POOL_function : * The function type that can be added to a thread pool. @@ -77,7 +70,7 @@ void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); /*! POOL_tryAdd() : - * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. + * Add the job `function(opaque)` to thread pool _if_ a worker is available. * Returns immediately even if not (does not block). * @return : 1 if successful, 0 if not. */ @@ -89,5 +82,3 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); #endif #endif - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/portability_macros.h b/vendor/github.com/DataDog/zstd/portability_macros.h deleted file mode 100644 index ecf5453b..00000000 --- a/vendor/github.com/DataDog/zstd/portability_macros.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_PORTABILITY_MACROS_H -#define ZSTD_PORTABILITY_MACROS_H - -/** - * This header file contains macro definitions to support portability. - * This header is shared between C and ASM code, so it MUST only - * contain macro definitions. It MUST not contain any C code. - * - * This header ONLY defines macros to detect platforms/feature support. - * - */ - - -/* compat. with non-clang compilers */ -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif - -/* compat. with non-clang compilers */ -#ifndef __has_builtin -# define __has_builtin(x) 0 -#endif - -/* compat. with non-clang compilers */ -#ifndef __has_feature -# define __has_feature(x) 0 -#endif - -/* detects whether we are being compiled under msan */ -#ifndef ZSTD_MEMORY_SANITIZER -# if __has_feature(memory_sanitizer) -# define ZSTD_MEMORY_SANITIZER 1 -# else -# define ZSTD_MEMORY_SANITIZER 0 -# endif -#endif - -/* detects whether we are being compiled under asan */ -#ifndef ZSTD_ADDRESS_SANITIZER -# if __has_feature(address_sanitizer) -# define ZSTD_ADDRESS_SANITIZER 1 -# elif defined(__SANITIZE_ADDRESS__) -# define ZSTD_ADDRESS_SANITIZER 1 -# else -# define ZSTD_ADDRESS_SANITIZER 0 -# endif -#endif - -/* detects whether we are being compiled under dfsan */ -#ifndef ZSTD_DATAFLOW_SANITIZER -# if __has_feature(dataflow_sanitizer) -# define ZSTD_DATAFLOW_SANITIZER 1 -# else -# define ZSTD_DATAFLOW_SANITIZER 0 -# endif -#endif - -/* Mark the internal assembly functions as hidden */ -#ifdef __ELF__ -# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func -#else -# define ZSTD_HIDE_ASM_FUNCTION(func) -#endif - -/* Enable runtime BMI2 dispatch based on the CPU. - * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. - */ -#ifndef DYNAMIC_BMI2 - #if ((defined(__clang__) && __has_attribute(__target__)) \ - || (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ - && (defined(__x86_64__) || defined(_M_X64)) \ - && !defined(__BMI2__) - # define DYNAMIC_BMI2 1 - #else - # define DYNAMIC_BMI2 0 - #endif -#endif - -/** - * Only enable assembly for GNUC compatible compilers, - * because other platforms may not support GAS assembly syntax. - * - * Only enable assembly for Linux / MacOS, other platforms may - * work, but they haven't been tested. This could likely be - * extended to BSD systems. - * - * Disable assembly when MSAN is enabled, because MSAN requires - * 100% of code to be instrumented to work. - */ -#if defined(__GNUC__) -# if defined(__linux__) || defined(__linux) || defined(__APPLE__) -# if ZSTD_MEMORY_SANITIZER -# define ZSTD_ASM_SUPPORTED 0 -# elif ZSTD_DATAFLOW_SANITIZER -# define ZSTD_ASM_SUPPORTED 0 -# else -# define ZSTD_ASM_SUPPORTED 1 -# endif -# else -# define ZSTD_ASM_SUPPORTED 0 -# endif -#else -# define ZSTD_ASM_SUPPORTED 0 -#endif - -/** - * Determines whether we should enable assembly for x86-64 - * with BMI2. - * - * Enable if all of the following conditions hold: - * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM - * - Assembly is supported - * - We are compiling for x86-64 and either: - * - DYNAMIC_BMI2 is enabled - * - BMI2 is supported at compile time - */ -#if !defined(ZSTD_DISABLE_ASM) && \ - ZSTD_ASM_SUPPORTED && \ - defined(__x86_64__) && \ - (DYNAMIC_BMI2 || defined(__BMI2__)) -# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 -#else -# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 -#endif - -/* - * For x86 ELF targets, add .note.gnu.property section for Intel CET in - * assembly sources when CET is enabled. - * - * Additionally, any function that may be called indirectly must begin - * with ZSTD_CET_ENDBRANCH. - */ -#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \ - && defined(__has_include) -# if __has_include() -# include -# define ZSTD_CET_ENDBRANCH _CET_ENDBR -# endif -#endif - -#ifndef ZSTD_CET_ENDBRANCH -# define ZSTD_CET_ENDBRANCH -#endif - -#endif /* ZSTD_PORTABILITY_MACROS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/threading.c b/vendor/github.com/DataDog/zstd/threading.c index df3c7ddf..482664bd 100644 --- a/vendor/github.com/DataDog/zstd/threading.c +++ b/vendor/github.com/DataDog/zstd/threading.c @@ -1,15 +1,13 @@ -#ifndef USE_EXTERNAL_ZSTD /** * Copyright (c) 2016 Tino Reichardt * All rights reserved. * - * You can contact the author at: - * - zstdmt source repository: https://github.com/mcmilk/zstdmt - * * This source code is licensed under both the BSD-style license (found in the * LICENSE file in the root directory of this source tree) and the GPLv2 (found * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt */ /** @@ -24,7 +22,8 @@ int g_ZSTD_threading_useless_symbol; #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) /** - * Windows minimalist Pthread Wrapper + * Windows minimalist Pthread Wrapper, based on : + * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html */ @@ -35,92 +34,37 @@ int g_ZSTD_threading_useless_symbol; /* === Implementation === */ -typedef struct { - void* (*start_routine)(void*); - void* arg; - int initialized; - ZSTD_pthread_cond_t initialized_cond; - ZSTD_pthread_mutex_t initialized_mutex; -} ZSTD_thread_params_t; - static unsigned __stdcall worker(void *arg) { - void* (*start_routine)(void*); - void* thread_arg; - - /* Initialized thread_arg and start_routine and signal main thread that we don't need it - * to wait any longer. - */ - { - ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg; - thread_arg = thread_param->arg; - start_routine = thread_param->start_routine; - - /* Signal main thread that we are running and do not depend on its memory anymore */ - ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex); - thread_param->initialized = 1; - ZSTD_pthread_cond_signal(&thread_param->initialized_cond); - ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex); - } - - start_routine(thread_arg); - + ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg; + thread->arg = thread->start_routine(thread->arg); return 0; } int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, void* (*start_routine) (void*), void* arg) { - ZSTD_thread_params_t thread_param; (void)unused; + thread->arg = arg; + thread->start_routine = start_routine; + thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL); - thread_param.start_routine = start_routine; - thread_param.arg = arg; - thread_param.initialized = 0; - *thread = NULL; - - /* Setup thread initialization synchronization */ - if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) { - /* Should never happen on Windows */ - return -1; - } - if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) { - /* Should never happen on Windows */ - ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); - return -1; - } - - /* Spawn thread */ - *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL); - if (!thread) { - ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); - ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + if (!thread->handle) return errno; - } - - /* Wait for thread to be initialized */ - ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex); - while(!thread_param.initialized) { - ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex); - } - ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex); - ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); - ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); - - return 0; + else + return 0; } -int ZSTD_pthread_join(ZSTD_pthread_t thread) +int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) { DWORD result; - if (!thread) return 0; - - result = WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); + if (!thread.handle) return 0; + result = WaitForSingleObject(thread.handle, INFINITE); switch (result) { case WAIT_OBJECT_0: + if (value_ptr) *value_ptr = thread.arg; return 0; case WAIT_ABANDONED: return EINVAL; @@ -133,12 +77,11 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread) #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) -#define ZSTD_DEPS_NEED_MALLOC -#include "zstd_deps.h" +#include int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) { - *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); + *mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); if (!*mutex) return 1; return pthread_mutex_init(*mutex, attr); @@ -150,14 +93,14 @@ int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) return 0; { int const ret = pthread_mutex_destroy(*mutex); - ZSTD_free(*mutex); + free(*mutex); return ret; } } int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) { - *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); + *cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t)); if (!*cond) return 1; return pthread_cond_init(*cond, attr); @@ -169,11 +112,9 @@ int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) return 0; { int const ret = pthread_cond_destroy(*cond); - ZSTD_free(*cond); + free(*cond); return ret; } } #endif - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/threading.h b/vendor/github.com/DataDog/zstd/threading.h index b9216599..3193ca7d 100644 --- a/vendor/github.com/DataDog/zstd/threading.h +++ b/vendor/github.com/DataDog/zstd/threading.h @@ -1,15 +1,13 @@ -#ifndef USE_EXTERNAL_ZSTD /** * Copyright (c) 2016 Tino Reichardt * All rights reserved. * - * You can contact the author at: - * - zstdmt source repository: https://github.com/mcmilk/zstdmt - * * This source code is licensed under both the BSD-style license (found in the * LICENSE file in the root directory of this source tree) and the GPLv2 (found * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt */ #ifndef THREADING_H_938743 @@ -24,7 +22,8 @@ extern "C" { #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) /** - * Windows minimalist Pthread Wrapper + * Windows minimalist Pthread Wrapper, based on : + * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html */ #ifdef WINVER # undef WINVER @@ -62,12 +61,16 @@ extern "C" { #define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) /* ZSTD_pthread_create() and ZSTD_pthread_join() */ -typedef HANDLE ZSTD_pthread_t; +typedef struct { + HANDLE handle; + void* (*start_routine)(void*); + void* arg; +} ZSTD_pthread_t; int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, void* (*start_routine) (void*), void* arg); -int ZSTD_pthread_join(ZSTD_pthread_t thread); +int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr); /** * add here more wrappers as required @@ -95,7 +98,7 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread); #define ZSTD_pthread_t pthread_t #define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) -#define ZSTD_pthread_join(a) pthread_join((a),NULL) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) #else /* DEBUGLEVEL >= 1 */ @@ -120,7 +123,7 @@ int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); #define ZSTD_pthread_t pthread_t #define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) -#define ZSTD_pthread_join(a) pthread_join((a),NULL) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) #endif @@ -149,5 +152,3 @@ typedef int ZSTD_pthread_cond_t; #endif #endif /* THREADING_H_938743 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/travis_test_32.sh b/vendor/github.com/DataDog/zstd/travis_test_32.sh index 264ca06d..4a0debc8 100644 --- a/vendor/github.com/DataDog/zstd/travis_test_32.sh +++ b/vendor/github.com/DataDog/zstd/travis_test_32.sh @@ -1,8 +1,6 @@ #!/bin/bash # Get utilities -#yum -y -q -e 0 install wget tar unzip gcc -apt-get update -apt-get -y install wget tar unzip gcc +yum -y -q -e 0 install wget tar unzip gcc # Get Go wget -q https://dl.google.com/go/go1.13.linux-386.tar.gz @@ -15,5 +13,5 @@ unzip mr.zip # Build and run tests go build -DISABLE_BIG_TESTS=1 PAYLOAD=$(pwd)/mr go test -v -DISABLE_BIG_TESTS=1 PAYLOAD=$(pwd)/mr go test -bench . +PAYLOAD=$(pwd)/mr go test -v +PAYLOAD=$(pwd)/mr go test -bench . diff --git a/vendor/github.com/DataDog/zstd/xxhash.c b/vendor/github.com/DataDog/zstd/xxhash.c index 71df219c..99d24596 100644 --- a/vendor/github.com/DataDog/zstd/xxhash.c +++ b/vendor/github.com/DataDog/zstd/xxhash.c @@ -1,27 +1,882 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * xxHash - Fast Hash algorithm - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - xxHash homepage: https://cyan4973.github.io/xxHash/ - * - xxHash source repository : https://github.com/Cyan4973/xxHash - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. +* xxHash - Fast Hash algorithm +* Copyright (C) 2012-2016, Yann Collet +* +* BSD 2-Clause License (http://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: http://www.xxhash.com +* - xxHash source repository : https://github.com/Cyan4973/xxHash */ +/* ************************************* +* 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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method doesn't depend on compiler but violate 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 (ie GCC + ARMv6) + * See http://stackoverflow.com/a/32095106/646947 for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define XXH_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \ + defined(__ICCARM__) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif -/* - * xxhash.c instantiates functions defined in xxhash.h +/*!XXH_ACCEPT_NULL_INPUT_POINTER : + * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer. + * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input. + * By default, this option is disabled. To enable it, uncomment below define : + */ +/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */ + +/*!XXH_FORCE_NATIVE_FORMAT : + * By default, xxHash library provides endian-independent Hash values, based on little-endian convention. + * Results are therefore identical for little-endian and big-endian CPU. + * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. + * Should endian-independence be of no importance for your application, you may set the #define below to 1, + * to improve speed for Big-endian CPU. + * This option has no impact on Little_Endian CPU. + */ +#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */ +# define XXH_FORCE_NATIVE_FORMAT 0 +#endif + +/*!XXH_FORCE_ALIGN_CHECK : + * This is a minor performance trick, only useful with lots of very small keys. + * It means : check for aligned/unaligned input. + * The check costs one initial branch per hash; set to 0 when the input data + * is guaranteed to be aligned. */ +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + -#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ -#define XXH_IMPLEMENTATION /* access definitions */ +/* ************************************* +* Includes & Memory related functions +***************************************/ +/* Modify the local functions below should you wish to use some other memory routines */ +/* for malloc(), free() */ +#include +#include /* size_t */ +static void* XXH_malloc(size_t s) { return malloc(s); } +static void XXH_free (void* p) { free(p); } +/* for memcpy() */ +#include +static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } +#ifndef XXH_STATIC_LINKING_ONLY +# define XXH_STATIC_LINKING_ONLY +#endif #include "xxhash.h" -#endif /* USE_EXTERNAL_ZSTD */ + +/* ************************************* +* Compiler Specific Options +***************************************/ +#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# define INLINE_KEYWORD inline +#else +# define INLINE_KEYWORD +#endif + +#if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_INLINE_ATTR __attribute__((always_inline)) +#elif defined(_MSC_VER) +# define FORCE_INLINE_ATTR __forceinline +#else +# define FORCE_INLINE_ATTR +#endif + +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR + + +#ifdef _MSC_VER +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + + +/* ************************************* +* Basic Types +***************************************/ +#ifndef MEM_MODULE +# define MEM_MODULE +# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; +# else + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */ +# endif +#endif + + +#if (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 U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; } +static U64 XXH_read64(const void* memPtr) { return *(const 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 */ +typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign; + +static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +#else + +/* portable and safe solution. Generally efficient. + * see : http://stackoverflow.com/a/32095106/646947 + */ + +static U32 XXH_read32(const void* memPtr) +{ + U32 val; + memcpy(&val, memPtr, sizeof(val)); + return val; +} + +static U64 XXH_read64(const void* memPtr) +{ + U64 val; + memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ +#if defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +#if defined(__ICCARM__) +# include +# define XXH_rotl32(x,r) __ROR(x,(32 - r)) +#else +# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) +#endif +# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) +#endif + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +# define XXH_swap64 _byteswap_uint64 +#elif GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +# define XXH_swap64 __builtin_bswap64 +#else +static U32 XXH_swap32 (U32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +static U64 XXH_swap64 (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 + + +/* ************************************* +* Architecture Macros +***************************************/ +typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; + +/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ +#ifndef XXH_CPU_LITTLE_ENDIAN + static const int g_one = 1; +# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one)) +#endif + + +/* *************************** +* Memory reads +*****************************/ +typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; + +FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +{ + if (align==XXH_unaligned) + return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); + else + return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); +} + +FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) +{ + return XXH_readLE32_align(ptr, endian, XXH_unaligned); +} + +static U32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} + +FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +{ + if (align==XXH_unaligned) + return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); + else + return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); +} + +FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) +{ + return XXH_readLE64_align(ptr, endian, XXH_unaligned); +} + +static U64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} + + +/* ************************************* +* Macros +***************************************/ +#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ + + +/* ************************************* +* Constants +***************************************/ +static const U32 PRIME32_1 = 2654435761U; +static const U32 PRIME32_2 = 2246822519U; +static const U32 PRIME32_3 = 3266489917U; +static const U32 PRIME32_4 = 668265263U; +static const U32 PRIME32_5 = 374761393U; + +static const U64 PRIME64_1 = 11400714785074694791ULL; +static const U64 PRIME64_2 = 14029467366897019727ULL; +static const U64 PRIME64_3 = 1609587929392839161ULL; +static const U64 PRIME64_4 = 9650029242287828579ULL; +static const U64 PRIME64_5 = 2870177450012600261ULL; + +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ************************** +* Utils +****************************/ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState) +{ + memcpy(dstState, srcState, sizeof(*dstState)); +} + +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState) +{ + memcpy(dstState, srcState, sizeof(*dstState)); +} + + +/* *************************** +* Simple Hash Functions +*****************************/ + +static U32 XXH32_round(U32 seed, U32 input) +{ + seed += input * PRIME32_2; + seed = XXH_rotl32(seed, 13); + seed *= PRIME32_1; + return seed; +} + +FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) +{ + const BYTE* p = (const BYTE*)input; + const BYTE* bEnd = p + len; + U32 h32; +#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) + +#ifdef XXH_ACCEPT_NULL_INPUT_POINTER + if (p==NULL) { + len=0; + bEnd=p=(const BYTE*)(size_t)16; + } +#endif + + if (len>=16) { + const BYTE* const limit = bEnd - 16; + U32 v1 = seed + PRIME32_1 + PRIME32_2; + U32 v2 = seed + PRIME32_2; + U32 v3 = seed + 0; + U32 v4 = seed - PRIME32_1; + + do { + v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4; + v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4; + v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4; + v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4; + } while (p<=limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + PRIME32_5; + } + + h32 += (U32) len; + + while (p+4<=bEnd) { + h32 += XXH_get32bits(p) * PRIME32_3; + h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; + p+=4; + } + + while (p> 15; + h32 *= PRIME32_2; + h32 ^= h32 >> 13; + h32 *= PRIME32_3; + h32 ^= h32 >> 16; + + return h32; +} + + +XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_CREATESTATE_STATIC(state); + XXH32_reset(state, seed); + XXH32_update(state, input, len); + return XXH32_digest(state); +#else + XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); + else + return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); + } } + + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); + else + return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); +#endif +} + + +static U64 XXH64_round(U64 acc, U64 input) +{ + acc += input * PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= PRIME64_1; + return acc; +} + +static U64 XXH64_mergeRound(U64 acc, U64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * PRIME64_1 + PRIME64_4; + return acc; +} + +FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) +{ + const BYTE* p = (const BYTE*)input; + const BYTE* const bEnd = p + len; + U64 h64; +#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) + +#ifdef XXH_ACCEPT_NULL_INPUT_POINTER + if (p==NULL) { + len=0; + bEnd=p=(const BYTE*)(size_t)32; + } +#endif + + if (len>=32) { + const BYTE* const limit = bEnd - 32; + U64 v1 = seed + PRIME64_1 + PRIME64_2; + U64 v2 = seed + PRIME64_2; + U64 v3 = seed + 0; + U64 v4 = seed - PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8; + v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8; + v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8; + v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8; + } while (p<=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 + PRIME64_5; + } + + h64 += (U64) len; + + while (p+8<=bEnd) { + U64 const k1 = XXH64_round(0, XXH_get64bits(p)); + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; + p+=8; + } + + if (p+4<=bEnd) { + h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; + h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; + p+=4; + } + + while (p> 33; + h64 *= PRIME64_2; + h64 ^= h64 >> 29; + h64 *= PRIME64_3; + h64 ^= h64 >> 32; + + return h64; +} + + +XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH64_CREATESTATE_STATIC(state); + XXH64_reset(state, seed); + XXH64_update(state, input, len); + return XXH64_digest(state); +#else + XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); + else + return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); + } } + + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); + else + return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); +#endif +} + + +/* ************************************************** +* Advanced Hash Functions +****************************************************/ + +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 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; +} + + +/*** Hash feed ***/ + +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed) +{ + XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ + memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */ + state.v1 = seed + PRIME32_1 + PRIME32_2; + state.v2 = seed + PRIME32_2; + state.v3 = seed + 0; + state.v4 = seed - PRIME32_1; + memcpy(statePtr, &state, sizeof(state)); + return XXH_OK; +} + + +XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed) +{ + XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ + memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */ + state.v1 = seed + PRIME64_1 + PRIME64_2; + state.v2 = seed + PRIME64_2; + state.v3 = seed + 0; + state.v4 = seed - PRIME64_1; + memcpy(statePtr, &state, sizeof(state)); + return XXH_OK; +} + + +FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) +{ + const BYTE* p = (const BYTE*)input; + const BYTE* const bEnd = p + len; + +#ifdef XXH_ACCEPT_NULL_INPUT_POINTER + if (input==NULL) return XXH_ERROR; +#endif + + state->total_len_32 += (unsigned)len; + state->large_len |= (len>=16) | (state->total_len_32>=16); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len); + state->memsize += (unsigned)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const U32* p32 = state->mem32; + state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++; + state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++; + state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++; + state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++; + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const BYTE* const limit = bEnd - 16; + U32 v1 = state->v1; + U32 v2 = state->v2; + U32 v3 = state->v3; + U32 v4 = state->v4; + + do { + v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4; + v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4; + v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4; + v4 = XXH32_round(v4, XXH_readLE32(p, endian)); 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 XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) +{ + XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH32_update_endian(state_in, input, len, XXH_littleEndian); + else + return XXH32_update_endian(state_in, input, len, XXH_bigEndian); +} + + + +FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) +{ + const BYTE * p = (const BYTE*)state->mem32; + const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize; + 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 */ + PRIME32_5; + } + + h32 += state->total_len_32; + + while (p+4<=bEnd) { + h32 += XXH_readLE32(p, endian) * PRIME32_3; + h32 = XXH_rotl32(h32, 17) * PRIME32_4; + p+=4; + } + + while (p> 15; + h32 *= PRIME32_2; + h32 ^= h32 >> 13; + h32 *= PRIME32_3; + h32 ^= h32 >> 16; + + return h32; +} + + +XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) +{ + XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH32_digest_endian(state_in, XXH_littleEndian); + else + return XXH32_digest_endian(state_in, XXH_bigEndian); +} + + + +/* **** XXH64 **** */ + +FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) +{ + const BYTE* p = (const BYTE*)input; + const BYTE* const bEnd = p + len; + +#ifdef XXH_ACCEPT_NULL_INPUT_POINTER + if (input==NULL) return XXH_ERROR; +#endif + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len); + state->memsize += (U32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian)); + state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian)); + state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian)); + state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian)); + p += 32-state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const BYTE* const limit = bEnd - 32; + U64 v1 = state->v1; + U64 v2 = state->v2; + U64 v3 = state->v3; + U64 v4 = state->v4; + + do { + v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8; + v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8; + v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8; + v4 = XXH64_round(v4, XXH_readLE64(p, endian)); 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 XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) +{ + XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH64_update_endian(state_in, input, len, XXH_littleEndian); + else + return XXH64_update_endian(state_in, input, len, XXH_bigEndian); +} + + + +FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) +{ + const BYTE * p = (const BYTE*)state->mem64; + const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize; + U64 h64; + + if (state->total_len >= 32) { + U64 const v1 = state->v1; + U64 const v2 = state->v2; + U64 const v3 = state->v3; + 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 + PRIME64_5; + } + + h64 += (U64) state->total_len; + + while (p+8<=bEnd) { + U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian)); + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; + p+=8; + } + + if (p+4<=bEnd) { + h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1; + h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; + p+=4; + } + + while (p> 33; + h64 *= PRIME64_2; + h64 ^= h64 >> 29; + h64 *= PRIME64_3; + h64 ^= h64 >> 32; + + return h64; +} + + +XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in) +{ + XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + + if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) + return XXH64_digest_endian(state_in, XXH_littleEndian); + else + return XXH64_digest_endian(state_in, XXH_bigEndian); +} + + +/* ************************** +* Canonical representation +****************************/ + +/*! Default XXH result types are basic unsigned 32 and 64 bits. +* The canonical representation follows human-readable write convention, aka big-endian (large digits first). +* These functions allow transformation of hash result into and from its canonical format. +* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs. +*/ + +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 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 XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} diff --git a/vendor/github.com/DataDog/zstd/xxhash.h b/vendor/github.com/DataDog/zstd/xxhash.h index 8675d59b..9bad1f59 100644 --- a/vendor/github.com/DataDog/zstd/xxhash.h +++ b/vendor/github.com/DataDog/zstd/xxhash.h @@ -1,37 +1,40 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * xxHash - Fast Hash algorithm - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - xxHash homepage: https://cyan4973.github.io/xxHash/ - * - xxHash source repository : https://github.com/Cyan4973/xxHash - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + xxHash - Extremely Fast Hash algorithm + Header File + Copyright (C) 2012-2016, Yann Collet. + + BSD 2-Clause License (http://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 source repository : https://github.com/Cyan4973/xxHash */ +/* Notice extracted from xxHash homepage : -#ifndef XXH_NO_XXH3 -# define XXH_NO_XXH3 -#endif - -#ifndef XXH_NAMESPACE -# define XXH_NAMESPACE ZSTD_ -#endif - -/*! - * @mainpage xxHash - * - * @file xxhash.h - * xxHash prototypes and implementation - */ -/* TODO: update */ -/* Notice extracted from xxHash homepage: - -xxHash is an extremely fast hash algorithm, running at RAM speed limits. +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) @@ -39,7 +42,7 @@ Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo Name Speed Q.Score Author xxHash 5.4 GB/s 10 CrapWow 3.2 GB/s 2 Andrew -MurmurHash 3a 2.7 GB/s 10 Austin Appleby +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 @@ -54,13 +57,8 @@ 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. +A 64-bits version, named XXH64, is available since r35. +It offers much better speed, but for 64-bits 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 @@ -70,34 +68,33 @@ XXH32 6.8 GB/s 6.0 GB/s extern "C" { #endif +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + + /* **************************** - * 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 +* Definitions +******************************/ +#include /* size_t */ +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; + + +/* **************************** +* API modifier +******************************/ +/** XXH_PRIVATE_API +* This is useful if you want to include xxhash functions in `static` mode +* in order to inline them, and remove their symbol from the public list. +* Methodology : +* #define XXH_PRIVATE_API +* #include "xxhash.h" +* `xxhash.c` is automatically included. +* It's not useful to compile and link it as a separate module anymore. +*/ +#ifdef XXH_PRIVATE_API +# ifndef XXH_STATIC_LINKING_ONLY +# define XXH_STATIC_LINKING_ONLY +# endif # if defined(__GNUC__) # define XXH_PUBLIC_API static __inline __attribute__((unused)) # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) @@ -105,205 +102,45 @@ extern "C" { # 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 +# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */ # endif +#else +# define XXH_PUBLIC_API /* do nothing */ +#endif /* XXH_PRIVATE_API */ - /* - * 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. - */ - /* Before that, we unconditionally #undef all symbols, - * in case they were already defined with XXH_NAMESPACE. - * They will then be redefined for XXH_INLINE_ALL - */ -# undef XXH_versionNumber - /* XXH32 */ -# undef XXH32 -# undef XXH32_createState -# undef XXH32_freeState -# undef XXH32_reset -# undef XXH32_update -# undef XXH32_digest -# undef XXH32_copyState -# undef XXH32_canonicalFromHash -# undef XXH32_hashFromCanonical - /* XXH64 */ -# undef XXH64 -# undef XXH64_createState -# undef XXH64_freeState -# undef XXH64_reset -# undef XXH64_update -# undef XXH64_digest -# undef XXH64_copyState -# undef XXH64_canonicalFromHash -# undef XXH64_hashFromCanonical - /* XXH3_64bits */ -# undef XXH3_64bits -# undef XXH3_64bits_withSecret -# undef XXH3_64bits_withSeed -# undef XXH3_64bits_withSecretandSeed -# undef XXH3_createState -# undef XXH3_freeState -# undef XXH3_copyState -# undef XXH3_64bits_reset -# undef XXH3_64bits_reset_withSeed -# undef XXH3_64bits_reset_withSecret -# undef XXH3_64bits_update -# undef XXH3_64bits_digest -# undef XXH3_generateSecret - /* XXH3_128bits */ -# undef XXH128 -# undef XXH3_128bits -# undef XXH3_128bits_withSeed -# undef XXH3_128bits_withSecret -# undef XXH3_128bits_reset -# undef XXH3_128bits_reset_withSeed -# undef XXH3_128bits_reset_withSecret -# undef XXH3_128bits_reset_withSecretandSeed -# undef XXH3_128bits_update -# undef XXH3_128bits_digest -# undef XXH128_isEqual -# undef XXH128_cmp -# undef XXH128_canonicalFromHash -# undef XXH128_hashFromCanonical - /* Finally, free the namespace itself */ -# undef XXH_NAMESPACE - - /* employ the namespace for XXH_INLINE_ALL */ -# define XXH_NAMESPACE XXH_INLINE_ - /* - * Some identifiers (enums, type names) are not symbols, - * but they must nonetheless be renamed to avoid redeclaration. - * Alternative solution: do not redeclare them. - * However, this requires some #ifdefs, and has a more dispersed impact. - * Meanwhile, renaming can be achieved in a single place. - */ -# define XXH_IPREF(Id) XXH_NAMESPACE ## 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 - +/*!XXH_NAMESPACE, aka Namespace Emulation : -/*! - * @defgroup public Public API - * Contains details on the public xxHash functions. - * @{ - */ -/* 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 +If you want to include _and expose_ xxHash functions from within your own library, +but also want to avoid symbol collisions with another library which also includes xxHash, -#ifdef XXH_DOXYGEN -/*! - * @brief Emulate a namespace by transparently prefixing all symbols. - * - * 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. - */ -# define XXH_NAMESPACE /* YOUR NAME HERE */ -# undef XXH_NAMESPACE -#endif +you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library +with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values). +Note that no change is required within the calling program as long as it includes `xxhash.h` : +regular symbol name 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 XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) # 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_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) -# 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_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) -# 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) -# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) -/* 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_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) -# 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_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) -# 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 @@ -311,5379 +148,158 @@ extern "C" { * Version ***************************************/ #define XXH_VERSION_MAJOR 0 -#define XXH_VERSION_MINOR 8 -#define XXH_VERSION_RELEASE 1 +#define XXH_VERSION_MINOR 6 +#define XXH_VERSION_RELEASE 2 #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) - -/*! - * @brief Obtains the xxHash version. - * - * This is mostly useful when xxHash is compiled as a shared library, - * since the returned value comes from the library, as opposed to header file. - * - * @return `XXH_VERSION_NUMBER` of the invoked library. - */ XXH_PUBLIC_API unsigned XXH_versionNumber (void); /* **************************** -* Common basic types +* Simple Hash Functions ******************************/ -#include /* size_t */ -typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; - - -/*-********************************************************************** -* 32-bit hash -************************************************************************/ -#if defined(XXH_DOXYGEN) /* Don't show include */ -/*! - * @brief An unsigned 32-bit integer. - * - * Not necessarily defined to `uint32_t` but functionally equivalent. - */ -typedef uint32_t XXH32_hash_t; - -#elif !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 - -/*! - * @} - * - * @defgroup xxh32_family XXH32 family - * @ingroup public - * Contains functions used in the classic 32-bit xxHash algorithm. - * - * @note - * XXH32 is useful for older platforms, with no or poor 64-bit performance. - * Note that @ref xxh3_family provides competitive speed - * for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results. - * - * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families - * @see @ref xxh32_impl for implementation details - * @{ - */ +typedef unsigned int XXH32_hash_t; +typedef unsigned long long XXH64_hash_t; + +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed); +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed); + +/*! +XXH32() : + Calculate the 32-bits 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 +XXH64() : + Calculate the 64-bits hash of sequence of length "len" stored at memory address "input". + "seed" can be used to alter the result predictably. + This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark). +*/ -/*! - * @brief Calculates the 32-bit hash of @p input using xxHash32. - * - * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s - * - * @param input The block of data to be hashed, at least @p length bytes in size. - * @param length The length of @p input, in bytes. - * @param seed The 32-bit seed to alter the hash's output predictably. - * - * @pre - * The memory between @p input and @p input + @p length must be valid, - * readable, contiguous memory. However, if @p length is `0`, @p input may be - * `NULL`. In C++, this also must be *TriviallyCopyable*. - * - * @return The calculated 32-bit hash value. - * - * @see - * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): - * Direct equivalents for the other variants of xxHash. - * @see - * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. - */ -XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); -/*! - * Streaming functions generate the xxHash value from an incremental 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()`. - * - * Example code for incrementally hashing a file: - * @code{.c} - * #include - * #include - * #define BUFFER_SIZE 256 - * - * // Note: XXH64 and XXH3 use the same interface. - * XXH32_hash_t - * hashFile(FILE* stream) - * { - * XXH32_state_t* state; - * unsigned char buf[BUFFER_SIZE]; - * size_t amt; - * XXH32_hash_t hash; - * - * state = XXH32_createState(); // Create a state - * assert(state != NULL); // Error check here - * XXH32_reset(state, 0xbaad5eed); // Reset state with our seed - * while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) { - * XXH32_update(state, buf, amt); // Hash the file in chunks - * } - * hash = XXH32_digest(state); // Finalize the hash - * XXH32_freeState(state); // Clean up - * return hash; - * } - * @endcode - */ +/* **************************** +* Streaming Hash Functions +******************************/ +typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ -/*! - * @typedef struct XXH32_state_s XXH32_state_t - * @brief The opaque state struct for the XXH32 streaming API. - * - * @see XXH32_state_s for details. - */ -typedef struct XXH32_state_s XXH32_state_t; +/*! State allocation, compatible with dynamic libraries */ -/*! - * @brief Allocates an @ref XXH32_state_t. - * - * Must be freed with XXH32_freeState(). - * @return An allocated XXH32_state_t on success, `NULL` on failure. - */ XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); -/*! - * @brief Frees an @ref XXH32_state_t. - * - * Must be allocated with XXH32_createState(). - * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). - * @return XXH_OK. - */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); -/*! - * @brief Copies one @ref XXH32_state_t to another. - * - * @param dst_state The state to copy to. - * @param src_state The state to copy from. - * @pre - * @p dst_state and @p src_state must not be `NULL` and must not overlap. - */ -XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); -/*! - * @brief Resets an @ref XXH32_state_t to begin a new hash. - * - * This function resets and seeds a state. Call it before @ref XXH32_update(). - * - * @param statePtr The state struct to reset. - * @param seed The 32-bit seed to alter the hash result predictably. - * - * @pre - * @p statePtr must not be `NULL`. - * - * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. - */ -XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); -/*! - * @brief Consumes a block of @p input to an @ref XXH32_state_t. - * - * Call this to incrementally consume blocks of data. - * - * @param statePtr The state struct to update. - * @param input The block of data to be hashed, at least @p length bytes in size. - * @param length The length of @p input, in bytes. - * - * @pre - * @p statePtr must not be `NULL`. - * @pre - * The memory between @p input and @p input + @p length must be valid, - * readable, contiguous memory. However, if @p length is `0`, @p input may be - * `NULL`. In C++, this also must be *TriviallyCopyable*. - * - * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. - */ -XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); -/*! - * @brief Returns the calculated hash value from an @ref XXH32_state_t. - * - * @note - * Calling XXH32_digest() will not affect @p statePtr, so you can update, - * digest, and update again. - * - * @param statePtr The state struct to calculate the hash from. - * - * @pre - * @p statePtr must not be `NULL`. - * - * @return The calculated xxHash32 value from that state. - */ +/* hash streaming */ + +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int 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 *******/ +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long 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); /* - * 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. - */ - -/*! - * @brief Canonical (big endian) representation of @ref XXH32_hash_t. - */ -typedef struct { - unsigned char digest[4]; /*!< Hash bytes, big endian */ -} XXH32_canonical_t; - -/*! - * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. - * - * @param dst The @ref XXH32_canonical_t pointer to be stored to. - * @param hash The @ref XXH32_hash_t to be converted. - * - * @pre - * @p dst must not be `NULL`. - */ -XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); +These functions generate the xxHash of an input provided in multiple segments. +Note that, for small input, they are slower than single-call functions, due to state management. +For small input, prefer `XXH32()` and `XXH64()` . -/*! - * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. - * - * @param src The @ref XXH32_canonical_t to convert. - * - * @pre - * @p src must not be `NULL`. - * - * @return The converted hash. - */ -XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); +XXH state must first be allocated, using XXH*_createState() . +Start a new hash by initializing state with a seed, using XXH*_reset(). -#ifdef __has_attribute -# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) -#else -# define XXH_HAS_ATTRIBUTE(x) 0 -#endif +Then, feed the hash state by calling XXH*_update() as many times as necessary. +Obviously, input must be allocated and read accessible. +The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. -/* C-language Attributes are added in C23. */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) -# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) -#else -# define XXH_HAS_C_ATTRIBUTE(x) 0 -#endif +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. -#if defined(__cplusplus) && defined(__has_cpp_attribute) -# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define XXH_HAS_CPP_ATTRIBUTE(x) 0 -#endif +It's still possible to continue inserting input into the hash state after a digest, +and generate some new hashes later on, by calling again XXH*_digest(). -/* -Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute -introduced in CPP17 and C23. -CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough -C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough +When done, free XXH state space if it was allocated dynamically. */ -#if XXH_HAS_C_ATTRIBUTE(x) -# define XXH_FALLTHROUGH [[fallthrough]] -#elif XXH_HAS_CPP_ATTRIBUTE(x) -# define XXH_FALLTHROUGH [[fallthrough]] -#elif XXH_HAS_ATTRIBUTE(__fallthrough__) -# define XXH_FALLTHROUGH __attribute__ ((fallthrough)) -#else -# define XXH_FALLTHROUGH -#endif -/*! - * @} - * @ingroup public - * @{ - */ -#ifndef XXH_NO_LONG_LONG -/*-********************************************************************** -* 64-bit hash -************************************************************************/ -#if defined(XXH_DOXYGEN) /* don't include */ -/*! - * @brief An unsigned 64-bit integer. - * - * Not necessarily defined to `uint64_t` but functionally equivalent. - */ -typedef uint64_t XXH64_hash_t; -#elif !defined (__VMS) \ - && (defined (__cplusplus) \ - || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include - typedef uint64_t XXH64_hash_t; -#else -# include -# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL - /* LP64 ABI says uint64_t is unsigned long */ - typedef unsigned long XXH64_hash_t; -# else - /* the following type must have a width of 64-bit */ - typedef unsigned long long XXH64_hash_t; -# endif +/* ************************** +* Utils +****************************/ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* ! C99 */ +# define restrict /* disable restrict */ #endif -/*! - * @} - * - * @defgroup xxh64_family XXH64 family - * @ingroup public - * @{ - * Contains functions used in the classic 64-bit xxHash algorithm. - * - * @note - * XXH3 provides competitive speed for both 32-bit and 64-bit systems, - * and offers true 64/128 bit hash results. - * It provides better speed for systems with vector processing capabilities. - */ - - -/*! - * @brief Calculates the 64-bit hash of @p input using xxHash64. - * - * This function usually runs faster on 64-bit systems, but slower on 32-bit - * systems (see benchmark). - * - * @param input The block of data to be hashed, at least @p length bytes in size. - * @param length The length of @p input, in bytes. - * @param seed The 64-bit seed to alter the hash's output predictably. - * - * @pre - * The memory between @p input and @p input + @p length must be valid, - * readable, contiguous memory. However, if @p length is `0`, @p input may be - * `NULL`. In C++, this also must be *TriviallyCopyable*. - * - * @return The calculated 64-bit hash. - * - * @see - * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): - * Direct equivalents for the other variants of xxHash. - * @see - * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. - */ -XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed); +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state); +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state); -/******* Streaming *******/ -/*! - * @brief The opaque state struct for the XXH64 streaming API. - * - * @see XXH64_state_s for details. - */ -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 +****************************/ +/* Default result type for XXH functions are primitive unsigned 32 and 64 bits. +* The canonical representation uses human-readable write convention, aka big-endian (large digits first). +* These functions allow transformation of hash result into and from its canonical format. +* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs. +*/ +typedef struct { unsigned char digest[4]; } XXH32_canonical_t; +typedef struct { unsigned char digest[8]; } XXH64_canonical_t; -/******* Canonical representation *******/ -typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); 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); - -#ifndef XXH_NO_XXH3 -/*! - * @} - * ************************************************************************ - * @defgroup xxh3_family XXH3 family - * @ingroup public - * @{ - * - * XXH3 is a more recent 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 - * - * Compared to XXH64, expect XXH3 to run approximately - * ~2x faster on large inputs and >3x faster on small ones, - * exact differences vary depending on platform. - * - * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, - * but does not require it. - * Any 32-bit and 64-bit targets that can run XXH32 smoothly - * can run XXH3 at competitive speeds, even without vector support. - * 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 via the XXH_VECTOR macro. - * - * XXH3 implementation is portable: - * it has a generic C90 formulation that can be compiled on any platform, - * all implementations generage exactly the same hash value on all platforms. - * Starting from v0.8.0, it's also labelled "stable", meaning that - * any future version will also generate the same hash value. - * - * XXH3 offers 2 variants, _64bits and _128bits. - * - * When only 64 bits are needed, prefer invoking 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 API supports one-shot hashing, streaming mode, and custom secrets. - */ - -/*-********************************************************************** -* XXH3 64-bit variant -************************************************************************/ - -/* 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); - -/*! - * The bare minimum size for a custom secret. - * - * @see - * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), - * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). - */ -#define XXH3_SECRET_SIZE_MIN 136 - -/* - * 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 the secret impacts the dispersion of the hash algorithm. - * Therefore, the secret _must_ look like a bunch of random bytes. - * Avoid "trivial" or structured data such as repeated sequences or a text document. - * Whenever in doubt about the "randomness" of the blob of bytes, - * consider employing "XXH3_generateSecret()" instead (see below). - * It will generate a proper high entropy secret derived from the blob of bytes. - * Another advantage of using XXH3_generateSecret() is that - * it guarantees that all bits within the initial blob of bytes - * will impact every bit of the output. - * This is not necessarily the case when using the blob of bytes directly - * because, when hashing _small_ inputs, only a portion of the secret is employed. - */ -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. - */ - -/*! - * @brief The state struct for the XXH3 streaming API. - * - * @see XXH3_state_s for details. - */ -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 -************************************************************************/ -/*! - * @brief The return value from 128-bit hashes. - * - * Stored in little endian order, although the fields themselves are in native - * endianness. - */ -typedef struct { - XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ - XXH64_hash_t high64; /*!< `value >> 64` */ -} 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_XXH3 */ -#endif /* XXH_NO_LONG_LONG */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); -/*! - * @} - */ #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. - */ - -/*! - * @internal - * @brief Structure for XXH32 streaming API. - * - * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, - * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is - * an opaque type. This allows fields to safely be changed. - * - * Typedef'd to @ref XXH32_state_t. - * Do not access the members of this struct directly. - * @see XXH64_state_s, XXH3_state_s - */ -struct XXH32_state_s { - XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ - XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ - XXH32_hash_t v[4]; /*!< Accumulator lanes */ - XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ - XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ - XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ -}; /* typedef'd to XXH32_state_t */ - - -#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ - -/*! - * @internal - * @brief Structure for XXH64 streaming API. - * - * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, - * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is - * an opaque type. This allows fields to safely be changed. - * - * Typedef'd to @ref XXH64_state_t. - * Do not access the members of this struct directly. - * @see XXH32_state_s, XXH3_state_s - */ -struct XXH64_state_s { - XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ - XXH64_hash_t v[4]; /*!< Accumulator lanes */ - XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ - XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ - XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ - XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ -}; /* typedef'd to XXH64_state_t */ - - -#ifndef XXH_NO_XXH3 - -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ -# include -# define XXH_ALIGN(n) alignas(n) -#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ -/* In C++ alignas() is a keyword */ -# 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(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ - && defined(__GNUC__) -# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) -#else -# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type -#endif - -/*! - * @brief The size of the internal XXH3 buffer. - * - * This is the optimal update size for incremental hashing. - * - * @see XXH3_64b_update(), XXH3_128b_update(). - */ -#define XXH3_INTERNALBUFFER_SIZE 256 - -/*! - * @brief Default size of the secret buffer (and @ref XXH3_kSecret). - * - * This is the size used in @ref XXH3_kSecret and the seeded functions. - * - * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. - */ -#define XXH3_SECRET_DEFAULT_SIZE 192 - -/*! - * @internal - * @brief Structure for XXH3 streaming API. - * - * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, - * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. - * Otherwise it is an opaque type. - * Never use this definition in combination with dynamic library. - * This allows fields to safely be changed in the future. - * - * @note ** This structure has a strict alignment requirement of 64 bytes!! ** - * Do not allocate this with `malloc()` or `new`, - * it will not be sufficiently aligned. - * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. - * - * Typedef'd to @ref XXH3_state_t. - * Do never access the members of this struct directly. - * - * @see XXH3_INITSTATE() for stack initialization. - * @see XXH3_createState(), XXH3_freeState(). - * @see XXH32_state_s, XXH64_state_s - */ -struct XXH3_state_s { - XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); - /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */ - XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); - /*!< Used to store a custom secret generated from a seed. */ - XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); - /*!< The internal buffer. @see XXH32_state_s::mem32 */ - XXH32_hash_t bufferedSize; - /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ - XXH32_hash_t useSeed; - /*!< Reserved field. Needed for padding on 64-bit. */ - size_t nbStripesSoFar; - /*!< Number or stripes processed. */ - XXH64_hash_t totalLen; - /*!< Total length hashed. 64-bit even on 32-bit targets. */ - size_t nbStripesPerBlock; - /*!< Number of stripes per block. */ - size_t secretLimit; - /*!< Size of @ref customSecret or @ref extSecret */ - XXH64_hash_t seed; - /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ - XXH64_hash_t reserved64; - /*!< Reserved field. */ - const unsigned char* extSecret; - /*!< Reference to an external secret for the _withSecret variants, NULL - * for other variants. */ - /* 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 - -/*! - * @brief Initializes a stack-allocated `XXH3_state_s`. - * - * When the @ref 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; } - - -/* XXH128() : - * simple alias to pre-selected XXH3_128bits variant - */ -XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); - - -/* === 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 @secretSize - * into an already allocated buffer @secretBuffer. - * @secretSize must be >= XXH3_SECRET_SIZE_MIN - * - * 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 large enough 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 - * XXH3_generateSecret() can be employed to ensure proper quality. - * - * customSeed can be anything. It can have any size, even small ones, - * and its content can be anything, even "poor entropy" sources such as a bunch of zeroes. - * The resulting `secret` will nonetheless provide all required qualities. - * - * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. - */ -XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize); - - -/* - * XXH3_generateSecret_fromSeed(): - * - * Generate the same secret as the _withSeed() variants. - * - * The resulting secret has a length of XXH3_SECRET_DEFAULT_SIZE (necessarily). - * @secretBuffer must be already allocated, of size at least XXH3_SECRET_DEFAULT_SIZE bytes. - * - * The generated secret can be used in combination with - *`*_withSecret()` and `_withSecretandSeed()` variants. - * This generator is notably useful in combination with `_withSecretandSeed()`, - * as a way to emulate a faster `_withSeed()` variant. - */ -XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed); - -/* - * *_withSecretandSeed() : - * These variants generate hash values using either - * @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) - * or @secret for "large" keys (>= XXH3_MIDSIZE_MAX). - * - * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. - * `_withSeed()` has to generate the secret on the fly for "large" keys. - * It's fast, but can be perceptible for "not so large" keys (< 1 KB). - * `_withSecret()` has to generate the masks on the fly for "small" keys, - * which requires more instructions than _withSeed() variants. - * Therefore, _withSecretandSeed variant combines the best of both worlds. - * - * When @secret has been generated by XXH3_generateSecret_fromSeed(), - * this variant produces *exactly* the same results as `_withSeed()` variant, - * hence offering only a pure speed benefit on "large" input, - * by skipping the need to regenerate the secret for every large input. - * - * Another usage scenario is to hash the secret to a 64-bit hash value, - * for example with XXH3_64bits(), which then becomes the seed, - * and then employ both the seed and the secret in _withSecretandSeed(). - * On top of speed, an added benefit is that each bit in the secret - * has a 50% chance to swap each bit in the output, - * via its impact to the seed. - * This is not guaranteed when using the secret directly in "small data" scenarios, - * because only portions of the secret are employed for small data. - */ -XXH_PUBLIC_API XXH64_hash_t -XXH3_64bits_withSecretandSeed(const void* data, size_t len, - const void* secret, size_t secretSize, - XXH64_hash_t seed); - -XXH_PUBLIC_API XXH128_hash_t -XXH3_128bits_withSecretandSeed(const void* data, size_t len, - const void* secret, size_t secretSize, - XXH64_hash_t seed64); - -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, - const void* secret, size_t secretSize, - XXH64_hash_t seed64); - -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, - const void* secret, size_t secretSize, - XXH64_hash_t seed64); - - -#endif /* XXH_NO_XXH3 */ -#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 -***************************************/ - -/*! - * @defgroup tuning Tuning parameters - * @{ - * - * Various macros to control xxHash's behavior. - */ -#ifdef XXH_DOXYGEN -/*! - * @brief Define this to disable 64-bit code. - * - * Useful if only using the @ref xxh32_family and you have a strict C90 compiler. - */ -# define XXH_NO_LONG_LONG -# undef XXH_NO_LONG_LONG /* don't actually */ -/*! - * @brief Controls how unaligned memory is accessed. - * - * 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. - * - * @par Possible options: - * - * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` - * @par - * Use `memcpy()`. Safe and portable. Note that most modern compilers will - * eliminate the function call and treat it as an unaligned access. - * - * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))` - * @par - * 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`. - * - * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast - * @par - * Casts directly and dereferences. This method doesn't depend on the - * compiler, but it violates the C standard as it directly dereferences an - * unaligned pointer. 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. - * - * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift - * @par - * Also portable. 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. However, some compilers - * will emit literal byteshifts even if the target supports unaligned access. - * . - * - * @warning - * Methods 1 and 2 rely on implementation-defined behavior. Use these with - * care, as what works on one compiler/platform/optimization level may cause - * another to read garbage data or even crash. - * - * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. - * - * Prefer these methods in priority order (0 > 3 > 1 > 2) - */ -# define XXH_FORCE_MEMORY_ACCESS 0 - -/*! - * @def XXH_FORCE_ALIGN_CHECK - * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() - * and XXH64() only). - * - * 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 reads, 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 an additional code path if memory - * access uses the same instruction for both aligned and unaligned - * addresses (e.g. x86 and aarch64). - * - * 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). - */ -# define XXH_FORCE_ALIGN_CHECK 0 - -/*! - * @def XXH_NO_INLINE_HINTS - * @brief When non-zero, sets all functions to `static`. - * - * 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. - */ -# define XXH_NO_INLINE_HINTS 0 - -/*! - * @def XXH32_ENDJMP - * @brief Whether to use a jump for `XXH32_finalize`. - * - * For performance, `XXH32_finalize` uses multiple branches in the finalizer. - * This is generally preferable for performance, - * but depending on exact architecture, a jmp may be preferable. - * - * This setting is only possibly making a difference for very small inputs. - */ -# define XXH32_ENDJMP 0 - -/*! - * @internal - * @brief Redefines old internal names. - * - * For compatibility with code that uses xxHash's internals before the names - * were changed to improve namespacing. There is no other reason to use this. - */ -# define XXH_OLD_NAMES -# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ -#endif /* XXH_DOXYGEN */ -/*! - * @} - */ - -#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ - /* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */ -# if !defined(__clang__) && \ -( \ - (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ - ( \ - defined(__GNUC__) && ( \ - (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \ - ( \ - defined(__mips__) && \ - (__mips <= 5 || __mips_isa_rev < 6) && \ - (!defined(__mips16) || defined(__mips_mips16e2)) \ - ) \ - ) \ - ) \ -) -# define XXH_FORCE_MEMORY_ACCESS 1 -# endif -#endif - -#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 - -#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 +/* ================================================================================================ + This section contains definitions which are not guaranteed to remain stable. + They may change in future versions, becoming incompatible with a different version of the library. + They shall only be used with static linking. + Never use these definitions in association with dynamic linking ! +=================================================================================================== */ +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345) +#define XXH_STATIC_H_3543687687345 + +/* These definitions are only meant to allow allocation of XXH state + statically, on stack, or in a struct for example. + Do not use members directly. */ + + struct XXH32_state_s { + unsigned total_len_32; + unsigned large_len; + unsigned v1; + unsigned v2; + unsigned v3; + unsigned v4; + unsigned mem32[4]; /* buffer defined as U32 for alignment */ + unsigned memsize; + unsigned reserved; /* never read nor write, will be removed in a future version */ + }; /* typedef'd to XXH32_state_t */ + + struct XXH64_state_s { + unsigned long long total_len; + unsigned long long v1; + unsigned long long v2; + unsigned long long v3; + unsigned long long v4; + unsigned long long mem64[4]; /* buffer defined as U64 for alignment */ + unsigned memsize; + unsigned reserved[2]; /* never read nor write, will be removed in a future version */ + }; /* typedef'd to XXH64_state_t */ + + +# ifdef XXH_PRIVATE_API +# include "xxhash.c" /* include xxhash functions as `static`, for inlining */ # endif -#endif - -#ifndef XXH32_ENDJMP -/* generally preferable for performance */ -# define XXH32_ENDJMP 0 -#endif - -/*! - * @defgroup impl Implementation - * @{ - */ +#endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */ -/* ************************************* -* Includes & Memory related functions -***************************************/ -/* Modify the local functions below should you wish to use some other memory routines */ -/* for ZSTD_malloc(), ZSTD_free() */ -#define ZSTD_DEPS_NEED_MALLOC -#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */ -static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); } -static void XXH_free (void* p) { ZSTD_free(p); } -static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); } - - -/* ************************************* -* 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__) || defined(__clang__) -# define XXH_FORCE_INLINE static __attribute__((unused)) -# else -# define XXH_FORCE_INLINE static -# endif -# define XXH_NO_INLINE static -/* enable inlining hints */ -#elif defined(__GNUC__) || defined(__clang__) -# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) -# define XXH_NO_INLINE static __attribute__((noinline)) -#elif defined(_MSC_VER) /* Visual Studio */ -# define XXH_FORCE_INLINE static __forceinline -# define XXH_NO_INLINE static __declspec(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 +#if defined (__cplusplus) +} #endif - - - -/* ************************************* -* Debug -***************************************/ -/*! - * @ingroup tuning - * @def XXH_DEBUGLEVEL - * @brief Sets the debugging level. - * - * 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 */ -#ifndef XXH_STATIC_ASSERT -# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ -# include -# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) -# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ -# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) -# else -# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) -# endif -# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) -#endif - -/*! - * @internal - * @def XXH_COMPILER_GUARD(var) - * @brief Used to prevent unwanted optimizations for @p var. - * - * It uses an empty GCC inline assembly statement with a register constraint - * which forces @p var into a general purpose register (e.g. eax, ebx, ecx - * on x86) and marks it as modified. - * - * This is used in a few places to avoid unwanted autovectorization (e.g. - * XXH32_round()). All vectorization we want is explicit via intrinsics, - * and _usually_ isn't wanted elsewhere. - * - * We also use it to prevent unwanted constant folding for AArch64 in - * XXH3_initCustomSecret_scalar(). - */ -#if defined(__GNUC__) || defined(__clang__) -# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var)) -#else -# define XXH_COMPILER_GUARD(var) ((void)0) -#endif - -/* ************************************* -* 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 *** */ - -/*! - * @internal - * @fn xxh_u32 XXH_read32(const void* ptr) - * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. - * - * Affected by @ref XXH_FORCE_MEMORY_ACCESS. - * - * @param ptr The pointer to read from. - * @return The 32-bit native endian integer from the bytes at @p ptr. - */ - -/*! - * @internal - * @fn xxh_u32 XXH_readLE32(const void* ptr) - * @brief Reads an unaligned 32-bit little endian integer from @p ptr. - * - * Affected by @ref XXH_FORCE_MEMORY_ACCESS. - * - * @param ptr The pointer to read from. - * @return The 32-bit little endian integer from the bytes at @p ptr. - */ - -/*! - * @internal - * @fn xxh_u32 XXH_readBE32(const void* ptr) - * @brief Reads an unaligned 32-bit big endian integer from @p ptr. - * - * Affected by @ref XXH_FORCE_MEMORY_ACCESS. - * - * @param ptr The pointer to read from. - * @return The 32-bit big endian integer from the bytes at @p ptr. - */ - -/*! - * @internal - * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) - * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. - * - * Affected by @ref XXH_FORCE_MEMORY_ACCESS. - * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is - * always @ref XXH_alignment::XXH_unaligned. - * - * @param ptr The pointer to read from. - * @param align Whether @p ptr is aligned. - * @pre - * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte - * aligned. - * @return The 32-bit little endian integer from the bytes at @p ptr. - */ - -#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://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html - */ -static xxh_u32 XXH_read32(const void* memPtr) -{ - xxh_u32 val; - XXH_memcpy(&val, memPtr, sizeof(val)); - return val; -} - -#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ - - -/* *** Endianness *** */ - -/*! - * @ingroup tuning - * @def XXH_CPU_LITTLE_ENDIAN - * @brief Whether the target is 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. - * - * @note - * This is not necessarily defined to an integer constant. - * - * @see XXH_isLittleEndian() for the runtime check. - */ -#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 -/*! - * @internal - * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. - * - * Most compilers will constant fold this. - */ -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 - -/*! - * @internal - * @def XXH_rotl32(x,r) - * @brief 32-bit rotate left. - * - * @param x The 32-bit integer to be rotated. - * @param r The number of bits to rotate. - * @pre - * @p r > 0 && @p r < 32 - * @note - * @p x and @p r may be evaluated multiple times. - * @return The rotated result. - */ -#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 - -/*! - * @internal - * @fn xxh_u32 XXH_swap32(xxh_u32 x) - * @brief A 32-bit byteswap. - * - * @param x The 32-bit integer to byteswap. - * @return @p x, byteswapped. - */ -#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 -*****************************/ - -/*! - * @internal - * @brief Enum to indicate whether a pointer is aligned. - */ -typedef enum { - XXH_aligned, /*!< Aligned */ - XXH_unaligned /*!< Possibly 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 -***************************************/ -/*! @ingroup public */ -XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } - - -/* ******************************************************************* -* 32-bit hash functions -*********************************************************************/ -/*! - * @} - * @defgroup xxh32_impl XXH32 implementation - * @ingroup impl - * @{ - */ - /* #define instead of static const, to be used as initializers */ -#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ -#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ -#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ -#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ -#define 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 - -/*! - * @internal - * @brief Normal stripe processing routine. - * - * This shuffles the bits so that any bit from @p input impacts several bits in - * @p acc. - * - * @param acc The accumulator lane. - * @param input The stripe of input to mix. - * @return The mixed accumulator lane. - */ -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(__SSE4_1__) || defined(__aarch64__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) - /* - * UGLY HACK: - * A compiler fence is the only thing that prevents GCC and Clang from - * autovectorizing the XXH32 loop (pragmas and attributes don't work for some - * reason) 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. - * - * This is also enabled on AArch64, as Clang autovectorizes it incorrectly - * and it is pointless writing a NEON implementation that is basically the - * same speed as scalar for XXH32. - */ - XXH_COMPILER_GUARD(acc); -#endif - return acc; -} - -/*! - * @internal - * @brief Mixes all bits to finalize the hash. - * - * The final mix ensures that all input bits have a chance to impact any bit in - * the output digest, resulting in an unbiased distribution. - * - * @param h32 The hash to avalanche. - * @return The avalanched hash. - */ -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) - -/*! - * @internal - * @brief Processes the last 0-15 bytes of @p ptr. - * - * There may be up to 15 bytes remaining to consume from the input. - * This final stage will digest them to ensure that all input bytes are present - * in the final mix. - * - * @param h32 The hash to finalize. - * @param ptr The pointer to the remaining input. - * @param len The remaining length, modulo 16. - * @param align Whether @p ptr is aligned. - * @return The finalized hash. - */ -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) - - if (ptr==NULL) XXH_ASSERT(len == 0); - - /* Compact rerolled version; generally faster */ - if (!XXH32_ENDJMP) { - 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; - XXH_FALLTHROUGH; - case 8: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 4: XXH_PROCESS4; - return XXH32_avalanche(h32); - - case 13: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 9: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 5: XXH_PROCESS4; - XXH_PROCESS1; - return XXH32_avalanche(h32); - - case 14: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 10: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 6: XXH_PROCESS4; - XXH_PROCESS1; - XXH_PROCESS1; - return XXH32_avalanche(h32); - - case 15: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 11: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 7: XXH_PROCESS4; - XXH_FALLTHROUGH; - case 3: XXH_PROCESS1; - XXH_FALLTHROUGH; - case 2: XXH_PROCESS1; - XXH_FALLTHROUGH; - case 1: XXH_PROCESS1; - XXH_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 - -/*! - * @internal - * @brief The implementation for @ref XXH32(). - * - * @param input , len , seed Directly passed from @ref XXH32(). - * @param align Whether @p input is aligned. - * @return The calculated hash. - */ -XXH_FORCE_INLINE xxh_u32 -XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) -{ - xxh_u32 h32; - - if (input==NULL) XXH_ASSERT(len == 0); - - if (len>=16) { - const xxh_u8* const bEnd = input + len; - 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); -} - -/*! @ingroup xxh32_family */ -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 *******/ -/*! - * @ingroup xxh32_family - */ -XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) -{ - return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); -} -/*! @ingroup xxh32_family */ -XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) -{ - XXH_free(statePtr); - return XXH_OK; -} - -/*! @ingroup xxh32_family */ -XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) -{ - XXH_memcpy(dstState, srcState, sizeof(*dstState)); -} - -/*! @ingroup xxh32_family */ -XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) -{ - XXH_ASSERT(statePtr != NULL); - memset(statePtr, 0, sizeof(*statePtr)); - statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; - statePtr->v[1] = seed + XXH_PRIME32_2; - statePtr->v[2] = seed + 0; - statePtr->v[3] = seed - XXH_PRIME32_1; - return XXH_OK; -} - - -/*! @ingroup xxh32_family */ -XXH_PUBLIC_API XXH_errorcode -XXH32_update(XXH32_state_t* state, const void* input, size_t len) -{ - if (input==NULL) { - XXH_ASSERT(len == 0); - return XXH_OK; - } - - { 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->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; - state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; - state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; - state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); - } - p += 16-state->memsize; - state->memsize = 0; - } - - if (p <= bEnd-16) { - const xxh_u8* const limit = bEnd - 16; - - do { - state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; - state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; - state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; - state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; - } while (p<=limit); - - } - - if (p < bEnd) { - XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); - state->memsize = (unsigned)(bEnd-p); - } - } - - return XXH_OK; -} - - -/*! @ingroup xxh32_family */ -XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) -{ - xxh_u32 h32; - - if (state->large_len) { - h32 = XXH_rotl32(state->v[0], 1) - + XXH_rotl32(state->v[1], 7) - + XXH_rotl32(state->v[2], 12) - + XXH_rotl32(state->v[3], 18); - } else { - h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; - } - - h32 += state->total_len_32; - - return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); -} - - -/******* Canonical representation *******/ - -/*! - * @ingroup xxh32_family - * 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); - XXH_memcpy(dst, &hash, sizeof(*dst)); -} -/*! @ingroup xxh32_family */ -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 -*********************************************************************/ -/*! - * @} - * @ingroup impl - * @{ - */ -/******* Memory access *******/ - -typedef XXH64_hash_t xxh_u64; - -#ifdef XXH_OLD_NAMES -# define U64 xxh_u64 -#endif - -#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://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html - */ -static xxh_u64 XXH_read64(const void* memPtr) -{ - xxh_u64 val; - XXH_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 *******/ -/*! - * @} - * @defgroup xxh64_impl XXH64 implementation - * @ingroup impl - * @{ - */ -/* #define rather that static const, to be used as initializers */ -#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ -#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ -#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ -#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ -#define 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) -{ - if (ptr==NULL) XXH_ASSERT(len == 0); - len &= 31; - while (len >= 8) { - 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; - len -= 8; - } - if (len >= 4) { - h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; - ptr += 4; - h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; - len -= 4; - } - while (len > 0) { - h64 ^= (*ptr++) * XXH_PRIME64_5; - h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; - --len; - } - return XXH64_avalanche(h64); -} - -#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) -{ - xxh_u64 h64; - if (input==NULL) XXH_ASSERT(len == 0); - - if (len>=32) { - const xxh_u8* const bEnd = input + len; - const xxh_u8* const limit = bEnd - 31; - 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 (inputv[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; - statePtr->v[1] = seed + XXH_PRIME64_2; - statePtr->v[2] = seed + 0; - statePtr->v[3] = seed - XXH_PRIME64_1; - return XXH_OK; -} - -/*! @ingroup xxh64_family */ -XXH_PUBLIC_API XXH_errorcode -XXH64_update (XXH64_state_t* state, const void* input, size_t len) -{ - if (input==NULL) { - XXH_ASSERT(len == 0); - return XXH_OK; - } - - { 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->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); - state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); - state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); - state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); - p += 32 - state->memsize; - state->memsize = 0; - } - - if (p+32 <= bEnd) { - const xxh_u8* const limit = bEnd - 32; - - do { - state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; - state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; - state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; - state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; - } while (p<=limit); - - } - - if (p < bEnd) { - XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); - state->memsize = (unsigned)(bEnd-p); - } - } - - return XXH_OK; -} - - -/*! @ingroup xxh64_family */ -XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state) -{ - xxh_u64 h64; - - if (state->total_len >= 32) { - h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); - h64 = XXH64_mergeRound(h64, state->v[0]); - h64 = XXH64_mergeRound(h64, state->v[1]); - h64 = XXH64_mergeRound(h64, state->v[2]); - h64 = XXH64_mergeRound(h64, state->v[3]); - } else { - h64 = state->v[2] /*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 *******/ - -/*! @ingroup xxh64_family */ -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); - XXH_memcpy(dst, &hash, sizeof(*dst)); -} - -/*! @ingroup xxh64_family */ -XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) -{ - return XXH_readBE64(src); -} - -#ifndef XXH_NO_XXH3 - -/* ********************************************************************* -* XXH3 -* New generation hash designed for speed on small keys and vectorization -************************************************************************ */ -/*! - * @} - * @defgroup xxh3_impl XXH3 implementation - * @ingroup impl - * @{ - */ - -/* === Compiler specifics === */ - -#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ -# define XXH_RESTRICT /* disable */ -#elif 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__) || defined(__clang__) -# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ - || defined(__aarch64__) || defined(_M_ARM) \ - || defined(_M_ARM64) || defined(_M_ARM64EC) -# define inline __inline__ /* circumvent a clang bug */ -# include -# undef inline -# elif defined(__AVX2__) -# include -# elif defined(__SSE2__) -# include -# endif -#endif - -#if 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 - * ========================================== */ - -#ifdef XXH_DOXYGEN -/*! - * @ingroup tuning - * @brief Overrides the vectorization implementation chosen for XXH3. - * - * Can be defined to 0 to disable SIMD or any of the values mentioned in - * @ref XXH_VECTOR_TYPE. - * - * If this is not defined, it uses predefined macros to determine the best - * implementation. - */ -# define XXH_VECTOR XXH_SCALAR -/*! - * @ingroup tuning - * @brief Possible values for @ref XXH_VECTOR. - * - * Note that these are actually implemented as macros. - * - * If this is not defined, it is detected automatically. - * @ref XXH_X86DISPATCH overrides this. - */ -enum XXH_VECTOR_TYPE /* fake enum */ { - XXH_SCALAR = 0, /*!< Portable scalar version */ - XXH_SSE2 = 1, /*!< - * SSE2 for Pentium 4, Opteron, all x86_64. - * - * @note SSE2 is also guaranteed on Windows 10, macOS, and - * Android x86. - */ - XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ - XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ - XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */ - XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ -}; -/*! - * @ingroup tuning - * @brief Selects the minimum alignment for XXH3's accumulators. - * - * When using SIMD, this should match the alignment required for said vector - * type, so, for example, 32 for AVX2. - * - * Default: Auto detected. - */ -# define XXH_ACC_ALIGN 8 -#endif - -/* Actual definition */ -#ifndef XXH_DOXYGEN -# define XXH_SCALAR 0 -# define XXH_SSE2 1 -# define XXH_AVX2 2 -# define XXH_AVX512 3 -# define XXH_NEON 4 -# define XXH_VSX 5 -#endif - -#ifndef XXH_VECTOR /* can be defined on command line */ -# if ( \ - defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ - || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ - ) && ( \ - defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ - || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ - ) -# define XXH_VECTOR XXH_NEON -# elif 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(__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(__clang__)) \ - && (defined(__arm__) || defined(__thumb__) || defined(_M_ARM)) -# 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 - -/*! - * @ingroup tuning - * @brief Controls the NEON to scalar ratio for XXH3 - * - * On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and - * 2 lanes on scalar by default. - * - * This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the - * emulated 64-bit arithmetic is too slow. - * - * Modern ARM CPUs are _very_ sensitive to how their pipelines are used. - * - * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but it can't - * have more than 2 NEON (F0/F1) micro-ops. If you are only using NEON instructions, - * you are only using 2/3 of the CPU bandwidth. - * - * This is even more noticeable on the more advanced cores like the A76 which - * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. - * - * Therefore, @ref XXH3_NEON_LANES lanes will be processed using NEON, and the - * remaining lanes will use scalar instructions. This improves the bandwidth - * and also gives the integer pipelines something to do besides twiddling loop - * counters and pointers. - * - * This change benefits CPUs with large micro-op buffers without negatively affecting - * other CPUs: - * - * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | - * |:----------------------|:--------------------|----------:|-----------:|------:| - * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | - * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | - * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | - * - * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. - * - * @see XXH3_accumulate_512_neon() - */ -# ifndef XXH3_NEON_LANES -# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ - && !defined(__OPTIMIZE_SIZE__) -# define XXH3_NEON_LANES 6 -# else -# define XXH3_NEON_LANES XXH_ACC_NB -# endif -# 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 -# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) -# define XXH_vec_revb vec_revb -# else -/*! - * A polyfill for POWER9's vec_revb(). - */ -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 vector load and byte swaps it on big endian. - */ -XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) -{ - xxh_u64x2 ret; - XXH_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_IX86)) /* _mm_prefetch() 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 - -#ifdef XXH_DOXYGEN -/*! - * @brief Calculates a 32-bit to 64-bit long multiply. - * - * Implemented as a macro. - * - * 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. - * - * @param x, y Numbers to be multiplied - * @return 64-bit product of the low 32 bits of @p x and @p y. - */ -XXH_FORCE_INLINE xxh_u64 -XXH_mult32to64(xxh_u64 x, xxh_u64 y) -{ - return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); -} -#elif defined(_MSC_VER) && defined(_M_IX86) -# 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 - -/*! - * @brief Calculates a 64->128-bit long multiply. - * - * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar - * version. - * - * @param lhs , rhs The 64-bit integers to be multiplied - * @return The 128-bit result represented in an @ref XXH128_hash_t. - */ -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(__clang__)) && !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)) && !defined(_M_ARM64EC) - -#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; - - /* - * MSVC for ARM64's __umulh method. - * - * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. - */ -#elif defined(_M_ARM64) || defined(_M_ARM64EC) - -#ifndef _MSC_VER -# pragma intrinsic(__umulh) -#endif - XXH128_hash_t r128; - r128.low64 = lhs * rhs; - r128.high64 = __umulh(lhs, rhs); - 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 -} - -/*! - * @brief Calculates 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. - * - * @param lhs , rhs The 64-bit integers to multiply - * @return The low 64 bits of the product XOR'd by the high 64 bits. - * @see XXH_mult64to128() - */ -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(9 <= 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. - */ - XXH_COMPILER_GUARD(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); - XXH_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_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) - -#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) -{ - __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)); - { __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)(0U - seed64)); - - const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); - __m512i* const dest = ( __m512i*) customSecret; - int i; - XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ - XXH_ASSERT(((size_t)dest & 63) == 0); - 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 { - const __m512i* cp; - 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_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) - -#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); - { __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); - { __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)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); - - const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); - __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 - */ - XXH_COMPILER_GUARD(dest); -# endif - XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ - XXH_ASSERT(((size_t)dest & 31) == 0); - - /* 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 - -/* x86dispatch always generates SSE2 */ -#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); - { __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); - { __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)(0U - seed64) }; - __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); -# else - __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); -# endif - int i; - - const void* const src16 = XXH3_kSecret; - __m128i* dst16 = (__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 - */ - XXH_COMPILER_GUARD(dst16); -# endif - XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ - XXH_ASSERT(((size_t)dst16 & 15) == 0); - - for (i=0; i < nbRounds; ++i) { - dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); - } } -} - -#endif - -#if (XXH_VECTOR == XXH_NEON) - -/* forward declarations for the scalar routines */ -XXH_FORCE_INLINE void -XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, - void const* XXH_RESTRICT secret, size_t lane); - -XXH_FORCE_INLINE void -XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, - void const* XXH_RESTRICT secret, size_t lane); - -/*! - * @internal - * @brief The bulk processing loop for NEON. - * - * The NEON code path is actually partially scalar when running on AArch64. This - * is to optimize the pipelining and can have up to 15% speedup depending on the - * CPU, and it also mitigates some GCC codegen issues. - * - * @see XXH3_NEON_LANES for configuring this and details about this optimization. - */ -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_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); - { - 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; - /* NEON for the first few lanes (these loops are normally interleaved) */ - for (i=0; i < XXH3_NEON_LANES / 2; 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); - - } - /* Scalar for the remainder. This may be a zero iteration loop. */ - for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { - XXH3_scalarRound(acc, input, secret, i); - } - } -} - -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; - /* NEON for the first few lanes (these loops are normally interleaved) */ - for (i=0; i < XXH3_NEON_LANES / 2; 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); - } - } - /* Scalar for the remainder. This may be a zero iteration loop. */ - for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { - XXH3_scalarScrambleRound(acc, secret, i); - } - } -} - -#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) -{ - /* presumed aligned */ - unsigned int* const xacc = (unsigned int*) acc; - 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); - /* acc_vec = xacc[i]; */ - xxh_u64x2 acc_vec = (xxh_u64x2)vec_xl(0, xacc + 4 * i); - acc_vec += product; - - /* swap high and low halves */ -#ifdef __s390x__ - acc_vec += vec_permi(data_vec, data_vec, 2); -#else - acc_vec += vec_xxpermdi(data_vec, data_vec, 2); -#endif - /* xacc[i] = acc_vec; */ - vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i); - } -} - -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 */ - -/*! - * @internal - * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). - * - * This is extracted to its own function because the NEON path uses a combination - * of NEON and scalar. - */ -XXH_FORCE_INLINE void -XXH3_scalarRound(void* XXH_RESTRICT acc, - void const* XXH_RESTRICT input, - void const* XXH_RESTRICT secret, - size_t lane) -{ - xxh_u64* xacc = (xxh_u64*) acc; - xxh_u8 const* xinput = (xxh_u8 const*) input; - xxh_u8 const* xsecret = (xxh_u8 const*) secret; - XXH_ASSERT(lane < XXH_ACC_NB); - XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); - { - xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); - xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); - xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ - xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); - } -} - -/*! - * @internal - * @brief Processes a 64 byte block of data using the scalar path. - */ -XXH_FORCE_INLINE void -XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, - const void* XXH_RESTRICT input, - const void* XXH_RESTRICT secret) -{ - size_t i; - for (i=0; i < XXH_ACC_NB; i++) { - XXH3_scalarRound(acc, input, secret, i); - } -} - -/*! - * @internal - * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). - * - * This is extracted to its own function because the NEON path uses a combination - * of NEON and scalar. - */ -XXH_FORCE_INLINE void -XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, - void const* XXH_RESTRICT secret, - size_t lane) -{ - xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ - const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ - XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); - XXH_ASSERT(lane < XXH_ACC_NB); - { - xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); - xxh_u64 acc64 = xacc[lane]; - acc64 = XXH_xorshift64(acc64, 47); - acc64 ^= key64; - acc64 *= XXH_PRIME32_1; - xacc[lane] = acc64; - } -} - -/*! - * @internal - * @brief Scrambles the accumulators after a large chunk has been read - */ -XXH_FORCE_INLINE void -XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) -{ - size_t i; - for (i=0; i < XXH_ACC_NB; i++) { - XXH3_scalarScrambleRound(acc, secret, i); - } -} - -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), it fights for bandwidth with - * the arithmetic instructions. - * - * 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 - * - * See XXH3_NEON_LANES for details on the pipsline. - * - * XXH3_64bits_withSeed, len == 256, Snapdragon 835 - * without hack: 2654.4 MB/s - * with hack: 3202.9 MB/s - */ - XXH_COMPILER_GUARD(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 - */ - XXH_COMPILER_GUARD(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 to transmit secret's size (when it's static) - * so that the compiler can properly optimize the vectorized loop. - * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. - */ -XXH_FORCE_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 preferable for performance that XXH3_hashLong is not inlined, - * as it results in a smaller function for small data, easier to the instruction cache. - * Note that inside this no_inline function, we do inline the internal loop, - * and provide a statically defined secret size to allow optimization of vector loop. - */ -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 === */ - -/*! @ingroup xxh3_family */ -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); -} - -/*! @ingroup xxh3_family */ -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); -} - -/*! @ingroup xxh3_family */ -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); -} - -XXH_PUBLIC_API XXH64_hash_t -XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) -{ - if (len <= XXH3_MIDSIZE_MAX) - return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); - return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize); -} - - -/* === 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); - } -} -/*! @ingroup xxh3_family */ -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; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) -{ - XXH_alignedFree(statePtr); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API void -XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) -{ - XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); -} - -static void -XXH3_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->useSeed = (seed != 0); - 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; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_reset(XXH3_state_t* statePtr) -{ - if (statePtr == NULL) return XXH_ERROR; - XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -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_reset_internal(statePtr, 0, secret, secretSize); - if (secret == NULL) return XXH_ERROR; - if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -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) || (statePtr->extSecret != NULL)) - XXH3_initCustomSecret(statePtr->customSecret, seed); - XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed64) -{ - if (statePtr == NULL) return XXH_ERROR; - if (secret == NULL) return XXH_ERROR; - if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; - XXH3_reset_internal(statePtr, seed64, secret, secretSize); - statePtr->useSeed = 1; /* always, even if seed64==0 */ - 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; - } -} - -#ifndef XXH3_STREAM_USE_STACK -# ifndef __clang__ /* clang doesn't need additional stack space */ -# define XXH3_STREAM_USE_STACK 1 -# endif -#endif -/* - * Both XXH3_64bits_update and XXH3_128bits_update use this routine. - */ -XXH_FORCE_INLINE XXH_errorcode -XXH3_update(XXH3_state_t* XXH_RESTRICT const state, - const xxh_u8* XXH_RESTRICT input, size_t len, - XXH3_f_accumulate_512 f_acc512, - XXH3_f_scrambleAcc f_scramble) -{ - if (input==NULL) { - XXH_ASSERT(len == 0); - return XXH_OK; - } - - XXH_ASSERT(state != NULL); - { const xxh_u8* const bEnd = input + len; - const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; -#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 - /* For some reason, gcc and MSVC seem to suffer greatly - * when operating accumulators directly into state. - * Operating into stack space seems to enable proper optimization. - * clang, on the other hand, doesn't seem to need this trick */ - XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; memcpy(acc, state->acc, sizeof(acc)); -#else - xxh_u64* XXH_RESTRICT const acc = state->acc; -#endif - state->totalLen += len; - XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); - - /* small input : just fill in tmp buffer */ - if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { - 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(acc, - &state->nbStripesSoFar, state->nbStripesPerBlock, - state->buffer, XXH3_INTERNALBUFFER_STRIPES, - secret, state->secretLimit, - f_acc512, f_scramble); - state->bufferedSize = 0; - } - XXH_ASSERT(input < bEnd); - - /* large input to consume : ingest per full block */ - if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) { - size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; - XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar); - /* join to current block's end */ - { size_t const nbStripesToEnd = state->nbStripesPerBlock - state->nbStripesSoFar; - XXH_ASSERT(nbStripesToEnd <= nbStripes); - XXH3_accumulate(acc, input, secret + state->nbStripesSoFar * XXH_SECRET_CONSUME_RATE, nbStripesToEnd, f_acc512); - f_scramble(acc, secret + state->secretLimit); - state->nbStripesSoFar = 0; - input += nbStripesToEnd * XXH_STRIPE_LEN; - nbStripes -= nbStripesToEnd; - } - /* consume per entire blocks */ - while(nbStripes >= state->nbStripesPerBlock) { - XXH3_accumulate(acc, input, secret, state->nbStripesPerBlock, f_acc512); - f_scramble(acc, secret + state->secretLimit); - input += state->nbStripesPerBlock * XXH_STRIPE_LEN; - nbStripes -= state->nbStripesPerBlock; - } - /* consume last partial block */ - XXH3_accumulate(acc, input, secret, nbStripes, f_acc512); - input += nbStripes * XXH_STRIPE_LEN; - XXH_ASSERT(input < bEnd); /* at least some bytes left */ - state->nbStripesSoFar = nbStripes; - /* buffer predecessor of last partial stripe */ - XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); - XXH_ASSERT(bEnd - input <= XXH_STRIPE_LEN); - } else { - /* content to consume <= block size */ - /* Consume input by a multiple of internal buffer size */ - if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { - const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; - do { - XXH3_consumeStripes(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); - } - } - - /* Some remaining input (always) : buffer it */ - XXH_ASSERT(input < bEnd); - XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); - XXH_ASSERT(state->bufferedSize == 0); - XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); - state->bufferedSize = (XXH32_hash_t)(bEnd-input); -#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 - /* save stack accumulators into state */ - memcpy(state->acc, acc, sizeof(acc)); -#endif - } - - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -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. - */ - XXH_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 */ - XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); - XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); - XXH3_accumulate_512(acc, - lastStripe, - secret + state->secretLimit - XXH_SECRET_LASTACC_START); - } -} - -/*! @ingroup xxh3_family */ -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->useSeed) - 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); -} - - - -/* ========================================== - * 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 to pass @secretLen (when it's static) - * to the compiler, so that it can properly optimize the vectorized loop. - */ -XXH_FORCE_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 === */ - -/*! @ingroup xxh3_family */ -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); -} - -/*! @ingroup xxh3_family */ -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); -} - -/*! @ingroup xxh3_family */ -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); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH128_hash_t -XXH3_128bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) -{ - if (len <= XXH3_MIDSIZE_MAX) - return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); - return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); -} - -/*! @ingroup xxh3_family */ -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 initialization and update functions are identical to 64-bit streaming variant. - * The only difference is the finalization routine. - */ - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset(XXH3_state_t* statePtr) -{ - return XXH3_64bits_reset(statePtr); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) -{ - return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) -{ - return XXH3_64bits_reset_withSeed(statePtr, seed); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed) -{ - return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); -} - -/*! @ingroup xxh3_family */ -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); -} - -/*! @ingroup xxh3_family */ -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 */ -/*! @ingroup xxh3_family */ -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 */ -/*! @ingroup xxh3_family */ -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 ======*/ -/*! @ingroup xxh3_family */ -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); - } - XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); - XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); -} - -/*! @ingroup xxh3_family */ -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; -} - - - -/* ========================================== - * Secret generators - * ========================================== - */ -#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) - -XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) -{ - XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); - XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize) -{ -#if (XXH_DEBUGLEVEL >= 1) - XXH_ASSERT(secretBuffer != NULL); - XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); -#else - /* production mode, assert() are disabled */ - if (secretBuffer == NULL) return XXH_ERROR; - if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; -#endif - - if (customSeedSize == 0) { - customSeed = XXH3_kSecret; - customSeedSize = XXH_SECRET_DEFAULT_SIZE; - } -#if (XXH_DEBUGLEVEL >= 1) - XXH_ASSERT(customSeed != NULL); -#else - if (customSeed == NULL) return XXH_ERROR; -#endif - - /* Fill secretBuffer with a copy of customSeed - repeat as needed */ - { size_t pos = 0; - while (pos < secretSize) { - size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); - memcpy((char*)secretBuffer + pos, customSeed, toCopy); - pos += toCopy; - } } - - { size_t const nbSeg16 = secretSize / 16; - size_t n; - XXH128_canonical_t scrambler; - XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); - for (n=0; n4GB) */ #define _FILE_OFFSET_BITS 64 #if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ -# ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE -# endif #elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ -# ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE -# endif #endif @@ -42,19 +37,17 @@ #include /* fprintf, fopen, ftello64 */ #include /* clock */ -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - #include "mem.h" /* read */ #include "fse.h" /* FSE_normalizeCount, FSE_writeNCount */ +#define HUF_STATIC_LINKING_ONLY #include "huf.h" /* HUF_buildCTable, HUF_writeCTable */ #include "zstd_internal.h" /* includes zstd.h */ #include "xxhash.h" /* XXH64 */ -#include "zstd_compress_internal.h" /* ZSTD_loadCEntropy() */ -#include "zdict.h" #include "divsufsort.h" -#include "bits.h" /* ZSTD_NbCommonBytes */ +#ifndef ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY +#endif +#include "zdict.h" /*-************************************* @@ -68,15 +61,14 @@ #define NOISELENGTH 32 +static const int g_compressionLevel_default = 3; static const U32 g_selectivity_default = 9; /*-************************************* * Console display ***************************************/ -#undef DISPLAY #define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } -#undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } @@ -107,30 +99,69 @@ unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize) return MEM_readLE32((const char*)dictBuffer + 4); } -size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize) -{ - size_t headerSize; - if (dictSize <= 8 || MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return ERROR(dictionary_corrupted); - - { ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t)); - U32* wksp = (U32*)malloc(HUF_WORKSPACE_SIZE); - if (!bs || !wksp) { - headerSize = ERROR(memory_allocation); - } else { - ZSTD_reset_compressedBlockState(bs); - headerSize = ZSTD_loadCEntropy(bs, wksp, dictBuffer, dictSize); - } - - free(bs); - free(wksp); - } - - return headerSize; -} /*-******************************************************** * Dictionary training functions **********************************************************/ +static unsigned ZDICT_NbCommonBytes (size_t val) +{ + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + unsigned long r=0; + _BitScanForward( &r, (U32)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } else { /* Big Endian CPU */ + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_clzll(val) >> 3); +# else + unsigned r; + const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ + if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif + } } +} + + /*! ZDICT_count() : Count the nb of common bytes between 2 pointers. Note : this function presumes end of buffer followed by noisy guard band. @@ -145,7 +176,7 @@ static size_t ZDICT_count(const void* pIn, const void* pMatch) pMatch = (const char*)pMatch+sizeof(size_t); continue; } - pIn = (const char*)pIn+ZSTD_NbCommonBytes(diff); + pIn = (const char*)pIn+ZDICT_NbCommonBytes(diff); return (size_t)((const char*)pIn - pStart); } } @@ -177,7 +208,7 @@ static dictItem ZDICT_analyzePos( U32 savings[LLIMIT] = {0}; const BYTE* b = (const BYTE*)buffer; size_t maxLength = LLIMIT; - size_t pos = (size_t)suffix[start]; + size_t pos = suffix[start]; U32 end = start; dictItem solution; @@ -311,7 +342,7 @@ static dictItem ZDICT_analyzePos( savings[i] = savings[i-1] + (lengthList[i] * (i-3)); DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f) \n", - (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / (double)maxLength); + (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / maxLength); solution.pos = (U32)pos; solution.length = (U32)maxLength; @@ -321,7 +352,7 @@ static dictItem ZDICT_analyzePos( { U32 id; for (id=start; id1) && (table[u-1].savings < elt.savings)) - table[u] = table[u-1], u--; + table[u] = table[u-1], u--; table[u] = elt; return u; } } @@ -384,7 +415,7 @@ static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const if ((table[u].pos + table[u].length >= elt.pos) && (table[u].pos < elt.pos)) { /* overlap, existing < new */ /* append */ - int const addedLength = (int)eltEnd - (int)(table[u].pos + table[u].length); + int const addedLength = (int)eltEnd - (table[u].pos + table[u].length); table[u].savings += elt.length / 8; /* rough approx bonus */ if (addedLength > 0) { /* otherwise, elt fully included into existing */ table[u].length += addedLength; @@ -477,7 +508,6 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize, clock_t displayClock = 0; clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10; -# undef DISPLAYUPDATE # define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \ if (ZDICT_clockSpan(displayClock) > refreshRate) \ { displayClock = clock(); DISPLAY(__VA_ARGS__); \ @@ -524,7 +554,7 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize, if (solution.length==0) { cursor++; continue; } ZDICT_insertDictItem(dictList, dictListSize, solution, buffer); cursor += solution.length; - DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / (double)bufferSize * 100.0); + DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100); } } _cleanup: @@ -558,20 +588,20 @@ typedef struct #define MAXREPOFFSET 1024 -static void ZDICT_countEStats(EStats_ress_t esr, const ZSTD_parameters* params, +static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params, unsigned* countLit, unsigned* offsetcodeCount, unsigned* matchlengthCount, unsigned* litlengthCount, U32* repOffsets, const void* src, size_t srcSize, U32 notificationLevel) { - size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params->cParams.windowLog); + size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params.cParams.windowLog); size_t cSize; if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */ - { size_t const errorCode = ZSTD_compressBegin_usingCDict_deprecated(esr.zc, esr.dict); + { size_t const errorCode = ZSTD_compressBegin_usingCDict(esr.zc, esr.dict); if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_compressBegin_usingCDict failed \n"); return; } } - cSize = ZSTD_compressBlock_deprecated(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize); + cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize); if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (unsigned)srcSize); return; } if (cSize) { /* if == 0; block is not compressible */ @@ -604,8 +634,8 @@ static void ZDICT_countEStats(EStats_ress_t esr, const ZSTD_parameters* params, if (nbSeq >= 2) { /* rep offsets */ const seqDef* const seq = seqStorePtr->sequencesStart; - U32 offset1 = seq[0].offBase - ZSTD_REP_NUM; - U32 offset2 = seq[1].offBase - ZSTD_REP_NUM; + U32 offset1 = seq[0].offset - 3; + U32 offset2 = seq[1].offset - 3; if (offset1 >= MAXREPOFFSET) offset1 = 0; if (offset2 >= MAXREPOFFSET) offset2 = 0; repOffsets[offset1] += 3; @@ -652,7 +682,7 @@ static void ZDICT_flatLit(unsigned* countLit) #define OFFCODE_MAX 30 /* only applicable to first block */ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, - int compressionLevel, + unsigned compressionLevel, const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize, unsigned notificationLevel) @@ -676,7 +706,6 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, size_t const totalSrcSize = ZDICT_totalSampleSize(fileSizes, nbFiles); size_t const averageSampleSize = totalSrcSize / (nbFiles + !nbFiles); BYTE* dstPtr = (BYTE*)dstBuffer; - U32 wksp[HUF_CTABLE_WORKSPACE_SIZE_U32]; /* init */ DEBUGLOG(4, "ZDICT_analyzeEntropy"); @@ -688,7 +717,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, memset(repOffset, 0, sizeof(repOffset)); repOffset[1] = repOffset[4] = repOffset[8] = 1; memset(bestRepOffset, 0, sizeof(bestRepOffset)); - if (compressionLevel==0) compressionLevel = ZSTD_CLEVEL_DEFAULT; + if (compressionLevel==0) compressionLevel = g_compressionLevel_default; params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize); esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem); @@ -702,22 +731,15 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, /* collect stats on all samples */ for (u=0; u= 4) { - /* writeStats */ - DISPLAYLEVEL(4, "Offset Code Frequencies : \n"); - for (u=0; u<=offcodeMax; u++) { - DISPLAYLEVEL(4, "%2u :%7u \n", u, offcodeCount[u]); - } } - /* analyze, build stats, starting with literals */ - { size_t maxNbBits = HUF_buildCTable_wksp(hufTable, countLit, 255, huffLog, wksp, sizeof(wksp)); + { size_t maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog); if (HUF_isError(maxNbBits)) { eSize = maxNbBits; DISPLAYLEVEL(1, " HUF_buildCTable error \n"); @@ -726,7 +748,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, if (maxNbBits==8) { /* not compressible : will fail on HUF_writeCTable() */ DISPLAYLEVEL(2, "warning : pathological dataset : literals are not compressible : samples are noisy or too regular \n"); ZDICT_flatLit(countLit); /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */ - maxNbBits = HUF_buildCTable_wksp(hufTable, countLit, 255, huffLog, wksp, sizeof(wksp)); + maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog); assert(maxNbBits==9); } huffLog = (U32)maxNbBits; @@ -740,7 +762,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, /* note : the result of this phase should be used to better appreciate the impact on statistics */ total=0; for (u=0; u<=offcodeMax; u++) total+=offcodeCount[u]; - errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax, /* useLowProbCount */ 1); + errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax); if (FSE_isError(errorCode)) { eSize = errorCode; DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount \n"); @@ -749,7 +771,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, Offlog = (U32)errorCode; total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u]; - errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML, /* useLowProbCount */ 1); + errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML); if (FSE_isError(errorCode)) { eSize = errorCode; DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount \n"); @@ -758,7 +780,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, mlLog = (U32)errorCode; total=0; for (u=0; u<=MaxLL; u++) total+=litLengthCount[u]; - errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL, /* useLowProbCount */ 1); + errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL); if (FSE_isError(errorCode)) { eSize = errorCode; DISPLAYLEVEL(1, "FSE_normalizeCount error with litLengthCount \n"); @@ -767,7 +789,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, llLog = (U32)errorCode; /* write result to buffer */ - { size_t const hhSize = HUF_writeCTable_wksp(dstPtr, maxDstSize, hufTable, 255, huffLog, wksp, sizeof(wksp)); + { size_t const hhSize = HUF_writeCTable(dstPtr, maxDstSize, hufTable, 255, huffLog); if (HUF_isError(hhSize)) { eSize = hhSize; DISPLAYLEVEL(1, "HUF_writeCTable error \n"); @@ -822,7 +844,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, MEM_writeLE32(dstPtr+8, bestRepOffset[2].offset); #else /* at this stage, we don't use the result of "most common first offset", - * as the impact of statistics is not properly evaluated */ + as the impact of statistics is not properly evaluated */ MEM_writeLE32(dstPtr+0, repStartValue[0]); MEM_writeLE32(dstPtr+4, repStartValue[1]); MEM_writeLE32(dstPtr+8, repStartValue[2]); @@ -838,17 +860,6 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, } -/** - * @returns the maximum repcode value - */ -static U32 ZDICT_maxRep(U32 const reps[ZSTD_REP_NUM]) -{ - U32 maxRep = reps[0]; - int r; - for (r = 1; r < ZSTD_REP_NUM; ++r) - maxRep = MAX(maxRep, reps[r]); - return maxRep; -} size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, const void* customDictContent, size_t dictContentSize, @@ -858,15 +869,13 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, size_t hSize; #define HBUFFSIZE 256 /* should prove large enough for all entropy headers */ BYTE header[HBUFFSIZE]; - int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel; + int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel; U32 const notificationLevel = params.notificationLevel; - /* The final dictionary content must be at least as large as the largest repcode */ - size_t const minContentSize = (size_t)ZDICT_maxRep(repStartValue); - size_t paddingSize; /* check conditions */ DEBUGLOG(4, "ZDICT_finalizeDictionary"); if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall); + if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong); if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall); /* dictionary header */ @@ -890,43 +899,12 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, hSize += eSize; } - /* Shrink the content size if it doesn't fit in the buffer */ - if (hSize + dictContentSize > dictBufferCapacity) { - dictContentSize = dictBufferCapacity - hSize; - } - - /* Pad the dictionary content with zeros if it is too small */ - if (dictContentSize < minContentSize) { - RETURN_ERROR_IF(hSize + minContentSize > dictBufferCapacity, dstSize_tooSmall, - "dictBufferCapacity too small to fit max repcode"); - paddingSize = minContentSize - dictContentSize; - } else { - paddingSize = 0; - } - - { - size_t const dictSize = hSize + paddingSize + dictContentSize; - - /* The dictionary consists of the header, optional padding, and the content. - * The padding comes before the content because the "best" position in the - * dictionary is the last byte. - */ - BYTE* const outDictHeader = (BYTE*)dictBuffer; - BYTE* const outDictPadding = outDictHeader + hSize; - BYTE* const outDictContent = outDictPadding + paddingSize; - - assert(dictSize <= dictBufferCapacity); - assert(outDictContent + dictContentSize == (BYTE*)dictBuffer + dictSize); - - /* First copy the customDictContent into its final location. - * `customDictContent` and `dictBuffer` may overlap, so we must - * do this before any other writes into the output buffer. - * Then copy the header & padding into the output buffer. - */ - memmove(outDictContent, customDictContent, dictContentSize); - memcpy(outDictHeader, header, hSize); - memset(outDictPadding, 0, paddingSize); - + /* copy elements in final buffer ; note : src and dst buffer can overlap */ + if (hSize + dictContentSize > dictBufferCapacity) dictContentSize = dictBufferCapacity - hSize; + { size_t const dictSize = hSize + dictContentSize; + char* dictEnd = (char*)dictBuffer + dictSize; + memmove(dictEnd - dictContentSize, customDictContent, dictContentSize); + memcpy(dictBuffer, header, hSize); return dictSize; } } @@ -937,7 +915,7 @@ static size_t ZDICT_addEntropyTablesFromBuffer_advanced( const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_params_t params) { - int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel; + int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel; U32 const notificationLevel = params.notificationLevel; size_t hSize = 8; @@ -966,11 +944,16 @@ static size_t ZDICT_addEntropyTablesFromBuffer_advanced( return MIN(dictBufferCapacity, hSize+dictContentSize); } +/* Hidden declaration for dbio.c */ +size_t ZDICT_trainFromBuffer_unsafe_legacy( + void* dictBuffer, size_t maxDictSize, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_legacy_params_t params); /*! ZDICT_trainFromBuffer_unsafe_legacy() : -* Warning : `samplesBuffer` must be followed by noisy guard band !!! +* Warning : `samplesBuffer` must be followed by noisy guard band. * @return : size of dictionary, or an error code which can be tested with ZDICT_isError() */ -static size_t ZDICT_trainFromBuffer_unsafe_legacy( +size_t ZDICT_trainFromBuffer_unsafe_legacy( void* dictBuffer, size_t maxDictSize, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_legacy_params_t params) @@ -1107,8 +1090,8 @@ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, memset(¶ms, 0, sizeof(params)); params.d = 8; params.steps = 4; - /* Use default level since no compression level information is available */ - params.zParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; + /* Default to level 6 since no compression level information is available */ + params.zParams.compressionLevel = 3; #if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1) params.zParams.notificationLevel = DEBUGLEVEL; #endif @@ -1126,5 +1109,3 @@ size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize samplesBuffer, samplesSizes, nbSamples, params); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zdict.h b/vendor/github.com/DataDog/zstd/zdict.h index 5f4af1e3..37978ecd 100644 --- a/vendor/github.com/DataDog/zstd/zdict.h +++ b/vendor/github.com/DataDog/zstd/zdict.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -9,184 +8,34 @@ * You may select, at your option, one of the above-listed licenses. */ +#ifndef DICTBUILDER_H_001 +#define DICTBUILDER_H_001 + #if defined (__cplusplus) extern "C" { #endif -#ifndef ZSTD_ZDICT_H -#define ZSTD_ZDICT_H /*====== Dependencies ======*/ #include /* size_t */ /* ===== ZDICTLIB_API : control library symbols visibility ===== */ -#ifndef ZDICTLIB_VISIBLE - /* Backwards compatibility with old macro name */ -# ifdef ZDICTLIB_VISIBILITY -# define ZDICTLIB_VISIBLE ZDICTLIB_VISIBILITY -# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZDICTLIB_VISIBLE __attribute__ ((visibility ("default"))) -# else -# define ZDICTLIB_VISIBLE -# endif -#endif - -#ifndef ZDICTLIB_HIDDEN -# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZDICTLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +#ifndef ZDICTLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZDICTLIB_VISIBILITY __attribute__ ((visibility ("default"))) # else -# define ZDICTLIB_HIDDEN +# define ZDICTLIB_VISIBILITY # endif #endif - #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBLE +# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBILITY #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZDICTLIB_API ZDICTLIB_VISIBLE +# define ZDICTLIB_API ZDICTLIB_VISIBILITY #endif -/******************************************************************************* - * Zstd dictionary builder - * - * FAQ - * === - * Why should I use a dictionary? - * ------------------------------ - * - * Zstd can use dictionaries to improve compression ratio of small data. - * Traditionally small files don't compress well because there is very little - * repetition in a single sample, since it is small. But, if you are compressing - * many similar files, like a bunch of JSON records that share the same - * structure, you can train a dictionary on ahead of time on some samples of - * these files. Then, zstd can use the dictionary to find repetitions that are - * present across samples. This can vastly improve compression ratio. - * - * When is a dictionary useful? - * ---------------------------- - * - * Dictionaries are useful when compressing many small files that are similar. - * The larger a file is, the less benefit a dictionary will have. Generally, - * we don't expect dictionary compression to be effective past 100KB. And the - * smaller a file is, the more we would expect the dictionary to help. - * - * How do I use a dictionary? - * -------------------------- - * - * Simply pass the dictionary to the zstd compressor with - * `ZSTD_CCtx_loadDictionary()`. The same dictionary must then be passed to - * the decompressor, using `ZSTD_DCtx_loadDictionary()`. There are other - * more advanced functions that allow selecting some options, see zstd.h for - * complete documentation. - * - * What is a zstd dictionary? - * -------------------------- - * - * A zstd dictionary has two pieces: Its header, and its content. The header - * contains a magic number, the dictionary ID, and entropy tables. These - * entropy tables allow zstd to save on header costs in the compressed file, - * which really matters for small data. The content is just bytes, which are - * repeated content that is common across many samples. - * - * What is a raw content dictionary? - * --------------------------------- - * - * A raw content dictionary is just bytes. It doesn't have a zstd dictionary - * header, a dictionary ID, or entropy tables. Any buffer is a valid raw - * content dictionary. - * - * How do I train a dictionary? - * ---------------------------- - * - * Gather samples from your use case. These samples should be similar to each - * other. If you have several use cases, you could try to train one dictionary - * per use case. - * - * Pass those samples to `ZDICT_trainFromBuffer()` and that will train your - * dictionary. There are a few advanced versions of this function, but this - * is a great starting point. If you want to further tune your dictionary - * you could try `ZDICT_optimizeTrainFromBuffer_cover()`. If that is too slow - * you can try `ZDICT_optimizeTrainFromBuffer_fastCover()`. - * - * If the dictionary training function fails, that is likely because you - * either passed too few samples, or a dictionary would not be effective - * for your data. Look at the messages that the dictionary trainer printed, - * if it doesn't say too few samples, then a dictionary would not be effective. - * - * How large should my dictionary be? - * ---------------------------------- - * - * A reasonable dictionary size, the `dictBufferCapacity`, is about 100KB. - * The zstd CLI defaults to a 110KB dictionary. You likely don't need a - * dictionary larger than that. But, most use cases can get away with a - * smaller dictionary. The advanced dictionary builders can automatically - * shrink the dictionary for you, and select the smallest size that doesn't - * hurt compression ratio too much. See the `shrinkDict` parameter. - * A smaller dictionary can save memory, and potentially speed up - * compression. - * - * How many samples should I provide to the dictionary builder? - * ------------------------------------------------------------ - * - * We generally recommend passing ~100x the size of the dictionary - * in samples. A few thousand should suffice. Having too few samples - * can hurt the dictionaries effectiveness. Having more samples will - * only improve the dictionaries effectiveness. But having too many - * samples can slow down the dictionary builder. - * - * How do I determine if a dictionary will be effective? - * ----------------------------------------------------- - * - * Simply train a dictionary and try it out. You can use zstd's built in - * benchmarking tool to test the dictionary effectiveness. - * - * # Benchmark levels 1-3 without a dictionary - * zstd -b1e3 -r /path/to/my/files - * # Benchmark levels 1-3 with a dictionary - * zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary - * - * When should I retrain a dictionary? - * ----------------------------------- - * - * You should retrain a dictionary when its effectiveness drops. Dictionary - * effectiveness drops as the data you are compressing changes. Generally, we do - * expect dictionaries to "decay" over time, as your data changes, but the rate - * at which they decay depends on your use case. Internally, we regularly - * retrain dictionaries, and if the new dictionary performs significantly - * better than the old dictionary, we will ship the new dictionary. - * - * I have a raw content dictionary, how do I turn it into a zstd dictionary? - * ------------------------------------------------------------------------- - * - * If you have a raw content dictionary, e.g. by manually constructing it, or - * using a third-party dictionary builder, you can turn it into a zstd - * dictionary by using `ZDICT_finalizeDictionary()`. You'll also have to - * provide some samples of the data. It will add the zstd header to the - * raw content, which contains a dictionary ID and entropy tables, which - * will improve compression ratio, and allow zstd to write the dictionary ID - * into the frame, if you so choose. - * - * Do I have to use zstd's dictionary builder? - * ------------------------------------------- - * - * No! You can construct dictionary content however you please, it is just - * bytes. It will always be valid as a raw content dictionary. If you want - * a zstd dictionary, which can improve compression ratio, use - * `ZDICT_finalizeDictionary()`. - * - * What is the attack surface of a zstd dictionary? - * ------------------------------------------------ - * - * Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so - * zstd should never crash, or access out-of-bounds memory no matter what - * the dictionary is. However, if an attacker can control the dictionary - * during decompression, they can cause zstd to generate arbitrary bytes, - * just like if they controlled the compressed data. - * - ******************************************************************************/ - /*! ZDICT_trainFromBuffer(): * Train a dictionary from an array of samples. @@ -212,81 +61,15 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCap const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); -typedef struct { - int compressionLevel; /**< optimize for a specific zstd compression level; 0 means default */ - unsigned notificationLevel; /**< Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ - unsigned dictID; /**< force dictID value; 0 means auto mode (32-bits random value) - * NOTE: The zstd format reserves some dictionary IDs for future use. - * You may use them in private settings, but be warned that they - * may be used by zstd in a public dictionary registry in the future. - * These dictionary IDs are: - * - low range : <= 32767 - * - high range : >= (2^31) - */ -} ZDICT_params_t; - -/*! ZDICT_finalizeDictionary(): - * Given a custom content as a basis for dictionary, and a set of samples, - * finalize dictionary by adding headers and statistics according to the zstd - * dictionary format. - * - * Samples must be stored concatenated in a flat buffer `samplesBuffer`, - * supplied with an array of sizes `samplesSizes`, providing the size of each - * sample in order. The samples are used to construct the statistics, so they - * should be representative of what you will compress with this dictionary. - * - * The compression level can be set in `parameters`. You should pass the - * compression level you expect to use in production. The statistics for each - * compression level differ, so tuning the dictionary for the compression level - * can help quite a bit. - * - * You can set an explicit dictionary ID in `parameters`, or allow us to pick - * a random dictionary ID for you, but we can't guarantee no collisions. - * - * The dstDictBuffer and the dictContent may overlap, and the content will be - * appended to the end of the header. If the header + the content doesn't fit in - * maxDictSize the beginning of the content is truncated to make room, since it - * is presumed that the most profitable content is at the end of the dictionary, - * since that is the cheapest to reference. - * - * `maxDictSize` must be >= max(dictContentSize, ZSTD_DICTSIZE_MIN). - * - * @return: size of dictionary stored into `dstDictBuffer` (<= `maxDictSize`), - * or an error code, which can be tested by ZDICT_isError(). - * Note: ZDICT_finalizeDictionary() will push notifications into stderr if - * instructed to, using notificationLevel>0. - * NOTE: This function currently may fail in several edge cases including: - * * Not enough samples - * * Samples are uncompressible - * * Samples are all exactly the same - */ -ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dstDictBuffer, size_t maxDictSize, - const void* dictContent, size_t dictContentSize, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_params_t parameters); - /*====== Helper functions ======*/ ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize); /**< extracts dictID; @return zero if error (not a valid dictionary) */ -ZDICTLIB_API size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize); /* returns dict header size; returns a ZSTD error code on failure */ ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode); ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode); -#endif /* ZSTD_ZDICT_H */ -#if defined(ZDICT_STATIC_LINKING_ONLY) && !defined(ZSTD_ZDICT_H_STATIC) -#define ZSTD_ZDICT_H_STATIC -/* This can be overridden externally to hide static symbols. */ -#ifndef ZDICTLIB_STATIC_API -# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZDICTLIB_STATIC_API __declspec(dllexport) ZDICTLIB_VISIBLE -# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZDICTLIB_STATIC_API __declspec(dllimport) ZDICTLIB_VISIBLE -# else -# define ZDICTLIB_STATIC_API ZDICTLIB_VISIBLE -# endif -#endif +#ifdef ZDICT_STATIC_LINKING_ONLY /* ==================================================================================== * The definitions in this section are considered experimental. @@ -295,9 +78,11 @@ ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode); * Use them only in association with static linking. * ==================================================================================== */ -#define ZDICT_DICTSIZE_MIN 256 -/* Deprecated: Remove in v1.6.0 */ -#define ZDICT_CONTENTSIZE_MIN 128 +typedef struct { + int compressionLevel; /* optimize for a specific zstd compression level; 0 means default */ + unsigned notificationLevel; /* Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ + unsigned dictID; /* force dictID value; 0 means auto mode (32-bits random value) */ +} ZDICT_params_t; /*! ZDICT_cover_params_t: * k and d are the only required parameters. @@ -342,7 +127,7 @@ typedef struct { * In general, it's recommended to provide a few thousands samples, though this can vary a lot. * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. */ -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( +ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover( void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, ZDICT_cover_params_t parameters); @@ -364,7 +149,7 @@ ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( * See ZDICT_trainFromBuffer() for details on failure modes. * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread. */ -ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( +ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_cover_params_t* parameters); @@ -385,7 +170,7 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( * In general, it's recommended to provide a few thousands samples, though this can vary a lot. * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. */ -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, +ZDICTLIB_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, ZDICT_fastCover_params_t parameters); @@ -408,11 +193,33 @@ ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, * See ZDICT_trainFromBuffer() for details on failure modes. * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 6 * 2^f bytes of memory for each thread. */ -ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer, +ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_fastCover_params_t* parameters); +/*! ZDICT_finalizeDictionary(): + * Given a custom content as a basis for dictionary, and a set of samples, + * finalize dictionary by adding headers and statistics. + * + * Samples must be stored concatenated in a flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample in order. + * + * dictContentSize must be >= ZDICT_CONTENTSIZE_MIN bytes. + * maxDictSize must be >= dictContentSize, and must be >= ZDICT_DICTSIZE_MIN bytes. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`), + * or an error code, which can be tested by ZDICT_isError(). + * Note: ZDICT_finalizeDictionary() will push notifications into stderr if instructed to, using notificationLevel>0. + * Note 2: dictBuffer and dictContent can overlap + */ +#define ZDICT_CONTENTSIZE_MIN 128 +#define ZDICT_DICTSIZE_MIN 256 +ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, + const void* dictContent, size_t dictContentSize, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + typedef struct { unsigned selectivityLevel; /* 0 means default; larger => select more => larger dictionary */ ZDICT_params_t zParams; @@ -433,45 +240,43 @@ typedef struct { * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. * Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0. */ -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_legacy( - void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, +ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy( + void *dictBuffer, size_t dictBufferCapacity, + const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, ZDICT_legacy_params_t parameters); - /* Deprecation warnings */ /* It is generally possible to disable deprecation warnings from compiler, for example with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */ #ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS -# define ZDICT_DEPRECATED(message) /* disable deprecation warnings */ +# define ZDICT_DEPRECATED(message) ZDICTLIB_API /* disable deprecation warnings */ #else # define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ -# define ZDICT_DEPRECATED(message) [[deprecated(message)]] -# elif defined(__clang__) || (ZDICT_GCC_VERSION >= 405) -# define ZDICT_DEPRECATED(message) __attribute__((deprecated(message))) +# define ZDICT_DEPRECATED(message) [[deprecated(message)]] ZDICTLIB_API +# elif (ZDICT_GCC_VERSION >= 405) || defined(__clang__) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated(message))) # elif (ZDICT_GCC_VERSION >= 301) -# define ZDICT_DEPRECATED(message) __attribute__((deprecated)) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated)) # elif defined(_MSC_VER) -# define ZDICT_DEPRECATED(message) __declspec(deprecated(message)) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API __declspec(deprecated(message)) # else # pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler") -# define ZDICT_DEPRECATED(message) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API # endif #endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */ ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead") -ZDICTLIB_STATIC_API size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); -#endif /* ZSTD_ZDICT_H_STATIC */ +#endif /* ZDICT_STATIC_LINKING_ONLY */ #if defined (__cplusplus) } #endif -#endif /* USE_EXTERNAL_ZSTD */ +#endif /* DICTBUILDER_H_001 */ diff --git a/vendor/github.com/DataDog/zstd/zstd.go b/vendor/github.com/DataDog/zstd/zstd.go index 2cf5c61b..b6af4eb1 100644 --- a/vendor/github.com/DataDog/zstd/zstd.go +++ b/vendor/github.com/DataDog/zstd/zstd.go @@ -1,18 +1,29 @@ package zstd /* -// support decoding of "legacy" zstd payloads from versions [0.4, 0.8], matching the -// default configuration of the zstd command line tool: -// https://github.com/facebook/zstd/blob/dev/programs/README.md -#cgo CFLAGS: -DZSTD_LEGACY_SUPPORT=4 -DZSTD_MULTITHREAD=1 - +#define ZSTD_STATIC_LINKING_ONLY #include "zstd.h" +#include "stdint.h" // for uintptr_t + +// The following *_wrapper function are used for removing superflouos +// memory allocations when calling the wrapped functions from Go code. +// See https://github.com/golang/go/issues/24450 for details. + +static size_t ZSTD_compress_wrapper(uintptr_t dst, size_t maxDstSize, const uintptr_t src, size_t srcSize, int compressionLevel) { + return ZSTD_compress((void*)dst, maxDstSize, (const void*)src, srcSize, compressionLevel); +} + +static size_t ZSTD_decompress_wrapper(uintptr_t dst, size_t maxDstSize, uintptr_t src, size_t srcSize) { + return ZSTD_decompress((void*)dst, maxDstSize, (const void *)src, srcSize); +} + */ import "C" import ( "bytes" "errors" "io/ioutil" + "runtime" "unsafe" ) @@ -28,17 +39,6 @@ var ( ErrEmptySlice = errors.New("Bytes slice is empty") ) -const ( - // decompressSizeBufferLimit is the limit we set on creating a decompression buffer for the Decompress API - // This is made to prevent DOS from maliciously-created payloads (aka zipbomb). - // For large payloads with a compression ratio > 10, you can do your own allocation and pass it to the method: - // dst := make([]byte, 1GB) - // decompressed, err := zstd.Decompress(dst, src) - decompressSizeBufferLimit = 1000 * 1000 - - zstdFrameHeaderSizeMin = 2 // From zstd.h. Since it's experimental API, hardcoding it -) - // CompressBound returns the worst case size needed for a destination buffer, // which can be used to preallocate a destination buffer or select a previously // allocated buffer from a pool. @@ -57,33 +57,6 @@ func cCompressBound(srcSize int) int { return int(C.ZSTD_compressBound(C.size_t(srcSize))) } -// decompressSizeHint tries to give a hint on how much of the output buffer size we should have -// based on zstd frame descriptors. To prevent DOS from maliciously-created payloads, limit the size -func decompressSizeHint(src []byte) int { - // 1 MB or 10x input size - upperBound := 10 * len(src) - if upperBound < decompressSizeBufferLimit { - upperBound = decompressSizeBufferLimit - } - - hint := upperBound - if len(src) >= zstdFrameHeaderSizeMin { - hint = int(C.ZSTD_getFrameContentSize(unsafe.Pointer(&src[0]), C.size_t(len(src)))) - if hint < 0 { // On error, just use upperBound - hint = upperBound - } - if hint == 0 { // When compressing the empty slice, we need an output of at least 1 to pass down to the C lib - hint = 1 - } - } - - // Take the minimum of both - if hint > upperBound { - return upperBound - } - return hint -} - // Compress src into dst. If you have a buffer to use, you can pass it to // prevent allocation. If it is too small, or if nil is passed, a new buffer // will be allocated and returned. @@ -100,26 +73,19 @@ func CompressLevel(dst, src []byte, level int) ([]byte, error) { dst = make([]byte, bound) } - // We need unsafe.Pointer(&src[0]) in the Cgo call to avoid "Go pointer to Go pointer" panics. - // This means we need to special case empty input. See: - // https://github.com/golang/go/issues/14210#issuecomment-346402945 - var cWritten C.size_t - if len(src) == 0 { - cWritten = C.ZSTD_compress( - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(nil), - C.size_t(0), - C.int(level)) - } else { - cWritten = C.ZSTD_compress( - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(&src[0]), - C.size_t(len(src)), - C.int(level)) + srcPtr := C.uintptr_t(uintptr(0)) // Do not point anywhere, if src is empty + if len(src) > 0 { + srcPtr = C.uintptr_t(uintptr(unsafe.Pointer(&src[0]))) } + cWritten := C.ZSTD_compress_wrapper( + C.uintptr_t(uintptr(unsafe.Pointer(&dst[0]))), + C.size_t(len(dst)), + srcPtr, + C.size_t(len(src)), + C.int(level)) + + runtime.KeepAlive(src) written := int(cWritten) // Check if the return is an Error code if err := getError(written); err != nil { @@ -135,25 +101,43 @@ func Decompress(dst, src []byte) ([]byte, error) { if len(src) == 0 { return []byte{}, ErrEmptySlice } + decompress := func(dst, src []byte) ([]byte, error) { - bound := decompressSizeHint(src) - if cap(dst) >= bound { - dst = dst[0:cap(dst)] - } else { - dst = make([]byte, bound) + cWritten := C.ZSTD_decompress_wrapper( + C.uintptr_t(uintptr(unsafe.Pointer(&dst[0]))), + C.size_t(len(dst)), + C.uintptr_t(uintptr(unsafe.Pointer(&src[0]))), + C.size_t(len(src))) + + runtime.KeepAlive(src) + written := int(cWritten) + // Check error + if err := getError(written); err != nil { + return nil, err + } + return dst[:written], nil } - written := int(C.ZSTD_decompress( - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(&src[0]), - C.size_t(len(src)))) - err := getError(written) - if err == nil { - return dst[:written], nil + if len(dst) == 0 { + // Attempt to use zStd to determine decompressed size (may result in error or 0) + size := int(C.size_t(C.ZSTD_getDecompressedSize(unsafe.Pointer(&src[0]), C.size_t(len(src))))) + + if err := getError(size); err != nil { + return nil, err + } + + if size > 0 { + dst = make([]byte, size) + } else { + dst = make([]byte, len(src)*3) // starting guess + } } - if !IsDstSizeTooSmallError(err) { - return nil, err + for i := 0; i < 3; i++ { // 3 tries to allocate a bigger buffer + result, err := decompress(dst, src) + if !IsDstSizeTooSmallError(err) { + return result, err + } + dst = make([]byte, len(dst)*2) // Grow buffer by 2 } // We failed getting a dst buffer of correct size, use stream API diff --git a/vendor/github.com/DataDog/zstd/zstd.h b/vendor/github.com/DataDog/zstd/zstd.h index c26aceed..72080ea8 100644 --- a/vendor/github.com/DataDog/zstd/zstd.h +++ b/vendor/github.com/DataDog/zstd/zstd.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,61 +14,27 @@ extern "C" { #ifndef ZSTD_H_235446 #define ZSTD_H_235446 -/* ====== Dependencies ======*/ +/* ====== Dependency ======*/ #include /* INT_MAX */ #include /* size_t */ /* ===== ZSTDLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDLIB_VISIBLE - /* Backwards compatibility with old macro name */ -# ifdef ZSTDLIB_VISIBILITY -# define ZSTDLIB_VISIBLE ZSTDLIB_VISIBILITY -# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) +#ifndef ZSTDLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default"))) # else -# define ZSTDLIB_VISIBLE +# define ZSTDLIB_VISIBILITY # endif #endif - -#ifndef ZSTDLIB_HIDDEN -# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) -# else -# define ZSTDLIB_HIDDEN -# endif -#endif - #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDLIB_API ZSTDLIB_VISIBLE +# define ZSTDLIB_API ZSTDLIB_VISIBILITY #endif -/* Deprecation warnings : - * Should these warnings be a problem, it is generally possible to disable them, - * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. - * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. - */ -#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS -# define ZSTD_DEPRECATED(message) /* disable deprecation warnings */ -#else -# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ -# define ZSTD_DEPRECATED(message) [[deprecated(message)]] -# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) -# define ZSTD_DEPRECATED(message) __attribute__((deprecated(message))) -# elif defined(__GNUC__) && (__GNUC__ >= 3) -# define ZSTD_DEPRECATED(message) __attribute__((deprecated)) -# elif defined(_MSC_VER) -# define ZSTD_DEPRECATED(message) __declspec(deprecated(message)) -# else -# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") -# define ZSTD_DEPRECATED(message) -# endif -#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ - /******************************************************************************* Introduction @@ -106,22 +71,17 @@ extern "C" { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 5 -#define ZSTD_VERSION_RELEASE 5 -#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) +#define ZSTD_VERSION_MINOR 4 +#define ZSTD_VERSION_RELEASE 4 -/*! ZSTD_versionNumber() : - * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ -ZSTDLIB_API unsigned ZSTD_versionNumber(void); +#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) +ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */ #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str #define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) - -/*! ZSTD_versionString() : - * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ -ZSTDLIB_API const char* ZSTD_versionString(void); +ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ /* ************************************* * Default constant @@ -144,13 +104,13 @@ ZSTDLIB_API const char* ZSTD_versionString(void); #define ZSTD_BLOCKSIZE_MAX (1<= ZSTD_compressBound(srcSize)` guarantees that zstd will have - * enough space to successfully compress the data. + * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. * @return : compressed size written into `dst` (<= `dstCapacity), * or an error code if it fails (which can be tested using ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, @@ -199,11 +159,9 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t * "empty", "unknown" and "error" results to the same return value (0), * while ZSTD_getFrameContentSize() gives them separate return values. * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */ -ZSTD_DEPRECATED("Replaced by ZSTD_getFrameContentSize") -ZSTDLIB_API -unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); +ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); -/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+ +/*! ZSTD_findFrameCompressedSize() : * `src` should point to the start of a ZSTD frame or skippable frame. * `srcSize` must be >= first frame size * @return : the compressed size of the first frame starting at `src`, @@ -213,35 +171,12 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize) /*====== Helper functions ======*/ -/* ZSTD_compressBound() : - * maximum compressed size in worst case single-pass scenario. - * When invoking `ZSTD_compress()` or any other one-pass compression function, - * it's recommended to provide @dstCapacity >= ZSTD_compressBound(srcSize) - * as it eliminates one potential failure scenario, - * aka not enough room in dst buffer to write the compressed frame. - * Note : ZSTD_compressBound() itself can fail, if @srcSize > ZSTD_MAX_INPUT_SIZE . - * In which case, ZSTD_compressBound() will return an error code - * which can be tested using ZSTD_isError(). - * - * ZSTD_COMPRESSBOUND() : - * same as ZSTD_compressBound(), but as a macro. - * It can be used to produce constants, which can be useful for static allocation, - * for example to size a static array on stack. - * Will produce constant value 0 if srcSize too large. - */ -#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00LLU : 0xFF00FF00U) -#define ZSTD_COMPRESSBOUND(srcSize) (((size_t)(srcSize) >= ZSTD_MAX_INPUT_SIZE) ? 0 : (srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ -ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ -/* ZSTD_isError() : - * Most ZSTD_* functions returning a size_t value can be tested for error, - * using ZSTD_isError(). - * @return 1 if error, 0 otherwise - */ +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ +ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ -ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ -ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ /*************************************** @@ -259,7 +194,7 @@ ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compres */ typedef struct ZSTD_CCtx_s ZSTD_CCtx; ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); -ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /*! ZSTD_compressCCtx() : * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. @@ -282,7 +217,7 @@ ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, * Use one context per thread for parallel execution. */ typedef struct ZSTD_DCtx_s ZSTD_DCtx; ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); -ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /*! ZSTD_decompressDCtx() : * Same as ZSTD_decompress(), @@ -294,9 +229,9 @@ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, const void* src, size_t srcSize); -/********************************************* -* Advanced compression API (Requires v1.4.0+) -**********************************************/ +/*************************************** +* Advanced compression API +***************************************/ /* API design : * Parameters are pushed one by one into an existing context, @@ -307,7 +242,7 @@ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, * * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). * - * This API supersedes all other "advanced" API entry points in the experimental section. + * This API supercedes all other "advanced" API entry points in the experimental section. * In the future, we expect to remove from experimental API entry points which are redundant with this API. */ @@ -326,6 +261,7 @@ typedef enum { ZSTD_fast=1, Only the order (from fast to strong) is guaranteed */ } ZSTD_strategy; + typedef enum { /* compression parameters @@ -338,10 +274,7 @@ typedef enum { * Default level is ZSTD_CLEVEL_DEFAULT==3. * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT. * Note 1 : it's possible to pass a negative compression level. - * Note 2 : setting a level does not automatically set all other compression parameters - * to default. Setting this will however eventually dynamically impact the compression - * parameters which have not been manually set. The manually set - * ones will 'stick'. */ + * Note 2 : setting a level resets all other compression parameters to default */ /* Advanced compression parameters : * It's possible to pin down compression parameters to some specific values. * In which case, these values are no longer dynamically selected by the compressor */ @@ -391,15 +324,14 @@ typedef enum { * The higher the value of selected strategy, the more complex it is, * resulting in stronger and slower compression. * Special: value 0 means "use default strategy". */ + /* LDM mode parameters */ ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. * This parameter is designed to improve compression ratio * for large inputs, by finding large matches at long distance. * It increases memory usage and window size. * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB - * except when expressly set to a different value. - * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and - * compression strategy >= ZSTD_btopt (== compression level 16+) */ + * except when expressly set to a different value. */ ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. * Larger values increase memory usage and compression ratio, * but decrease compression speed. @@ -430,24 +362,20 @@ typedef enum { ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ /* multi-threading parameters */ - /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). - * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. - * In a situation where it's unknown if the linked library supports multi-threading or not, - * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. - */ + /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * They return an error otherwise. */ ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. - * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : + * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() : * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, - * while compression is performed in parallel, within worker thread(s). + * while compression work is performed in parallel, within worker threads. * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). * More workers improve speed, but also increase memory usage. - * Default value is `0`, aka "single-threaded mode" : no worker is spawned, - * compression is performed inside Caller's thread, and all invocations are blocking */ + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */ ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. * 0 means default, which is dynamically determined based on compression parameters. - * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. + * Job size must be a minimum of overlap size, or 1 MB, whichever is largest. * The minimum size is automatically and transparently enforced. */ ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. @@ -472,16 +400,6 @@ typedef enum { * ZSTD_c_literalCompressionMode * ZSTD_c_targetCBlockSize * ZSTD_c_srcSizeHint - * ZSTD_c_enableDedicatedDictSearch - * ZSTD_c_stableInBuffer - * ZSTD_c_stableOutBuffer - * ZSTD_c_blockDelimiters - * ZSTD_c_validateSequences - * ZSTD_c_useBlockSplitter - * ZSTD_c_useRowMatchFinder - * ZSTD_c_prefetchCDictTables - * ZSTD_c_enableSeqProducerFallback - * ZSTD_c_maxBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly; * also, the enums values themselves are unstable and can still change. @@ -492,19 +410,7 @@ typedef enum { ZSTD_c_experimentalParam4=1001, ZSTD_c_experimentalParam5=1002, ZSTD_c_experimentalParam6=1003, - ZSTD_c_experimentalParam7=1004, - ZSTD_c_experimentalParam8=1005, - ZSTD_c_experimentalParam9=1006, - ZSTD_c_experimentalParam10=1007, - ZSTD_c_experimentalParam11=1008, - ZSTD_c_experimentalParam12=1009, - ZSTD_c_experimentalParam13=1010, - ZSTD_c_experimentalParam14=1011, - ZSTD_c_experimentalParam15=1012, - ZSTD_c_experimentalParam16=1013, - ZSTD_c_experimentalParam17=1014, - ZSTD_c_experimentalParam18=1015, - ZSTD_c_experimentalParam19=1016 + ZSTD_c_experimentalParam7=1004 } ZSTD_cParameter; typedef struct { @@ -567,7 +473,7 @@ typedef enum { * They will be used to compress next frame. * Resetting session never fails. * - The parameters : changes all parameters back to "default". - * This also removes any reference to any dictionary or external sequence producer. + * This removes any reference to any dictionary too. * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) * - Both : similar to resetting the session, followed by resetting parameters. @@ -580,8 +486,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset); * Should cctx hold data from a previously unfinished frame, everything about it is forgotten. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - The function is always blocking, returns when compression is completed. - * NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have - * enough space to successfully compress the data, though it is possible it fails for other reasons. + * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. * @return : compressed size written into `dst` (<= `dstCapacity), * or an error code if it fails (which can be tested using ZSTD_isError()). */ @@ -590,9 +495,9 @@ ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, const void* src, size_t srcSize); -/*********************************************** -* Advanced decompression API (Requires v1.4.0+) -************************************************/ +/*************************************** +* Advanced decompression API +***************************************/ /* The advanced API pushes parameters one by one into an existing DCtx context. * Parameters are sticky, and remain valid for all following frames @@ -614,19 +519,11 @@ typedef enum { /* note : additional experimental parameters are also available * within the experimental section of the API. * At the time of this writing, they include : - * ZSTD_d_format - * ZSTD_d_stableOutBuffer - * ZSTD_d_forceIgnoreChecksum - * ZSTD_d_refMultipleDDicts - * ZSTD_d_disableHuffmanAssembly + * ZSTD_c_format * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly */ - ZSTD_d_experimentalParam1=1000, - ZSTD_d_experimentalParam2=1001, - ZSTD_d_experimentalParam3=1002, - ZSTD_d_experimentalParam4=1003, - ZSTD_d_experimentalParam5=1004 + ZSTD_d_experimentalParam1=1000 } ZSTD_dParameter; @@ -740,7 +637,7 @@ typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ /*===== ZSTD_CStream management functions =====*/ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); -ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /*===== Streaming compression functions =====*/ typedef enum { @@ -756,15 +653,14 @@ typedef enum { : note : multithreaded compression will block to flush as much output as possible. */ } ZSTD_EndDirective; -/*! ZSTD_compressStream2() : Requires v1.4.0+ +/*! ZSTD_compressStream2() : * Behaves about the same as ZSTD_compressStream, with additional control on end directive. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) * - output->pos must be <= dstCapacity, input->pos must be <= srcSize * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. - * - endOp must be a valid directive * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. - * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, + * - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available, * and then immediately returns, just indicating that there is some data remaining to be flushed. * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. @@ -802,9 +698,11 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output /* ***************************************************************************** - * This following is a legacy streaming API, available since v1.0+ . + * This following is a legacy streaming API. * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). * It is redundant, but remains fully supported. + * Advanced parameters and dictionary compression can only be used through the + * new API. ******************************************************************************/ /*! @@ -813,9 +711,6 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); - * - * Note that ZSTD_initCStream() clears any previously set dictionary. Use the new API - * to compress with a dictionary. */ ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); /*! @@ -862,35 +757,17 @@ typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ /*===== ZSTD_DStream management functions =====*/ ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); -ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /*===== Streaming decompression functions =====*/ -/*! ZSTD_initDStream() : - * Initialize/reset DStream state for new decompression operation. - * Call before new decompression operation using same DStream. +/* This function is redundant with the advanced API and equivalent to: * - * Note : This function is redundant with the advanced API and equivalent to: - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_reset(zds); * ZSTD_DCtx_refDDict(zds, NULL); */ ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); -/*! ZSTD_decompressStream() : - * Streaming decompression function. - * Call repetitively to consume full input updating it as necessary. - * Function will update both input and output `pos` fields exposing current state via these fields: - * - `input.pos < input.size`, some input remaining and caller should provide remaining input - * on the next call. - * - `output.pos < output.size`, decoder finished and flushed all remaining buffers. - * - `output.pos == output.size`, potentially uncflushed data present in the internal buffers, - * call ZSTD_decompressStream() again to flush remaining data to output. - * Note : with no additional input, amount of data flushed <= ZSTD_BLOCKSIZE_MAX. - * - * @return : 0 when a frame is completely decoded and fully flushed, - * or an error code, which can be tested using ZSTD_isError(), - * or any other value > 0, which means there is some decoding or flushing to do to complete current frame. - */ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ @@ -903,7 +780,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output /*! ZSTD_compress_usingDict() : * Compression at an explicit compression level using a Dictionary. * A dictionary can be any arbitrary data segment (also called a prefix), - * or a buffer with specified information (see zdict.h). + * or a buffer with specified information (see dictBuilder/zdict.h). * Note : This function loads the dictionary, resulting in significant startup delay. * It's intended for a dictionary used only once. * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ @@ -946,8 +823,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize int compressionLevel); /*! ZSTD_freeCDict() : - * Function frees memory allocated by ZSTD_createCDict(). - * If a NULL pointer is passed, no operation is performed. */ + * Function frees memory allocated by ZSTD_createCDict(). */ ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); /*! ZSTD_compress_usingCDict() : @@ -969,8 +845,7 @@ typedef struct ZSTD_DDict_s ZSTD_DDict; ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); /*! ZSTD_freeDDict() : - * Function frees memory allocated with ZSTD_createDDict() - * If a NULL pointer is passed, no operation is performed. */ + * Function frees memory allocated with ZSTD_createDDict() */ ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); /*! ZSTD_decompress_usingDDict() : @@ -986,30 +861,24 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, * Dictionary helper functions *******************************/ -/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ +/*! ZSTD_getDictID_fromDict() : * Provides the dictID stored within dictionary. * if @return == 0, the dictionary is not conformant with Zstandard specification. * It can still be loaded, but as a content-only dictionary. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); -/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ - * Provides the dictID of the dictionary loaded into `cdict`. - * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. - * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ -ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); - -/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ +/*! ZSTD_getDictID_fromDDict() : * Provides the dictID of the dictionary loaded into `ddict`. * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); -/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ +/*! ZSTD_getDictID_fromFrame() : * Provides the dictID required to decompressed the frame stored within `src`. * If @return == 0, the dictID could not be decoded. * This could for one of the following reasons : * - The frame does not require a dictionary to be decoded (most common case). - * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden piece of information. + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). * - This is not a Zstandard frame. @@ -1018,26 +887,23 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); /******************************************************************************* - * Advanced dictionary and prefix API (Requires v1.4.0+) + * Advanced dictionary and prefix API * * This API allows dictionaries to be used with ZSTD_compress2(), - * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). - * Dictionaries are sticky, they remain valid when same context is re-used, - * they only reset when the context is reset - * with ZSTD_reset_parameters or ZSTD_reset_session_and_parameters. - * In contrast, Prefixes are single-use. + * ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and + * only reset with the context is reset with ZSTD_reset_parameters or + * ZSTD_reset_session_and_parameters. Prefixes are single-use. ******************************************************************************/ -/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ +/*! ZSTD_CCtx_loadDictionary() : * Create an internal CDict from `dict` buffer. * Decompression will have to use same dictionary. * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary, * meaning "return to no-dictionary mode". - * Note 1 : Dictionary is sticky, it will be used for all future compressed frames, - * until parameters are reset, a new dictionary is loaded, or the dictionary - * is explicitly invalidated by loading a NULL dictionary. + * Note 1 : Dictionary is sticky, it will be used for all future compressed frames. + * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters). * Note 2 : Loading a dictionary involves building tables. * It's also a CPU consuming operation, with non-negligible impact on latency. * Tables are dependent on compression parameters, and for this reason, @@ -1046,18 +912,14 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead. * In such a case, dictionary buffer must outlive its users. * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced() - * to precisely select how dictionary content must be interpreted. - * Note 5 : This method does not benefit from LDM (long distance mode). - * If you want to employ LDM on some large dictionary content, - * prefer employing ZSTD_CCtx_refPrefix() described below. - */ + * to precisely select how dictionary content must be interpreted. */ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); -/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ - * Reference a prepared dictionary, to be used for all future compressed frames. +/*! ZSTD_CCtx_refCDict() : + * Reference a prepared dictionary, to be used for all next compressed frames. * Note that compression parameters are enforced from within CDict, * and supersede any compression parameter previously set within CCtx. - * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. * The dictionary will remain valid for future compressed frames using same CCtx. * @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -1067,13 +929,12 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); -/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ +/*! ZSTD_CCtx_refPrefix() : * Reference a prefix (single-usage dictionary) for next compressed frame. * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). * Decompression will need same prefix to properly regenerate data. * Compressing with a prefix is similar in outcome as performing a diff and compressing it, * but performs much faster, especially during decompression (compression speed is tunable with compression level). - * This method is compatible with LDM (long distance mode). * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary * Note 1 : Prefix buffer is referenced. It **must** outlive compression. @@ -1089,10 +950,10 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize); -/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ - * Create an internal DDict from dict buffer, to be used to decompress all future frames. - * The dictionary remains valid for all future frames, until explicitly invalidated, or - * a new dictionary is loaded. +/*! ZSTD_DCtx_loadDictionary() : + * Create an internal DDict from dict buffer, + * to be used to decompress next frames. + * The dictionary remains valid for all future frames, until explicitly invalidated. * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, * meaning "return to no-dictionary mode". @@ -1106,26 +967,18 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, */ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ +/*! ZSTD_DCtx_refDDict() : * Reference a prepared dictionary, to be used to decompress next frames. * The dictionary remains active for decompression of future frames using same DCtx. - * - * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function - * will store the DDict references in a table, and the DDict used for decompression - * will be determined at decompression time, as per the dict ID in the frame. - * The memory for the table is allocated on the first call to refDDict, and can be - * freed with ZSTD_freeDCtx(). - * - * If called with ZSTD_d_refMultipleDDicts disabled (the default), only one dictionary - * will be managed, and referencing a dictionary effectively "discards" any previous one. - * * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. * Special: referencing a NULL DDict means "return to no-dictionary mode". * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. */ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ +/*! ZSTD_DCtx_refPrefix() : * Reference a prefix (single-usage dictionary) to decompress next frame. * This is the reverse operation of ZSTD_CCtx_refPrefix(), * and must use the same prefix as the one used during compression. @@ -1146,7 +999,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, /* === Memory management === */ -/*! ZSTD_sizeof_*() : Requires v1.4.0+ +/*! ZSTD_sizeof_*() : * These functions give the _current_ memory usage of selected object. * Note that object memory usage can evolve (increase or decrease) over time. */ ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); @@ -1171,17 +1024,6 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) #define ZSTD_H_ZSTD_STATIC_LINKING_ONLY -/* This can be overridden externally to hide static symbols. */ -#ifndef ZSTDLIB_STATIC_API -# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE -# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE -# else -# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE -# endif -#endif - /**************************************************************************************** * experimental API (static linking only) **************************************************************************************** @@ -1216,7 +1058,6 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ #define ZSTD_STRATEGY_MIN ZSTD_fast #define ZSTD_STRATEGY_MAX ZSTD_btultra2 -#define ZSTD_BLOCKSIZE_MAX_MIN (1 << 10) /* The minimum valid max blocksize. Maximum blocksizes smaller than this make compressBound() inaccurate. */ #define ZSTD_OVERLAPLOG_MIN 0 @@ -1245,46 +1086,30 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #define ZSTD_SRCSIZEHINT_MIN 0 #define ZSTD_SRCSIZEHINT_MAX INT_MAX +/* internal */ +#define ZSTD_HASHLOG3_MAX 17 + /* --- Advanced types --- */ typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params; typedef struct { - unsigned int offset; /* The offset of the match. (NOT the same as the offset code) - * If offset == 0 and matchLength == 0, this sequence represents the last - * literals in the block of litLength size. - */ - - unsigned int litLength; /* Literal length of the sequence. */ - unsigned int matchLength; /* Match length of the sequence. */ - - /* Note: Users of this API may provide a sequence with matchLength == litLength == offset == 0. - * In this case, we will treat the sequence as a marker for a block boundary. - */ - - unsigned int rep; /* Represents which repeat offset is represented by the field 'offset'. - * Ranges from [0, 3]. - * - * Repeat offsets are essentially previous offsets from previous sequences sorted in - * recency order. For more detail, see doc/zstd_compression_format.md - * - * If rep == 0, then 'offset' does not contain a repeat offset. - * If rep > 0: - * If litLength != 0: - * rep == 1 --> offset == repeat_offset_1 - * rep == 2 --> offset == repeat_offset_2 - * rep == 3 --> offset == repeat_offset_3 - * If litLength == 0: - * rep == 1 --> offset == repeat_offset_2 - * rep == 2 --> offset == repeat_offset_3 - * rep == 3 --> offset == repeat_offset_1 - 1 - * - * Note: This field is optional. ZSTD_generateSequences() will calculate the value of - * 'rep', but repeat offsets do not necessarily need to be calculated from an external - * sequence provider's perspective. For example, ZSTD_compressSequences() does not - * use this 'rep' field at all (as of now). - */ + unsigned int matchPos; /* Match pos in dst */ + /* If seqDef.offset > 3, then this is seqDef.offset - 3 + * If seqDef.offset < 3, then this is the corresponding repeat offset + * But if seqDef.offset < 3 and litLength == 0, this is the + * repeat offset before the corresponding repeat offset + * And if seqDef.offset == 3 and litLength == 0, this is the + * most recent repeat offset - 1 + */ + unsigned int offset; + unsigned int litLength; /* Literal length */ + unsigned int matchLength; /* Match length */ + /* 0 when seq not rep and seqDef.offset otherwise + * when litLength == 0 this will be <= 4, otherwise <= 3 like normal + */ + unsigned int rep; } ZSTD_Sequence; typedef struct { @@ -1326,18 +1151,6 @@ typedef enum { * Decoder cannot recognise automatically this format, requiring this instruction. */ } ZSTD_format_e; -typedef enum { - /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ - ZSTD_d_validateChecksum = 0, - ZSTD_d_ignoreChecksum = 1 -} ZSTD_forceIgnoreChecksum_e; - -typedef enum { - /* Note: this enum controls ZSTD_d_refMultipleDDicts */ - ZSTD_rmd_refSingleDDict = 0, - ZSTD_rmd_refMultipleDDicts = 1 -} ZSTD_refMultipleDDicts_e; - typedef enum { /* Note: this enum and the behavior it controls are effectively internal * implementation details of the compressor. They are expected to continue @@ -1386,18 +1199,9 @@ typedef enum { ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ } ZSTD_literalCompressionMode_e; -typedef enum { - /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final - * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable - * or ZSTD_ps_disable allow for a force enable/disable the feature. - */ - ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ - ZSTD_ps_enable = 1, /* Force-enable the feature */ - ZSTD_ps_disable = 2 /* Do not use the feature */ -} ZSTD_paramSwitch_e; /*************************************** -* Frame header and size functions +* Frame size functions ***************************************/ /*! ZSTD_findDecompressedSize() : @@ -1421,14 +1225,14 @@ typedef enum { * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to * read each contained frame header. This is fast as most of the data is skipped, * however it does mean that all frame data must be present and valid. */ -ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); +ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); /*! ZSTD_decompressBound() : * `src` should point to the start of a series of ZSTD encoded and/or skippable frames * `srcSize` must be the _exact_ size of this series * (i.e. there should be a frame boundary at `src + srcSize`) * @return : - upper-bound for the decompressed size of all data in all successive frames - * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * - if an error occured: ZSTD_CONTENTSIZE_ERROR * * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. @@ -1436,202 +1240,22 @@ ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: * upper-bound = # blocks * min(128 KB, Window_Size) */ -ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); +ZSTDLIB_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); /*! ZSTD_frameHeaderSize() : * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. * @return : size of the Frame Header, * or an error code (if srcSize is too small) */ -ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); - -typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; -typedef struct { - unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ - unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ - unsigned blockSizeMax; - ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ - unsigned headerSize; - unsigned dictID; - unsigned checksumFlag; - unsigned _reserved1; - unsigned _reserved2; -} ZSTD_frameHeader; - -/*! ZSTD_getFrameHeader() : - * decode Frame Header, or requires larger `srcSize`. - * @return : 0, `zfhPtr` is correctly filled, - * >0, `srcSize` is too small, value is wanted `srcSize` amount, - * or an error code, which can be tested using ZSTD_isError() */ -ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ -/*! ZSTD_getFrameHeader_advanced() : - * same as ZSTD_getFrameHeader(), - * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ -ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); +ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); -/*! ZSTD_decompressionMargin() : - * Zstd supports in-place decompression, where the input and output buffers overlap. - * In this case, the output buffer must be at least (Margin + Output_Size) bytes large, - * and the input buffer must be at the end of the output buffer. - * - * _______________________ Output Buffer ________________________ - * | | - * | ____ Input Buffer ____| - * | | | - * v v v - * |---------------------------------------|-----------|----------| - * ^ ^ ^ - * |___________________ Output_Size ___________________|_ Margin _| - * - * NOTE: See also ZSTD_DECOMPRESSION_MARGIN(). - * NOTE: This applies only to single-pass decompression through ZSTD_decompress() or - * ZSTD_decompressDCtx(). - * NOTE: This function supports multi-frame input. - * - * @param src The compressed frame(s) - * @param srcSize The size of the compressed frame(s) - * @returns The decompression margin or an error that can be checked with ZSTD_isError(). - */ -ZSTDLIB_STATIC_API size_t ZSTD_decompressionMargin(const void* src, size_t srcSize); - -/*! ZSTD_DECOMPRESS_MARGIN() : - * Similar to ZSTD_decompressionMargin(), but instead of computing the margin from - * the compressed frame, compute it from the original size and the blockSizeLog. - * See ZSTD_decompressionMargin() for details. - * - * WARNING: This macro does not support multi-frame input, the input must be a single - * zstd frame. If you need that support use the function, or implement it yourself. - * - * @param originalSize The original uncompressed size of the data. - * @param blockSize The block size == MIN(windowSize, ZSTD_BLOCKSIZE_MAX). - * Unless you explicitly set the windowLog smaller than - * ZSTD_BLOCKSIZELOG_MAX you can just use ZSTD_BLOCKSIZE_MAX. - */ -#define ZSTD_DECOMPRESSION_MARGIN(originalSize, blockSize) ((size_t)( \ - ZSTD_FRAMEHEADERSIZE_MAX /* Frame header */ + \ - 4 /* checksum */ + \ - ((originalSize) == 0 ? 0 : 3 * (((originalSize) + (blockSize) - 1) / blockSize)) /* 3 bytes per block */ + \ - (blockSize) /* One block of margin */ \ - )) - -typedef enum { - ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ - ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ -} ZSTD_sequenceFormat_e; - -/*! ZSTD_sequenceBound() : - * `srcSize` : size of the input buffer - * @return : upper-bound for the number of sequences that can be generated - * from a buffer of srcSize bytes - * - * note : returns number of sequences - to get bytes, multiply by sizeof(ZSTD_Sequence). - */ -ZSTDLIB_STATIC_API size_t ZSTD_sequenceBound(size_t srcSize); - -/*! ZSTD_generateSequences() : - * Generate sequences using ZSTD_compress2(), given a source buffer. - * - * Each block will end with a dummy sequence - * with offset == 0, matchLength == 0, and litLength == length of last literals. - * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) - * simply acts as a block delimiter. - * - * @zc can be used to insert custom compression params. - * This function invokes ZSTD_compress2(). - * - * The output of this function can be fed into ZSTD_compressSequences() with CCtx - * setting of ZSTD_c_blockDelimiters as ZSTD_sf_explicitBlockDelimiters - * @return : number of sequences generated - */ - -ZSTDLIB_STATIC_API size_t -ZSTD_generateSequences( ZSTD_CCtx* zc, - ZSTD_Sequence* outSeqs, size_t outSeqsSize, - const void* src, size_t srcSize); - -/*! ZSTD_mergeBlockDelimiters() : - * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals - * by merging them into the literals of the next sequence. - * - * As such, the final generated result has no explicit representation of block boundaries, - * and the final last literals segment is not represented in the sequences. - * - * The output of this function can be fed into ZSTD_compressSequences() with CCtx - * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters - * @return : number of sequences left after merging - */ -ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); - -/*! ZSTD_compressSequences() : - * Compress an array of ZSTD_Sequence, associated with @src buffer, into dst. - * @src contains the entire input (not just the literals). - * If @srcSize > sum(sequence.length), the remaining bytes are considered all literals - * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) - * The entire source is compressed into a single frame. - * - * The compression behavior changes based on cctx params. In particular: - * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain - * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on - * the block size derived from the cctx, and sequences may be split. This is the default setting. - * - * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain - * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. - * - * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined - * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for - * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. - * - * In addition to the two adjustable experimental params, there are other important cctx params. - * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. - * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. - * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset - * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md - * - * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. - * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, - * and cannot emit an RLE block that disagrees with the repcode history - * @return : final compressed size, or a ZSTD error code. - */ -ZSTDLIB_STATIC_API size_t -ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, - const void* src, size_t srcSize); - - -/*! ZSTD_writeSkippableFrame() : - * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. - * - * Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, - * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. - * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so - * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. - * - * Returns an error if destination buffer is not large enough, if the source size is not representable - * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). - * - * @return : number of bytes written or a ZSTD error. - */ -ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, - const void* src, size_t srcSize, unsigned magicVariant); - -/*! ZSTD_readSkippableFrame() : - * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. - * - * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, - * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested - * in the magicVariant. - * - * Returns an error if destination buffer is not large enough, or if the frame is not skippable. - * - * @return : number of bytes written or a ZSTD error. +/*! ZSTD_getSequences() : + * Extract sequences from the sequence store + * zc can be used to insert custom compression params. + * This function invokes ZSTD_compress2 + * @return : number of sequences extracted */ -ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, - const void* src, size_t srcSize); - -/*! ZSTD_isSkippableFrame() : - * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. - */ -ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); - +ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize); /*************************************** @@ -1639,35 +1263,27 @@ ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); ***************************************/ /*! ZSTD_estimate*() : - * These functions make it possible to estimate memory usage - * of a future {D,C}Ctx, before its creation. - * - * ZSTD_estimateCCtxSize() will provide a memory budget large enough - * for any compression level up to selected one. - * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate - * does not include space for a window buffer. - * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. - * The estimate will assume the input may be arbitrarily large, - * which is the worst case. - * - * When srcSize can be bound by a known and rather "small" value, - * this fact can be used to provide a tighter estimation - * because the CCtx compression context will need less memory. - * This tighter estimation can be provided by more advanced functions - * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), - * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). - * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. - * - * Note : only single-threaded compression is supported. - * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. - * - * Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the Block-Level Sequence Producer API at this time. - * Size estimates assume that no external sequence producer is registered. - */ -ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); + * These functions make it possible to estimate memory usage of a future + * {D,C}Ctx, before its creation. + * + * ZSTD_estimateCCtxSize() will provide a budget large enough for any + * compression level up to selected one. Unlike ZSTD_estimateCStreamSize*(), + * this estimate does not include space for a window buffer, so this estimate + * is guaranteed to be enough for single-shot compressions, but not streaming + * compressions. It will however assume the input may be arbitrarily large, + * which is the worst case. If srcSize is known to always be small, + * ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with + * ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with + * ZSTD_CCtxParams_setParameter(). + * + * Note: only single-threaded compression is supported. This function will + * return an error code if ZSTD_c_nbWorkers is >= 1. */ +ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); /*! ZSTD_estimateCStreamSize() : * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. @@ -1681,26 +1297,21 @@ ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), * an internal ?Dict will be created, which additional size is not estimated here. - * In this case, get total size by adding ZSTD_estimate?DictSize - * Note 2 : only single-threaded compression is supported. - * ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. - * Note 3 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time. - * Size estimates assume that no external sequence producer is registered. - */ -ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + * In this case, get total size by adding ZSTD_estimate?DictSize */ +ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); /*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. */ -ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); /*! ZSTD_initStatic*() : * Initialize an object using a pre-allocated fixed-size buffer. @@ -1723,20 +1334,20 @@ ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadM * Limitation 2 : static cctx currently not compatible with multi-threading. * Limitation 3 : static dctx is incompatible with legacy support. */ -ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ +ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ -ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ +ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ -ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( +ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams); -ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( +ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, @@ -1751,54 +1362,24 @@ ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); typedef void (*ZSTD_freeFunction) (void* opaque, void* address); typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; -static -#ifdef __GNUC__ -__attribute__((__unused__)) -#endif -ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ +static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ -ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams, ZSTD_customMem customMem); -/*! Thread pool : - * These prototypes make it possible to share a thread pool among multiple compression contexts. - * This can limit resources for applications with multiple threads where each one uses - * a threaded compression mode (via ZSTD_c_nbWorkers parameter). - * ZSTD_createThreadPool creates a new thread pool with a given number of threads. - * Note that the lifetime of such pool must exist while being used. - * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value - * to use an internal thread pool). - * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. - */ -typedef struct POOL_ctx_s ZSTD_threadPool; -ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); -ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); - - -/* - * This API is temporary and is expected to change or disappear in the future! - */ -ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - const ZSTD_CCtx_params* cctxParams, - ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_customMem customMem); /*************************************** @@ -1811,22 +1392,22 @@ ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( * As a consequence, `dictBuffer` **must** outlive CDict, * and its content must remain unmodified throughout the lifetime of CDict. * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ -ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. * `estimatedSrcSize` value is optional, select 0 if not known */ -ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); +ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); /*! ZSTD_getParams() : * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ -ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); +ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); /*! ZSTD_checkCParams() : * Ensure param values remain within authorized range. * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ -ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); +ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); /*! ZSTD_adjustCParams() : * optimize params for a given `srcSize` and `dictSize`. @@ -1834,48 +1415,23 @@ ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); * `dictSize` must be `0` when there is no dictionary. * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. * This function never fails (wide contract) */ -ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); - -/*! ZSTD_CCtx_setCParams() : - * Set all parameters provided within @p cparams into the working @p cctx. - * Note : if modifying parameters during compression (MT mode only), - * note that changes to the .windowLog parameter will be ignored. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()). - * On failure, no parameters are updated. - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams); - -/*! ZSTD_CCtx_setFParams() : - * Set all parameters provided within @p fparams into the working @p cctx. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams); - -/*! ZSTD_CCtx_setParams() : - * Set all parameters provided within @p params into the working @p cctx. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params); +ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); /*! ZSTD_compress_advanced() : * Note : this function is now DEPRECATED. * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. - * This prototype will generate compilation warnings. */ -ZSTD_DEPRECATED("use ZSTD_compress2") -ZSTDLIB_STATIC_API -size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - ZSTD_parameters params); + * This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */ +ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params); /*! ZSTD_compress_usingCDict_advanced() : - * Note : this function is now DEPRECATED. + * Note : this function is now REDUNDANT. * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. - * This prototype will generate compilation warnings. */ -ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") -ZSTDLIB_STATIC_API -size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + * This prototype will be marked as deprecated and generate compilation warning in some future version */ +ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, @@ -1885,18 +1441,18 @@ size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, /*! ZSTD_CCtx_loadDictionary_byReference() : * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); /*! ZSTD_CCtx_loadDictionary_advanced() : * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over * how to load the dictionary (by copy ? by reference ?) * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); /*! ZSTD_CCtx_refPrefix_advanced() : * Same as ZSTD_CCtx_refPrefix(), but gives finer control over * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); /* === experimental parameters === */ /* these parameters can be used with ZSTD_setParameter() @@ -1935,15 +1491,9 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const vo * See the comments on that enum for an explanation of the feature. */ #define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 -/* Controlled with ZSTD_paramSwitch_e enum. - * Default is ZSTD_ps_auto. - * Set to ZSTD_ps_disable to never compress literals. - * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals - * may still be emitted if huffman is not beneficial to use.) - * - * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use - * literals compression based on the compression parameters - specifically, - * negative compression levels do not use literal compression. +/* Controls how the literals are compressed (default is auto). + * The value must be of type ZSTD_literalCompressionMode_e. + * See ZSTD_literalCompressionMode_t enum definition for details. */ #define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 @@ -1958,265 +1508,12 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const vo * but compression ratio may regress significantly if guess considerably underestimates */ #define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 -/* Controls whether the new and experimental "dedicated dictionary search - * structure" can be used. This feature is still rough around the edges, be - * prepared for surprising behavior! - * - * How to use it: - * - * When using a CDict, whether to use this feature or not is controlled at - * CDict creation, and it must be set in a CCtxParams set passed into that - * construction (via ZSTD_createCDict_advanced2()). A compression will then - * use the feature or not based on how the CDict was constructed; the value of - * this param, set in the CCtx, will have no effect. - * - * However, when a dictionary buffer is passed into a CCtx, such as via - * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control - * whether the CDict that is created internally can use the feature or not. - * - * What it does: - * - * Normally, the internal data structures of the CDict are analogous to what - * would be stored in a CCtx after compressing the contents of a dictionary. - * To an approximation, a compression using a dictionary can then use those - * data structures to simply continue what is effectively a streaming - * compression where the simulated compression of the dictionary left off. - * Which is to say, the search structures in the CDict are normally the same - * format as in the CCtx. - * - * It is possible to do better, since the CDict is not like a CCtx: the search - * structures are written once during CDict creation, and then are only read - * after that, while the search structures in the CCtx are both read and - * written as the compression goes along. This means we can choose a search - * structure for the dictionary that is read-optimized. - * - * This feature enables the use of that different structure. - * - * Note that some of the members of the ZSTD_compressionParameters struct have - * different semantics and constraints in the dedicated search structure. It is - * highly recommended that you simply set a compression level in the CCtxParams - * you pass into the CDict creation call, and avoid messing with the cParams - * directly. - * - * Effects: - * - * This will only have any effect when the selected ZSTD_strategy - * implementation supports this feature. Currently, that's limited to - * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. - * - * Note that this means that the CDict tables can no longer be copied into the - * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be - * usable. The dictionary can only be attached or reloaded. - * - * In general, you should expect compression to be faster--sometimes very much - * so--and CDict creation to be slightly slower. Eventually, we will probably - * make this mode the default. - */ -#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 - -/* ZSTD_c_stableInBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells the compressor that input data presented with ZSTD_inBuffer - * will ALWAYS be the same between calls. - * Technically, the @src pointer must never be changed, - * and the @pos field can only be updated by zstd. - * However, it's possible to increase the @size field, - * allowing scenarios where more data can be appended after compressions starts. - * These conditions are checked by the compressor, - * and compression will fail if they are not respected. - * Also, data in the ZSTD_inBuffer within the range [src, src + pos) - * MUST not be modified during compression or it will result in data corruption. - * - * When this flag is enabled zstd won't allocate an input window buffer, - * because the user guarantees it can reference the ZSTD_inBuffer until - * the frame is complete. But, it will still allocate an output buffer - * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also - * avoid the memcpy() from the input buffer to the input window buffer. - * - * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using - * this flag is ALWAYS memory safe, and will never access out-of-bounds - * memory. However, compression WILL fail if conditions are not respected. - * - * WARNING: The data in the ZSTD_inBuffer in the range [src, src + pos) MUST - * not be modified during compression or it will result in data corruption. - * This is because zstd needs to reference data in the ZSTD_inBuffer to find - * matches. Normally zstd maintains its own window buffer for this purpose, - * but passing this flag tells zstd to rely on user provided buffer instead. - */ -#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 - -/* ZSTD_c_stableOutBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells he compressor that the ZSTD_outBuffer will not be resized between - * calls. Specifically: (out.size - out.pos) will never grow. This gives the - * compressor the freedom to say: If the compressed data doesn't fit in the - * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to - * always decompress directly into the output buffer, instead of decompressing - * into an internal buffer and copying to the output buffer. - * - * When this flag is enabled zstd won't allocate an output buffer, because - * it can write directly to the ZSTD_outBuffer. It will still allocate the - * input window buffer (see ZSTD_c_stableInBuffer). - * - * Zstd will check that (out.size - out.pos) never grows and return an error - * if it does. While not strictly necessary, this should prevent surprises. - */ -#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 - -/* ZSTD_c_blockDelimiters - * Default is 0 == ZSTD_sf_noBlockDelimiters. - * - * For use with sequence compression API: ZSTD_compressSequences(). - * - * Designates whether or not the given array of ZSTD_Sequence contains block delimiters - * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. - * See the definition of ZSTD_Sequence for more specifics. - */ -#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 - -/* ZSTD_c_validateSequences - * Default is 0 == disabled. Set to 1 to enable sequence validation. - * - * For use with sequence compression API: ZSTD_compressSequences(). - * Designates whether or not we validate sequences provided to ZSTD_compressSequences() - * during function execution. - * - * Without validation, providing a sequence that does not conform to the zstd spec will cause - * undefined behavior, and may produce a corrupted block. - * - * With validation enabled, if sequence is invalid (see doc/zstd_compression_format.md for - * specifics regarding offset/matchlength requirements) then the function will bail out and - * return an error. - * - */ -#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 - -/* ZSTD_c_useBlockSplitter - * Controlled with ZSTD_paramSwitch_e enum. - * Default is ZSTD_ps_auto. - * Set to ZSTD_ps_disable to never use block splitter. - * Set to ZSTD_ps_enable to always use block splitter. - * - * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use - * block splitting based on the compression parameters. - */ -#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 - -/* ZSTD_c_useRowMatchFinder - * Controlled with ZSTD_paramSwitch_e enum. - * Default is ZSTD_ps_auto. - * Set to ZSTD_ps_disable to never use row-based matchfinder. - * Set to ZSTD_ps_enable to force usage of row-based matchfinder. - * - * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use - * the row-based matchfinder based on support for SIMD instructions and the window log. - * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 - */ -#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 - -/* ZSTD_c_deterministicRefPrefix - * Default is 0 == disabled. Set to 1 to enable. - * - * Zstd produces different results for prefix compression when the prefix is - * directly adjacent to the data about to be compressed vs. when it isn't. - * This is because zstd detects that the two buffers are contiguous and it can - * use a more efficient match finding algorithm. However, this produces different - * results than when the two buffers are non-contiguous. This flag forces zstd - * to always load the prefix in non-contiguous mode, even if it happens to be - * adjacent to the data, to guarantee determinism. - * - * If you really care about determinism when using a dictionary or prefix, - * like when doing delta compression, you should select this option. It comes - * at a speed penalty of about ~2.5% if the dictionary and data happened to be - * contiguous, and is free if they weren't contiguous. We don't expect that - * intentionally making the dictionary and data contiguous will be worth the - * cost to memcpy() the data. - */ -#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 - -/* ZSTD_c_prefetchCDictTables - * Controlled with ZSTD_paramSwitch_e enum. Default is ZSTD_ps_auto. - * - * In some situations, zstd uses CDict tables in-place rather than copying them - * into the working context. (See docs on ZSTD_dictAttachPref_e above for details). - * In such situations, compression speed is seriously impacted when CDict tables are - * "cold" (outside CPU cache). This parameter instructs zstd to prefetch CDict tables - * when they are used in-place. - * - * For sufficiently small inputs, the cost of the prefetch will outweigh the benefit. - * For sufficiently large inputs, zstd will by default memcpy() CDict tables - * into the working context, so there is no need to prefetch. This parameter is - * targeted at a middle range of input sizes, where a prefetch is cheap enough to be - * useful but memcpy() is too expensive. The exact range of input sizes where this - * makes sense is best determined by careful experimentation. - * - * Note: for this parameter, ZSTD_ps_auto is currently equivalent to ZSTD_ps_disable, - * but in the future zstd may conditionally enable this feature via an auto-detection - * heuristic for cold CDicts. - * Use ZSTD_ps_disable to opt out of prefetching under any circumstances. - */ -#define ZSTD_c_prefetchCDictTables ZSTD_c_experimentalParam16 - -/* ZSTD_c_enableSeqProducerFallback - * Allowed values are 0 (disable) and 1 (enable). The default setting is 0. - * - * Controls whether zstd will fall back to an internal sequence producer if an - * external sequence producer is registered and returns an error code. This fallback - * is block-by-block: the internal sequence producer will only be called for blocks - * where the external sequence producer returns an error code. Fallback parsing will - * follow any other cParam settings, such as compression level, the same as in a - * normal (fully-internal) compression operation. - * - * The user is strongly encouraged to read the full Block-Level Sequence Producer API - * documentation (below) before setting this parameter. */ -#define ZSTD_c_enableSeqProducerFallback ZSTD_c_experimentalParam17 - -/* ZSTD_c_maxBlockSize - * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). - * The default is ZSTD_BLOCKSIZE_MAX, and setting to 0 will set to the default. - * - * This parameter can be used to set an upper bound on the blocksize - * that overrides the default ZSTD_BLOCKSIZE_MAX. It cannot be used to set upper - * bounds greater than ZSTD_BLOCKSIZE_MAX or bounds lower than 1KB (will make - * compressBound() inaccurate). Only currently meant to be used for testing. - * - */ -#define ZSTD_c_maxBlockSize ZSTD_c_experimentalParam18 - -/* ZSTD_c_searchForExternalRepcodes - * This parameter affects how zstd parses external sequences, such as sequences - * provided through the compressSequences() API or from an external block-level - * sequence producer. - * - * If set to ZSTD_ps_enable, the library will check for repeated offsets in - * external sequences, even if those repcodes are not explicitly indicated in - * the "rep" field. Note that this is the only way to exploit repcode matches - * while using compressSequences() or an external sequence producer, since zstd - * currently ignores the "rep" field of external sequences. - * - * If set to ZSTD_ps_disable, the library will not exploit repeated offsets in - * external sequences, regardless of whether the "rep" field has been set. This - * reduces sequence compression overhead by about 25% while sacrificing some - * compression ratio. - * - * The default value is ZSTD_ps_auto, for which the library will enable/disable - * based on compression level. - * - * Note: for now, this param only has an effect if ZSTD_c_blockDelimiters is - * set to ZSTD_sf_explicitBlockDelimiters. That may change in the future. - */ -#define ZSTD_c_searchForExternalRepcodes ZSTD_c_experimentalParam19 - /*! ZSTD_CCtx_getParameter() : * Get the requested compression parameter value, selected by enum ZSTD_cParameter, * and store it into int* value. * @return : 0, or an error code (which can be tested with ZSTD_isError()). */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); +ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); /*! ZSTD_CCtx_params : @@ -2231,47 +1528,45 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cPa * These parameters will be applied to * all subsequent frames. * - ZSTD_compressStream2() : Do compression using the CCtx. - * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. + * - ZSTD_freeCCtxParams() : Free the memory. * * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() * for static allocation of CCtx for single-threaded compression. */ -ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); -ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ +ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /*! ZSTD_CCtxParams_reset() : * Reset params to default values. */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); /*! ZSTD_CCtxParams_init() : * Initializes the compression parameters of cctxParams according to * compression level. All other parameters are reset to their default values. */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); +ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); /*! ZSTD_CCtxParams_init_advanced() : * Initializes the compression and frame parameters of cctxParams according to * params. All other parameters are reset to their default values. */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); +ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); -/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ +/*! ZSTD_CCtxParams_setParameter() : * Similar to ZSTD_CCtx_setParameter. * Set one compression parameter, selected by enum ZSTD_cParameter. - * Parameters must be applied to a ZSTD_CCtx using - * ZSTD_CCtx_setParametersUsingCCtxParams(). - * @result : a code representing success or failure (which can be tested with - * ZSTD_isError()). + * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); +ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); /*! ZSTD_CCtxParams_getParameter() : * Similar to ZSTD_CCtx_getParameter. * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); +ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); /*! ZSTD_CCtx_setParametersUsingCCtxParams() : * Apply a set of ZSTD_CCtx_params to the compression context. @@ -2280,7 +1575,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* p * if nbWorkers>=1, new parameters will be picked up at next job, * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( +ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); /*! ZSTD_compressStream2_simpleArgs() : @@ -2289,7 +1584,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( * This variant might be helpful for binders from dynamic languages * which have troubles handling structures containing memory pointers. */ -ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( +ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs ( ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos, @@ -2305,33 +1600,33 @@ ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. * Note 3 : Skippable Frame Identifiers are considered valid. */ -ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); +ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size); /*! ZSTD_createDDict_byReference() : * Create a digested dictionary, ready to start decompression operation without startup delay. * Dictionary content is referenced, and therefore stays in dictBuffer. * It is important that dictBuffer outlives DDict, * it must remain read accessible throughout the lifetime of DDict */ -ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); /*! ZSTD_DCtx_loadDictionary_byReference() : * Same as ZSTD_DCtx_loadDictionary(), * but references `dict` content instead of copying it into `dctx`. * This saves memory if `dict` remains around., * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); /*! ZSTD_DCtx_loadDictionary_advanced() : * Same as ZSTD_DCtx_loadDictionary(), * but gives direct control over * how to load the dictionary (by copy ? by reference ?) * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); /*! ZSTD_DCtx_refPrefix_advanced() : * Same as ZSTD_DCtx_refPrefix(), but gives finer control over * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); /*! ZSTD_DCtx_setMaxWindowSize() : * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. @@ -2340,107 +1635,20 @@ ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const vo * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); - -/*! ZSTD_DCtx_getParameter() : - * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, - * and store it into int* value. - * @return : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); +ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); /* ZSTD_d_format * experimental parameter, * allowing selection between ZSTD_format_e input compression formats */ #define ZSTD_d_format ZSTD_d_experimentalParam1 -/* ZSTD_d_stableOutBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same - * between calls, except for the modifications that zstd makes to pos (the - * caller must not modify pos). This is checked by the decompressor, and - * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer - * MUST be large enough to fit the entire decompressed frame. This will be - * checked when the frame content size is known. The data in the ZSTD_outBuffer - * in the range [dst, dst + pos) MUST not be modified during decompression - * or you will get data corruption. - * - * When this flag is enabled zstd won't allocate an output buffer, because - * it can write directly to the ZSTD_outBuffer, but it will still allocate - * an input buffer large enough to fit any compressed block. This will also - * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. - * If you need to avoid the input buffer allocation use the buffer-less - * streaming API. - * - * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using - * this flag is ALWAYS memory safe, and will never access out-of-bounds - * memory. However, decompression WILL fail if you violate the preconditions. - * - * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST - * not be modified during decompression or you will get data corruption. This - * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate - * matches. Normally zstd maintains its own buffer for this purpose, but passing - * this flag tells zstd to use the user provided buffer. - */ -#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 - -/* ZSTD_d_forceIgnoreChecksum - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable - * - * Tells the decompressor to skip checksum validation during decompression, regardless - * of whether checksumming was specified during compression. This offers some - * slight performance benefits, and may be useful for debugging. - * Param has values of type ZSTD_forceIgnoreChecksum_e - */ -#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 - -/* ZSTD_d_refMultipleDDicts - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable - * - * If enabled and dctx is allocated on the heap, then additional memory will be allocated - * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() - * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead - * store all references. At decompression time, the appropriate dictID is selected - * from the set of DDicts based on the dictID in the frame. - * - * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. - * - * Param has values of byte ZSTD_refMultipleDDicts_e - * - * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory - * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. - * Memory is allocated as per ZSTD_DCtx::customMem. - * - * Although this function allocates memory for the table, the user is still responsible for - * memory management of the underlying ZSTD_DDict* themselves. - */ -#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 - -/* ZSTD_d_disableHuffmanAssembly - * Set to 1 to disable the Huffman assembly implementation. - * The default value is 0, which allows zstd to use the Huffman assembly - * implementation if available. - * - * This parameter can be used to disable Huffman assembly at runtime. - * If you want to disable it at compile time you can define the macro - * ZSTD_DISABLE_ASM. - */ -#define ZSTD_d_disableHuffmanAssembly ZSTD_d_experimentalParam5 - /*! ZSTD_DCtx_setFormat() : - * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). * Instruct the decoder context about what kind of data to decode next. * This instruction is mandatory to decode data without a fully-formed header, * such ZSTD_f_zstd1_magicless for example. * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") -ZSTDLIB_STATIC_API -size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); +ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); /*! ZSTD_decompressStream_simpleArgs() : * Same as ZSTD_decompressStream(), @@ -2448,7 +1656,7 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); * This can be helpful for binders from dynamic languages * which have troubles handling structures containing memory pointers. */ -ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( +ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs ( ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos); @@ -2462,9 +1670,8 @@ ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( ********************************************************************/ /*===== Advanced Streaming compression functions =====*/ - -/*! ZSTD_initCStream_srcSize() : - * This function is DEPRECATED, and equivalent to: +/**! ZSTD_initCStream_srcSize() : + * This function is deprecated, and equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); @@ -2473,16 +1680,15 @@ ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( * pledgedSrcSize must be correct. If it is not known at init time, use * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, * "0" also disables frame content size field. It may be enabled in the future. - * This prototype will generate compilation warnings. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, +ZSTDLIB_API size_t +ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); -/*! ZSTD_initCStream_usingDict() : - * This function is DEPRECATED, and is equivalent to: +/**! ZSTD_initCStream_usingDict() : + * This function is deprecated, and is equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); @@ -2491,71 +1697,69 @@ size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, * dict == NULL or dictSize < 8, in which case no dict is used. * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. - * This prototype will generate compilation warnings. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, +ZSTDLIB_API size_t +ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); -/*! ZSTD_initCStream_advanced() : - * This function is DEPRECATED, and is equivalent to: +/**! ZSTD_initCStream_advanced() : + * This function is deprecated, and is approximately equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setParams(zcs, params); + * // Pseudocode: Set each zstd parameter and leave the rest as-is. + * for ((param, value) : params) { + * ZSTD_CCtx_setParameter(zcs, param, value); + * } * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); * * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. * pledgedSrcSize must be correct. * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. - * This prototype will generate compilation warnings. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, +ZSTDLIB_API size_t +ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); -/*! ZSTD_initCStream_usingCDict() : - * This function is DEPRECATED, and equivalent to: +/**! ZSTD_initCStream_usingCDict() : + * This function is deprecated, and equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, cdict); * * note : cdict will just be referenced, and must outlive compression session - * This prototype will generate compilation warnings. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); +ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); -/*! ZSTD_initCStream_usingCDict_advanced() : - * This function is DEPRECATED, and is equivalent to: +/**! ZSTD_initCStream_usingCDict_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setFParams(zcs, fParams); + * // Pseudocode: Set each zstd frame parameter and leave the rest as-is. + * for ((fParam, value) : fParams) { + * ZSTD_CCtx_setParameter(zcs, fParam, value); + * } * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); * ZSTD_CCtx_refCDict(zcs, cdict); * * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. * pledgedSrcSize must be correct. If srcSize is not known at init time, use * value ZSTD_CONTENTSIZE_UNKNOWN. - * This prototype will generate compilation warnings. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, +ZSTDLIB_API size_t +ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /*! ZSTD_resetCStream() : - * This function is DEPRECATED, and is equivalent to: + * This function is deprecated, and is equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but - * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be - * explicitly specified. * * start a new frame, using same parameters from previous frame. * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. @@ -2565,11 +1769,9 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. * @return : 0, or an error code (which can be tested using ZSTD_isError()) - * This prototype will generate compilation warnings. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); +ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); typedef struct { @@ -2587,7 +1789,7 @@ typedef struct { * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. * Aggregates progression inside active worker threads. */ -ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); +ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); /*! ZSTD_toFlushNow() : * Tell how many bytes are ready to be flushed immediately. @@ -2602,218 +1804,49 @@ ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCt * therefore flush speed is limited by production speed of oldest job * irrespective of the speed of concurrent (and newer) jobs. */ -ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); /*===== Advanced Streaming decompression functions =====*/ - -/*! +/** * This function is deprecated, and is equivalent to: * * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); * * note: no dictionary will be used if dict == NULL or dictSize < 8 + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_loadDictionary, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); -/*! +/** * This function is deprecated, and is equivalent to: * * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); * ZSTD_DCtx_refDDict(zds, ddict); * * note : ddict is referenced, it must outlive decompression session + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_refDDict, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); +ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); -/*! +/** * This function is deprecated, and is equivalent to: * * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); * * re-use decompression parameters from previous init; saves dictionary loading + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTD_DEPRECATED("use ZSTD_DCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); - - -/* ********************* BLOCK-LEVEL SEQUENCE PRODUCER API ********************* - * - * *** OVERVIEW *** - * The Block-Level Sequence Producer API allows users to provide their own custom - * sequence producer which libzstd invokes to process each block. The produced list - * of sequences (literals and matches) is then post-processed by libzstd to produce - * valid compressed blocks. - * - * This block-level offload API is a more granular complement of the existing - * frame-level offload API compressSequences() (introduced in v1.5.1). It offers - * an easier migration story for applications already integrated with libzstd: the - * user application continues to invoke the same compression functions - * ZSTD_compress2() or ZSTD_compressStream2() as usual, and transparently benefits - * from the specific advantages of the external sequence producer. For example, - * the sequence producer could be tuned to take advantage of known characteristics - * of the input, to offer better speed / ratio, or could leverage hardware - * acceleration not available within libzstd itself. - * - * See contrib/externalSequenceProducer for an example program employing the - * Block-Level Sequence Producer API. - * - * *** USAGE *** - * The user is responsible for implementing a function of type - * ZSTD_sequenceProducer_F. For each block, zstd will pass the following - * arguments to the user-provided function: - * - * - sequenceProducerState: a pointer to a user-managed state for the sequence - * producer. - * - * - outSeqs, outSeqsCapacity: an output buffer for the sequence producer. - * outSeqsCapacity is guaranteed >= ZSTD_sequenceBound(srcSize). The memory - * backing outSeqs is managed by the CCtx. - * - * - src, srcSize: an input buffer for the sequence producer to parse. - * srcSize is guaranteed to be <= ZSTD_BLOCKSIZE_MAX. - * - * - dict, dictSize: a history buffer, which may be empty, which the sequence - * producer may reference as it parses the src buffer. Currently, zstd will - * always pass dictSize == 0 into external sequence producers, but this will - * change in the future. - * - * - compressionLevel: a signed integer representing the zstd compression level - * set by the user for the current operation. The sequence producer may choose - * to use this information to change its compression strategy and speed/ratio - * tradeoff. Note: the compression level does not reflect zstd parameters set - * through the advanced API. - * - * - windowSize: a size_t representing the maximum allowed offset for external - * sequences. Note that sequence offsets are sometimes allowed to exceed the - * windowSize if a dictionary is present, see doc/zstd_compression_format.md - * for details. - * - * The user-provided function shall return a size_t representing the number of - * sequences written to outSeqs. This return value will be treated as an error - * code if it is greater than outSeqsCapacity. The return value must be non-zero - * if srcSize is non-zero. The ZSTD_SEQUENCE_PRODUCER_ERROR macro is provided - * for convenience, but any value greater than outSeqsCapacity will be treated as - * an error code. - * - * If the user-provided function does not return an error code, the sequences - * written to outSeqs must be a valid parse of the src buffer. Data corruption may - * occur if the parse is not valid. A parse is defined to be valid if the - * following conditions hold: - * - The sum of matchLengths and literalLengths must equal srcSize. - * - All sequences in the parse, except for the final sequence, must have - * matchLength >= ZSTD_MINMATCH_MIN. The final sequence must have - * matchLength >= ZSTD_MINMATCH_MIN or matchLength == 0. - * - All offsets must respect the windowSize parameter as specified in - * doc/zstd_compression_format.md. - * - If the final sequence has matchLength == 0, it must also have offset == 0. - * - * zstd will only validate these conditions (and fail compression if they do not - * hold) if the ZSTD_c_validateSequences cParam is enabled. Note that sequence - * validation has a performance cost. - * - * If the user-provided function returns an error, zstd will either fall back - * to an internal sequence producer or fail the compression operation. The user can - * choose between the two behaviors by setting the ZSTD_c_enableSeqProducerFallback - * cParam. Fallback compression will follow any other cParam settings, such as - * compression level, the same as in a normal compression operation. - * - * The user shall instruct zstd to use a particular ZSTD_sequenceProducer_F - * function by calling - * ZSTD_registerSequenceProducer(cctx, - * sequenceProducerState, - * sequenceProducer) - * This setting will persist until the next parameter reset of the CCtx. - * - * The sequenceProducerState must be initialized by the user before calling - * ZSTD_registerSequenceProducer(). The user is responsible for destroying the - * sequenceProducerState. - * - * *** LIMITATIONS *** - * This API is compatible with all zstd compression APIs which respect advanced parameters. - * However, there are three limitations: - * - * First, the ZSTD_c_enableLongDistanceMatching cParam is not currently supported. - * COMPRESSION WILL FAIL if it is enabled and the user tries to compress with a block-level - * external sequence producer. - * - Note that ZSTD_c_enableLongDistanceMatching is auto-enabled by default in some - * cases (see its documentation for details). Users must explicitly set - * ZSTD_c_enableLongDistanceMatching to ZSTD_ps_disable in such cases if an external - * sequence producer is registered. - * - As of this writing, ZSTD_c_enableLongDistanceMatching is disabled by default - * whenever ZSTD_c_windowLog < 128MB, but that's subject to change. Users should - * check the docs on ZSTD_c_enableLongDistanceMatching whenever the Block-Level Sequence - * Producer API is used in conjunction with advanced settings (like ZSTD_c_windowLog). - * - * Second, history buffers are not currently supported. Concretely, zstd will always pass - * dictSize == 0 to the external sequence producer (for now). This has two implications: - * - Dictionaries are not currently supported. Compression will *not* fail if the user - * references a dictionary, but the dictionary won't have any effect. - * - Stream history is not currently supported. All advanced compression APIs, including - * streaming APIs, work with external sequence producers, but each block is treated as - * an independent chunk without history from previous blocks. - * - * Third, multi-threading within a single compression is not currently supported. In other words, - * COMPRESSION WILL FAIL if ZSTD_c_nbWorkers > 0 and an external sequence producer is registered. - * Multi-threading across compressions is fine: simply create one CCtx per thread. - * - * Long-term, we plan to overcome all three limitations. There is no technical blocker to - * overcoming them. It is purely a question of engineering effort. - */ - -#define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1)) - -typedef size_t ZSTD_sequenceProducer_F ( - void* sequenceProducerState, - ZSTD_Sequence* outSeqs, size_t outSeqsCapacity, - const void* src, size_t srcSize, - const void* dict, size_t dictSize, - int compressionLevel, - size_t windowSize -); - -/*! ZSTD_registerSequenceProducer() : - * Instruct zstd to use a block-level external sequence producer function. - * - * The sequenceProducerState must be initialized by the caller, and the caller is - * responsible for managing its lifetime. This parameter is sticky across - * compressions. It will remain set until the user explicitly resets compression - * parameters. - * - * Sequence producer registration is considered to be an "advanced parameter", - * part of the "advanced API". This means it will only have an effect on compression - * APIs which respect advanced parameters, such as compress2() and compressStream2(). - * Older compression APIs such as compressCCtx(), which predate the introduction of - * "advanced parameters", will ignore any external sequence producer setting. - * - * The sequence producer can be "cleared" by registering a NULL function pointer. This - * removes all limitations described above in the "LIMITATIONS" section of the API docs. - * - * The user is strongly encouraged to read the full API documentation (above) before - * calling this function. */ -ZSTDLIB_STATIC_API void -ZSTD_registerSequenceProducer( - ZSTD_CCtx* cctx, - void* sequenceProducerState, - ZSTD_sequenceProducer_F* sequenceProducer -); +ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /********************************************************************* -* Buffer-less and synchronous inner streaming functions (DEPRECATED) -* -* This API is deprecated, and will be removed in a future version. -* It allows streaming (de)compression with user allocated buffers. -* However, it is hard to use, and not as well tested as the rest of -* our API. +* Buffer-less and synchronous inner streaming functions * -* Please use the normal streaming API instead: ZSTD_compressStream2, -* and ZSTD_decompressStream. -* If there is functionality that you need, but it doesn't provide, -* please open an issue on our GitHub. +* This is an advanced API, giving full control over buffer management, for users which need direct control over memory. +* But it's also a complex one, with several restrictions, documented below. +* Prefer normal streaming API for an easier experience. ********************************************************************* */ /** @@ -2824,7 +1857,9 @@ ZSTD_registerSequenceProducer( ZSTD_CCtx object can be re-used multiple times within successive compression operations. Start by initializing a context. - Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression, + or ZSTD_compressBegin_advanced(), for finer parameter control. + It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx() Then, consume your input using ZSTD_compressContinue(). There are some important considerations to keep in mind when using this advanced function : @@ -2846,30 +1881,18 @@ ZSTD_registerSequenceProducer( */ /*===== Buffer-less streaming compression functions =====*/ -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ - -ZSTD_DEPRECATED("This function will likely be removed in a future release. It is misleading and has very limited utility.") -ZSTDLIB_STATIC_API -size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ - -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - -/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ -ZSTD_DEPRECATED("use advanced API to access custom parameters") -ZSTDLIB_STATIC_API -size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTD_DEPRECATED("use advanced API to access custom parameters") -ZSTDLIB_STATIC_API -size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ -/** +ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ +ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + + +/*- Buffer-less streaming decompression (synchronous mode) A ZSTD_DCtx object is required to track streaming operations. @@ -2880,8 +1903,8 @@ size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_ Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. Data fragment must be large enough to ensure successful decoding. `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. - result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. - >0 : `srcSize` is too small, please provide at least result bytes on next attempt. + @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. + >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. errorCode, which can be tested using ZSTD_isError(). It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, @@ -2900,7 +1923,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_ The most memory efficient way is to use a round buffer of sufficient size. Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), - which can return an error code if required value is too large for current system (in 32-bits mode). + which can @return an error code if required value is too large for current system (in 32-bits mode). In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, up to the moment there is not enough room left in the buffer to guarantee decoding another full block, which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. @@ -2920,7 +1943,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_ ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. - result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. It can also be an error code, which can be tested with ZSTD_isError(). @@ -2943,42 +1966,49 @@ size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_ */ /*===== Buffer-less streaming decompression functions =====*/ +typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; +typedef struct { + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ + unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; + ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ + unsigned headerSize; + unsigned dictID; + unsigned checksumFlag; +} ZSTD_frameHeader; -ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ +/*! ZSTD_getFrameHeader() : + * decode Frame Header, or requires larger `srcSize`. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +/*! ZSTD_getFrameHeader_advanced() : + * same as ZSTD_getFrameHeader(), + * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ +ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); +ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); -ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); +ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); -ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); /* misc */ -ZSTD_DEPRECATED("This function will likely be removed in the next minor release. It is misleading and has very limited utility.") -ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; -ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); +ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); -/* ========================================= */ -/** Block level API (DEPRECATED) */ -/* ========================================= */ +/* ============================ */ +/** Block level API */ +/* ============================ */ /*! - - This API is deprecated in favor of the regular compression API. - You can get the frame header down to 2 bytes by setting: - - ZSTD_c_format = ZSTD_f_zstd1_magicless - - ZSTD_c_contentSizeFlag = 0 - - ZSTD_c_checksumFlag = 0 - - ZSTD_c_dictIDFlag = 0 - - This API is not as well tested as our normal API, so we recommend not using it. - We will be removing it in a future version. If the normal API doesn't provide - the functionality you need, please open a GitHub issue. - Block functions produce and decode raw zstd blocks, without frame metadata. Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. @@ -2989,6 +2019,7 @@ ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); - It is necessary to init context before starting + compression : any ZSTD_compressBegin*() variant, including with dictionary + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + + copyCCtx() and copyDCtx() can be used too - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + If input is larger than a block size, it's necessary to split input data into multiple blocks + For inputs larger than a single block, consider using regular ZSTD_compress() instead. @@ -3005,21 +2036,14 @@ ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); */ /*===== Raw zstd block functions =====*/ -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ +ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ + #endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ #if defined (__cplusplus) } #endif - -#else /* USE_EXTERNAL_ZSTD */ -#include_next -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_bulk.go b/vendor/github.com/DataDog/zstd/zstd_bulk.go deleted file mode 100644 index 0616df9b..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_bulk.go +++ /dev/null @@ -1,151 +0,0 @@ -package zstd - -/* -#include "zstd.h" -*/ -import "C" -import ( - "errors" - "runtime" - "unsafe" -) - -var ( - // ErrEmptyDictionary is returned when the given dictionary is empty - ErrEmptyDictionary = errors.New("Dictionary is empty") - // ErrBadDictionary is returned when cannot load the given dictionary - ErrBadDictionary = errors.New("Cannot load dictionary") -) - -// BulkProcessor implements Bulk processing dictionary API. -// When compressing multiple messages or blocks using the same dictionary, -// it's recommended to digest the dictionary only once, since it's a costly operation. -// NewBulkProcessor() will create a state from digesting a dictionary. -// The resulting state can be used for future compression/decompression operations with very limited startup cost. -// BulkProcessor can be created once and shared by multiple threads concurrently, since its usage is read-only. -// The state will be freed when gc cleans up BulkProcessor. -type BulkProcessor struct { - cDict *C.struct_ZSTD_CDict_s - dDict *C.struct_ZSTD_DDict_s -} - -// NewBulkProcessor creates a new BulkProcessor with a pre-trained dictionary and compression level -func NewBulkProcessor(dictionary []byte, compressionLevel int) (*BulkProcessor, error) { - if len(dictionary) < 1 { - return nil, ErrEmptyDictionary - } - - p := &BulkProcessor{} - runtime.SetFinalizer(p, finalizeBulkProcessor) - - p.cDict = C.ZSTD_createCDict( - unsafe.Pointer(&dictionary[0]), - C.size_t(len(dictionary)), - C.int(compressionLevel), - ) - if p.cDict == nil { - return nil, ErrBadDictionary - } - p.dDict = C.ZSTD_createDDict( - unsafe.Pointer(&dictionary[0]), - C.size_t(len(dictionary)), - ) - if p.dDict == nil { - return nil, ErrBadDictionary - } - - return p, nil -} - -// Compress compresses `src` into `dst` with the dictionary given when creating the BulkProcessor. -// If you have a buffer to use, you can pass it to prevent allocation. -// If it is too small, or if nil is passed, a new buffer will be allocated and returned. -func (p *BulkProcessor) Compress(dst, src []byte) ([]byte, error) { - bound := CompressBound(len(src)) - if cap(dst) >= bound { - dst = dst[0:bound] - } else { - dst = make([]byte, bound) - } - - cctx := C.ZSTD_createCCtx() - // We need unsafe.Pointer(&src[0]) in the Cgo call to avoid "Go pointer to Go pointer" panics. - // This means we need to special case empty input. See: - // https://github.com/golang/go/issues/14210#issuecomment-346402945 - var cWritten C.size_t - if len(src) == 0 { - cWritten = C.ZSTD_compress_usingCDict( - cctx, - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(nil), - C.size_t(len(src)), - p.cDict, - ) - } else { - cWritten = C.ZSTD_compress_usingCDict( - cctx, - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(&src[0]), - C.size_t(len(src)), - p.cDict, - ) - } - - C.ZSTD_freeCCtx(cctx) - - written := int(cWritten) - if err := getError(written); err != nil { - return nil, err - } - return dst[:written], nil -} - -// Decompress decompresses `src` into `dst` with the dictionary given when creating the BulkProcessor. -// If you have a buffer to use, you can pass it to prevent allocation. -// If it is too small, or if nil is passed, a new buffer will be allocated and returned. -func (p *BulkProcessor) Decompress(dst, src []byte) ([]byte, error) { - if len(src) == 0 { - return nil, ErrEmptySlice - } - - contentSize := decompressSizeHint(src) - if cap(dst) >= contentSize { - dst = dst[0:contentSize] - } else { - dst = make([]byte, contentSize) - } - - if contentSize == 0 { - return dst, nil - } - - dctx := C.ZSTD_createDCtx() - cWritten := C.ZSTD_decompress_usingDDict( - dctx, - unsafe.Pointer(&dst[0]), - C.size_t(contentSize), - unsafe.Pointer(&src[0]), - C.size_t(len(src)), - p.dDict, - ) - C.ZSTD_freeDCtx(dctx) - - written := int(cWritten) - if err := getError(written); err != nil { - return nil, err - } - - return dst[:written], nil -} - -// finalizeBulkProcessor frees compression and decompression dictionaries from memory -func finalizeBulkProcessor(p *BulkProcessor) { - if p.cDict != nil { - C.ZSTD_freeCDict(p.cDict) - } - if p.dDict != nil { - C.ZSTD_freeDDict(p.dDict) - } -} diff --git a/vendor/github.com/DataDog/zstd/zstd_common.c b/vendor/github.com/DataDog/zstd/zstd_common.c index 656c46c7..667f4a27 100644 --- a/vendor/github.com/DataDog/zstd/zstd_common.c +++ b/vendor/github.com/DataDog/zstd/zstd_common.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +13,8 @@ /*-************************************* * Dependencies ***************************************/ -#define ZSTD_DEPS_NEED_MALLOC +#include /* malloc, calloc, free */ +#include /* memset */ #include "error_private.h" #include "zstd_internal.h" @@ -48,4 +48,36 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } * provides error code string from enum */ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } -#endif /* USE_EXTERNAL_ZSTD */ + + +/*=************************************************************** +* Custom allocator +****************************************************************/ +void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) + return customMem.customAlloc(customMem.opaque, size); + return malloc(size); +} + +void* ZSTD_calloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) { + /* calloc implemented as malloc+memset; + * not as efficient as calloc, but next best guess for custom malloc */ + void* const ptr = customMem.customAlloc(customMem.opaque, size); + memset(ptr, 0, size); + return ptr; + } + return calloc(1, size); +} + +void ZSTD_free(void* ptr, ZSTD_customMem customMem) +{ + if (ptr!=NULL) { + if (customMem.customFree) + customMem.customFree(customMem.opaque, ptr); + else + free(ptr); + } +} diff --git a/vendor/github.com/DataDog/zstd/zstd_compress.c b/vendor/github.com/DataDog/zstd/zstd_compress.c index 728514ae..35346b92 100644 --- a/vendor/github.com/DataDog/zstd/zstd_compress.c +++ b/vendor/github.com/DataDog/zstd/zstd_compress.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -12,12 +11,14 @@ /*-************************************* * Dependencies ***************************************/ -#include "allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */ +#include /* INT_MAX */ +#include /* memset */ +#include "cpu.h" #include "mem.h" #include "hist.h" /* HIST_countFast_wksp */ #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ #include "fse.h" +#define HUF_STATIC_LINKING_ONLY #include "huf.h" #include "zstd_compress_internal.h" #include "zstd_compress_sequences.h" @@ -27,50 +28,13 @@ #include "zstd_lazy.h" #include "zstd_opt.h" #include "zstd_ldm.h" -#include "zstd_compress_superblock.h" -#include "bits.h" /* ZSTD_highbit32, ZSTD_rotateRight_U64 */ - -/* *************************************************************** -* Tuning parameters -*****************************************************************/ -/*! - * COMPRESS_HEAPMODE : - * Select how default decompression function ZSTD_compress() allocates its context, - * on stack (0, default), or into heap (1). - * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. - */ -#ifndef ZSTD_COMPRESS_HEAPMODE -# define ZSTD_COMPRESS_HEAPMODE 0 -#endif -/*! - * ZSTD_HASHLOG3_MAX : - * Maximum size of the hash table dedicated to find 3-bytes matches, - * in log format, aka 17 => 1 << 17 == 128Ki positions. - * This structure is only used in zstd_opt. - * Since allocation is centralized for all strategies, it has to be known here. - * The actual (selected) size of the hash table is then stored in ZSTD_matchState_t.hashLog3, - * so that zstd_opt.c doesn't need to know about this constant. - */ -#ifndef ZSTD_HASHLOG3_MAX -# define ZSTD_HASHLOG3_MAX 17 -#endif /*-************************************* * Helper functions ***************************************/ -/* ZSTD_compressBound() - * Note that the result from this function is only valid for - * the one-pass compression functions. - * When employing the streaming mode, - * if flushes are frequently altering the size of blocks, - * the overhead from block headers can make the compressed data larger - * than the return value of ZSTD_compressBound(). - */ size_t ZSTD_compressBound(size_t srcSize) { - size_t const r = ZSTD_COMPRESSBOUND(srcSize); - if (r==0) return ERROR(srcSize_wrong); - return r; + return ZSTD_COMPRESSBOUND(srcSize); } @@ -80,7 +44,6 @@ size_t ZSTD_compressBound(size_t srcSize) { struct ZSTD_CDict_s { const void* dictContent; size_t dictContentSize; - ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ ZSTD_cwksp workspace; ZSTD_matchState_t matchState; @@ -88,10 +51,6 @@ struct ZSTD_CDict_s { ZSTD_customMem customMem; U32 dictID; int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ - ZSTD_paramSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use - * row-based matchfinder. Unless the cdict is reloaded, we will use - * the same greedy/lazy matchfinder at compression time. - */ }; /* typedef'd to ZSTD_CDict within "zstd.h" */ ZSTD_CCtx* ZSTD_createCCtx(void) @@ -102,9 +61,9 @@ ZSTD_CCtx* ZSTD_createCCtx(void) static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) { assert(cctx != NULL); - ZSTD_memset(cctx, 0, sizeof(*cctx)); + memset(cctx, 0, sizeof(*cctx)); cctx->customMem = memManager; - cctx->bmi2 = ZSTD_cpuSupportsBmi2(); + cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); assert(!ZSTD_isError(err)); (void)err; @@ -115,34 +74,36 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) { ZSTD_STATIC_ASSERT(zcss_init==0); ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); if (!cctx) return NULL; ZSTD_initCCtx(cctx, customMem); return cctx; } } -ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) +ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) { ZSTD_cwksp ws; ZSTD_CCtx* cctx; if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ - ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); + ZSTD_cwksp_init(&ws, workspace, workspaceSize); cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); - if (cctx == NULL) return NULL; - - ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx)); + if (cctx == NULL) { + return NULL; + } + memset(cctx, 0, sizeof(ZSTD_CCtx)); ZSTD_cwksp_move(&cctx->workspace, &ws); cctx->staticSize = workspaceSize; /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ - if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; + if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); - cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE); + cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object( + &cctx->workspace, HUF_WORKSPACE_SIZE); cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); return cctx; } @@ -152,10 +113,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) */ static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) { - ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem); + ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); ZSTD_freeCDict(cctx->localDict.cdict); - ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict)); - ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); + memset(&cctx->localDict, 0, sizeof(cctx->localDict)); + memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); cctx->cdict = NULL; } @@ -182,9 +143,12 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) if (cctx==NULL) return 0; /* support free on NULL */ RETURN_ERROR_IF(cctx->staticSize, memory_allocation, "not compatible with static CCtx"); - { int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); + { + int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); ZSTD_freeCCtxContent(cctx); - if (!cctxInWorkspace) ZSTD_customFree(cctx, cctx->customMem); + if (!cctxInWorkspace) { + ZSTD_free(cctx, cctx->customMem); + } } return 0; } @@ -219,116 +183,15 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } -/* Returns true if the strategy supports using a row based matchfinder */ -static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) { - return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2); -} - -/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder - * for this compression. - */ -static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_paramSwitch_e mode) { - assert(mode != ZSTD_ps_auto); - return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_ps_enable); -} - -/* Returns row matchfinder usage given an initial mode and cParams */ -static ZSTD_paramSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_paramSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { -#if defined(ZSTD_ARCH_X86_SSE2) || defined(ZSTD_ARCH_ARM_NEON) - int const kHasSIMD128 = 1; -#else - int const kHasSIMD128 = 0; -#endif - if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */ - mode = ZSTD_ps_disable; - if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode; - if (kHasSIMD128) { - if (cParams->windowLog > 14) mode = ZSTD_ps_enable; - } else { - if (cParams->windowLog > 17) mode = ZSTD_ps_enable; - } - return mode; -} - -/* Returns block splitter usage (generally speaking, when using slower/stronger compression modes) */ -static ZSTD_paramSwitch_e ZSTD_resolveBlockSplitterMode(ZSTD_paramSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { - if (mode != ZSTD_ps_auto) return mode; - return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17) ? ZSTD_ps_enable : ZSTD_ps_disable; -} - -/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */ -static int ZSTD_allocateChainTable(const ZSTD_strategy strategy, - const ZSTD_paramSwitch_e useRowMatchFinder, - const U32 forDDSDict) { - assert(useRowMatchFinder != ZSTD_ps_auto); - /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate. - * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder. - */ - return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder)); -} - -/* Returns ZSTD_ps_enable if compression parameters are such that we should - * enable long distance matching (wlog >= 27, strategy >= btopt). - * Returns ZSTD_ps_disable otherwise. - */ -static ZSTD_paramSwitch_e ZSTD_resolveEnableLdm(ZSTD_paramSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { - if (mode != ZSTD_ps_auto) return mode; - return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable; -} - -static int ZSTD_resolveExternalSequenceValidation(int mode) { - return mode; -} - -/* Resolves maxBlockSize to the default if no value is present. */ -static size_t ZSTD_resolveMaxBlockSize(size_t maxBlockSize) { - if (maxBlockSize == 0) { - return ZSTD_BLOCKSIZE_MAX; - } else { - return maxBlockSize; - } -} - -static ZSTD_paramSwitch_e ZSTD_resolveExternalRepcodeSearch(ZSTD_paramSwitch_e value, int cLevel) { - if (value != ZSTD_ps_auto) return value; - if (cLevel < 10) { - return ZSTD_ps_disable; - } else { - return ZSTD_ps_enable; - } -} - -/* Returns 1 if compression parameters are such that CDict hashtable and chaintable indices are tagged. - * If so, the tags need to be removed in ZSTD_resetCCtx_byCopyingCDict. */ -static int ZSTD_CDictIndicesAreTagged(const ZSTD_compressionParameters* const cParams) { - return cParams->strategy == ZSTD_fast || cParams->strategy == ZSTD_dfast; -} - static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( ZSTD_compressionParameters cParams) { ZSTD_CCtx_params cctxParams; - /* should not matter, as all cParams are presumed properly defined */ - ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT); + memset(&cctxParams, 0, sizeof(cctxParams)); cctxParams.cParams = cParams; - - /* Adjust advanced params according to cParams */ - cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams); - if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); - assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); - assert(cctxParams.ldmParams.hashRateLog < 32); - } - cctxParams.useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams.useBlockSplitter, &cParams); - cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); - cctxParams.validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams.validateSequences); - cctxParams.maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams.maxBlockSize); - cctxParams.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams.searchForExternalRepcodes, - cctxParams.compressionLevel); + cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ assert(!ZSTD_checkCParams(cParams)); + cctxParams.fParams.contentSizeFlag = 1; return cctxParams; } @@ -336,12 +199,13 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( ZSTD_customMem customMem) { ZSTD_CCtx_params* params; - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - params = (ZSTD_CCtx_params*)ZSTD_customCalloc( + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + params = (ZSTD_CCtx_params*)ZSTD_calloc( sizeof(ZSTD_CCtx_params), customMem); if (!params) { return NULL; } - ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); params->customMem = customMem; + params->compressionLevel = ZSTD_CLEVEL_DEFAULT; + params->fParams.contentSizeFlag = 1; return params; } @@ -353,7 +217,7 @@ ZSTD_CCtx_params* ZSTD_createCCtxParams(void) size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } - ZSTD_customFree(params, params->customMem); + ZSTD_free(params, params->customMem); return 0; } @@ -363,64 +227,36 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) } size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { - RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); - ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); + RETURN_ERROR_IF(!cctxParams, GENERIC); + memset(cctxParams, 0, sizeof(*cctxParams)); cctxParams->compressionLevel = compressionLevel; cctxParams->fParams.contentSizeFlag = 1; return 0; } -#define ZSTD_NO_CLEVEL 0 - -/** - * Initializes `cctxParams` from `params` and `compressionLevel`. - * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. - */ -static void -ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, - const ZSTD_parameters* params, - int compressionLevel) -{ - assert(!ZSTD_checkCParams(params->cParams)); - ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); - cctxParams->cParams = params->cParams; - cctxParams->fParams = params->fParams; - /* Should not matter, as all cParams are presumed properly defined. - * But, set it for tracing anyway. - */ - cctxParams->compressionLevel = compressionLevel; - cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); - cctxParams->useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->useBlockSplitter, ¶ms->cParams); - cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); - cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences); - cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize); - cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel); - DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", - cctxParams->useRowMatchFinder, cctxParams->useBlockSplitter, cctxParams->ldmParams.enableLdm); -} - size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { - RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); - FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); - ZSTD_CCtxParams_init_internal(cctxParams, ¶ms, ZSTD_NO_CLEVEL); + RETURN_ERROR_IF(!cctxParams, GENERIC); + FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); + memset(cctxParams, 0, sizeof(*cctxParams)); + assert(!ZSTD_checkCParams(params.cParams)); + cctxParams->cParams = params.cParams; + cctxParams->fParams = params.fParams; + cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ return 0; } -/** - * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. - * @param params Validated zstd parameters. - */ -static void ZSTD_CCtxParams_setZstdParams( - ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) -{ - assert(!ZSTD_checkCParams(params->cParams)); - cctxParams->cParams = params->cParams; - cctxParams->fParams = params->fParams; - /* Should not matter, as all cParams are presumed properly defined. - * But, set it for tracing anyway. - */ - cctxParams->compressionLevel = ZSTD_NO_CLEVEL; +/* ZSTD_assignParamsToCCtxParams() : + * params is presumed valid at this stage */ +static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( + const ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) +{ + ZSTD_CCtx_params ret = *cctxParams; + assert(!ZSTD_checkCParams(params.cParams)); + ret.cParams = params.cParams; + ret.fParams = params.fParams; + ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ + return ret; } ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) @@ -503,25 +339,15 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) return bounds; case ZSTD_c_overlapLog: -#ifdef ZSTD_MULTITHREAD bounds.lowerBound = ZSTD_OVERLAPLOG_MIN; bounds.upperBound = ZSTD_OVERLAPLOG_MAX; -#else - bounds.lowerBound = 0; - bounds.upperBound = 0; -#endif return bounds; - case ZSTD_c_enableDedicatedDictSearch: + case ZSTD_c_enableLongDistanceMatching: bounds.lowerBound = 0; bounds.upperBound = 1; return bounds; - case ZSTD_c_enableLongDistanceMatching: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - case ZSTD_c_ldmHashLog: bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; @@ -560,15 +386,15 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) return bounds; case ZSTD_c_forceAttachDict: - ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad); + ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); bounds.lowerBound = ZSTD_dictDefaultAttach; bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ return bounds; case ZSTD_c_literalCompressionMode: - ZSTD_STATIC_ASSERT(ZSTD_ps_auto < ZSTD_ps_enable && ZSTD_ps_enable < ZSTD_ps_disable); - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; + ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); + bounds.lowerBound = ZSTD_lcm_auto; + bounds.upperBound = ZSTD_lcm_uncompressed; return bounds; case ZSTD_c_targetCBlockSize: @@ -581,60 +407,10 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; return bounds; - case ZSTD_c_stableInBuffer: - case ZSTD_c_stableOutBuffer: - bounds.lowerBound = (int)ZSTD_bm_buffered; - bounds.upperBound = (int)ZSTD_bm_stable; - return bounds; - - case ZSTD_c_blockDelimiters: - bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters; - bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters; - return bounds; - - case ZSTD_c_validateSequences: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - - case ZSTD_c_useBlockSplitter: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - - case ZSTD_c_useRowMatchFinder: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - - case ZSTD_c_deterministicRefPrefix: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - - case ZSTD_c_prefetchCDictTables: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - - case ZSTD_c_enableSeqProducerFallback: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - - case ZSTD_c_maxBlockSize: - bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN; - bounds.upperBound = ZSTD_BLOCKSIZE_MAX; - return bounds; - - case ZSTD_c_searchForExternalRepcodes: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - default: - bounds.error = ERROR(parameter_unsupported); - return bounds; + { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 }; + return boundError; + } } } @@ -652,7 +428,7 @@ static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) #define BOUNDCHECK(cParam, val) { \ RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ - parameter_outOfBound, "Param out of bounds"); \ + parameter_outOfBound); \ } @@ -679,7 +455,6 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: - case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: @@ -689,17 +464,6 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_literalCompressionMode: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: - case ZSTD_c_stableInBuffer: - case ZSTD_c_stableOutBuffer: - case ZSTD_c_blockDelimiters: - case ZSTD_c_validateSequences: - case ZSTD_c_useBlockSplitter: - case ZSTD_c_useRowMatchFinder: - case ZSTD_c_deterministicRefPrefix: - case ZSTD_c_prefetchCDictTables: - case ZSTD_c_enableSeqProducerFallback: - case ZSTD_c_maxBlockSize: - case ZSTD_c_searchForExternalRepcodes: default: return 0; } @@ -712,7 +476,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) if (ZSTD_isUpdateAuthorized(param)) { cctx->cParamsChanged = 1; } else { - RETURN_ERROR(stage_wrong, "can only set params in cctx init stage"); + RETURN_ERROR(stage_wrong); } } switch(param) @@ -741,27 +505,15 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: - case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: case ZSTD_c_ldmBucketSizeLog: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: - case ZSTD_c_stableInBuffer: - case ZSTD_c_stableOutBuffer: - case ZSTD_c_blockDelimiters: - case ZSTD_c_validateSequences: - case ZSTD_c_useBlockSplitter: - case ZSTD_c_useRowMatchFinder: - case ZSTD_c_deterministicRefPrefix: - case ZSTD_c_prefetchCDictTables: - case ZSTD_c_enableSeqProducerFallback: - case ZSTD_c_maxBlockSize: - case ZSTD_c_searchForExternalRepcodes: break; - default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); + default: RETURN_ERROR(parameter_unsupported); } return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); } @@ -778,11 +530,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, return (size_t)CCtxParams->format; case ZSTD_c_compressionLevel : { - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); - if (value == 0) - CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ - else + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); + if (value) { /* 0 : does not change current level */ CCtxParams->compressionLevel = value; + } if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; return 0; /* return type (size_t) cannot represent negative values */ } @@ -814,12 +565,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_minMatch : if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_minMatch, value); - CCtxParams->cParams.minMatch = (U32)value; + CCtxParams->cParams.minMatch = value; return CCtxParams->cParams.minMatch; case ZSTD_c_targetLength : BOUNDCHECK(ZSTD_c_targetLength, value); - CCtxParams->cParams.targetLength = (U32)value; + CCtxParams->cParams.targetLength = value; return CCtxParams->cParams.targetLength; case ZSTD_c_strategy : @@ -832,12 +583,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Content size written in frame header _when known_ (default:1) */ DEBUGLOG(4, "set content size flag = %u", (value!=0)); CCtxParams->fParams.contentSizeFlag = value != 0; - return (size_t)CCtxParams->fParams.contentSizeFlag; + return CCtxParams->fParams.contentSizeFlag; case ZSTD_c_checksumFlag : /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ CCtxParams->fParams.checksumFlag = value != 0; - return (size_t)CCtxParams->fParams.checksumFlag; + return CCtxParams->fParams.checksumFlag; case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); @@ -846,18 +597,18 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_forceMaxWindow : CCtxParams->forceWindow = (value != 0); - return (size_t)CCtxParams->forceWindow; + return CCtxParams->forceWindow; case ZSTD_c_forceAttachDict : { const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; - BOUNDCHECK(ZSTD_c_forceAttachDict, (int)pref); + BOUNDCHECK(ZSTD_c_forceAttachDict, pref); CCtxParams->attachDictPref = pref; return CCtxParams->attachDictPref; } case ZSTD_c_literalCompressionMode : { - const ZSTD_paramSwitch_e lcm = (ZSTD_paramSwitch_e)value; - BOUNDCHECK(ZSTD_c_literalCompressionMode, (int)lcm); + const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; + BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); CCtxParams->literalCompressionMode = lcm; return CCtxParams->literalCompressionMode; } @@ -867,7 +618,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); return 0; #else - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); CCtxParams->nbWorkers = value; return CCtxParams->nbWorkers; #endif @@ -880,7 +631,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Adjust to the minimum non-default value. */ if (value != 0 && value < ZSTDMT_JOBSIZE_MIN) value = ZSTDMT_JOBSIZE_MIN; - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); assert(value >= 0); CCtxParams->jobSize = value; return CCtxParams->jobSize; @@ -891,7 +642,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); return 0; #else - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); CCtxParams->overlapLog = value; return CCtxParams->overlapLog; #endif @@ -901,123 +652,62 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); return 0; #else - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); CCtxParams->rsyncable = value; return CCtxParams->rsyncable; #endif - case ZSTD_c_enableDedicatedDictSearch : - CCtxParams->enableDedicatedDictSearch = (value!=0); - return (size_t)CCtxParams->enableDedicatedDictSearch; - case ZSTD_c_enableLongDistanceMatching : - BOUNDCHECK(ZSTD_c_enableLongDistanceMatching, value); - CCtxParams->ldmParams.enableLdm = (ZSTD_paramSwitch_e)value; + CCtxParams->ldmParams.enableLdm = (value!=0); return CCtxParams->ldmParams.enableLdm; case ZSTD_c_ldmHashLog : if (value!=0) /* 0 ==> auto */ BOUNDCHECK(ZSTD_c_ldmHashLog, value); - CCtxParams->ldmParams.hashLog = (U32)value; + CCtxParams->ldmParams.hashLog = value; return CCtxParams->ldmParams.hashLog; case ZSTD_c_ldmMinMatch : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmMinMatch, value); - CCtxParams->ldmParams.minMatchLength = (U32)value; + CCtxParams->ldmParams.minMatchLength = value; return CCtxParams->ldmParams.minMatchLength; case ZSTD_c_ldmBucketSizeLog : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); - CCtxParams->ldmParams.bucketSizeLog = (U32)value; + CCtxParams->ldmParams.bucketSizeLog = value; return CCtxParams->ldmParams.bucketSizeLog; case ZSTD_c_ldmHashRateLog : - if (value!=0) /* 0 ==> default */ - BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); - CCtxParams->ldmParams.hashRateLog = (U32)value; + RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, + parameter_outOfBound); + CCtxParams->ldmParams.hashRateLog = value; return CCtxParams->ldmParams.hashRateLog; case ZSTD_c_targetCBlockSize : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_targetCBlockSize, value); - CCtxParams->targetCBlockSize = (U32)value; + CCtxParams->targetCBlockSize = value; return CCtxParams->targetCBlockSize; case ZSTD_c_srcSizeHint : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_srcSizeHint, value); CCtxParams->srcSizeHint = value; - return (size_t)CCtxParams->srcSizeHint; - - case ZSTD_c_stableInBuffer: - BOUNDCHECK(ZSTD_c_stableInBuffer, value); - CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value; - return CCtxParams->inBufferMode; - - case ZSTD_c_stableOutBuffer: - BOUNDCHECK(ZSTD_c_stableOutBuffer, value); - CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value; - return CCtxParams->outBufferMode; - - case ZSTD_c_blockDelimiters: - BOUNDCHECK(ZSTD_c_blockDelimiters, value); - CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value; - return CCtxParams->blockDelimiters; - - case ZSTD_c_validateSequences: - BOUNDCHECK(ZSTD_c_validateSequences, value); - CCtxParams->validateSequences = value; - return CCtxParams->validateSequences; - - case ZSTD_c_useBlockSplitter: - BOUNDCHECK(ZSTD_c_useBlockSplitter, value); - CCtxParams->useBlockSplitter = (ZSTD_paramSwitch_e)value; - return CCtxParams->useBlockSplitter; - - case ZSTD_c_useRowMatchFinder: - BOUNDCHECK(ZSTD_c_useRowMatchFinder, value); - CCtxParams->useRowMatchFinder = (ZSTD_paramSwitch_e)value; - return CCtxParams->useRowMatchFinder; - - case ZSTD_c_deterministicRefPrefix: - BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value); - CCtxParams->deterministicRefPrefix = !!value; - return CCtxParams->deterministicRefPrefix; - - case ZSTD_c_prefetchCDictTables: - BOUNDCHECK(ZSTD_c_prefetchCDictTables, value); - CCtxParams->prefetchCDictTables = (ZSTD_paramSwitch_e)value; - return CCtxParams->prefetchCDictTables; - - case ZSTD_c_enableSeqProducerFallback: - BOUNDCHECK(ZSTD_c_enableSeqProducerFallback, value); - CCtxParams->enableMatchFinderFallback = value; - return CCtxParams->enableMatchFinderFallback; - - case ZSTD_c_maxBlockSize: - if (value!=0) /* 0 ==> default */ - BOUNDCHECK(ZSTD_c_maxBlockSize, value); - CCtxParams->maxBlockSize = value; - return CCtxParams->maxBlockSize; - - case ZSTD_c_searchForExternalRepcodes: - BOUNDCHECK(ZSTD_c_searchForExternalRepcodes, value); - CCtxParams->searchForExternalRepcodes = (ZSTD_paramSwitch_e)value; - return CCtxParams->searchForExternalRepcodes; + return CCtxParams->srcSizeHint; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } } -size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value) +size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) { return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); } size_t ZSTD_CCtxParams_getParameter( - ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value) + ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) { switch(param) { @@ -1094,9 +784,6 @@ size_t ZSTD_CCtxParams_getParameter( *value = CCtxParams->rsyncable; break; #endif - case ZSTD_c_enableDedicatedDictSearch : - *value = CCtxParams->enableDedicatedDictSearch; - break; case ZSTD_c_enableLongDistanceMatching : *value = CCtxParams->ldmParams.enableLdm; break; @@ -1118,39 +805,6 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_srcSizeHint : *value = (int)CCtxParams->srcSizeHint; break; - case ZSTD_c_stableInBuffer : - *value = (int)CCtxParams->inBufferMode; - break; - case ZSTD_c_stableOutBuffer : - *value = (int)CCtxParams->outBufferMode; - break; - case ZSTD_c_blockDelimiters : - *value = (int)CCtxParams->blockDelimiters; - break; - case ZSTD_c_validateSequences : - *value = (int)CCtxParams->validateSequences; - break; - case ZSTD_c_useBlockSplitter : - *value = (int)CCtxParams->useBlockSplitter; - break; - case ZSTD_c_useRowMatchFinder : - *value = (int)CCtxParams->useRowMatchFinder; - break; - case ZSTD_c_deterministicRefPrefix: - *value = (int)CCtxParams->deterministicRefPrefix; - break; - case ZSTD_c_prefetchCDictTables: - *value = (int)CCtxParams->prefetchCDictTables; - break; - case ZSTD_c_enableSeqProducerFallback: - *value = CCtxParams->enableMatchFinderFallback; - break; - case ZSTD_c_maxBlockSize: - *value = (int)CCtxParams->maxBlockSize; - break; - case ZSTD_c_searchForExternalRepcodes: - *value = (int)CCtxParams->searchForExternalRepcodes; - break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } return 0; @@ -1167,79 +821,31 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams( ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) { DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "The context is in the wrong stage!"); - RETURN_ERROR_IF(cctx->cdict, stage_wrong, - "Can't override parameters with cdict attached (some must " - "be inherited from the cdict)."); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); + RETURN_ERROR_IF(cctx->cdict, stage_wrong); cctx->requestedParams = *params; return 0; } -size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams) -{ - ZSTD_STATIC_ASSERT(sizeof(cparams) == 7 * 4 /* all params are listed below */); - DEBUGLOG(4, "ZSTD_CCtx_setCParams"); - /* only update if all parameters are valid */ - FORWARD_IF_ERROR(ZSTD_checkCParams(cparams), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, cparams.windowLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, cparams.chainLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, cparams.hashLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, cparams.searchLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, cparams.minMatch), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, cparams.targetLength), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, cparams.strategy), ""); - return 0; -} - -size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams) -{ - ZSTD_STATIC_ASSERT(sizeof(fparams) == 3 * 4 /* all params are listed below */); - DEBUGLOG(4, "ZSTD_CCtx_setFParams"); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, fparams.contentSizeFlag != 0), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, fparams.checksumFlag != 0), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_dictIDFlag, fparams.noDictIDFlag == 0), ""); - return 0; -} - -size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params) -{ - DEBUGLOG(4, "ZSTD_CCtx_setParams"); - /* First check cParams, because we want to update all or none. */ - FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); - /* Next set fParams, because this could fail if the cctx isn't in init stage. */ - FORWARD_IF_ERROR(ZSTD_CCtx_setFParams(cctx, params.fParams), ""); - /* Finally set cParams, which should succeed. */ - FORWARD_IF_ERROR(ZSTD_CCtx_setCParams(cctx, params.cParams), ""); - return 0; -} - -size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %llu bytes", pledgedSrcSize); - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't set pledgedSrcSize when not in init stage."); + DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; return 0; } -static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( - int const compressionLevel, - size_t const dictSize); -static int ZSTD_dedicatedDictSearch_isSupported( - const ZSTD_compressionParameters* cParams); -static void ZSTD_dedicatedDictSearch_revertCParams( - ZSTD_compressionParameters* cParams); - /** - * Initializes the local dictionary using requested parameters. - * NOTE: Initialization does not employ the pledged src size, - * because the dictionary may be used for multiple compressions. + * Initializes the local dict using the requested parameters. + * NOTE: This does not use the pledged src size, because it may be used for more + * than one compression. */ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) { ZSTD_localDict* const dl = &cctx->localDict; + ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( + &cctx->requestedParams, 0, dl->dictSize); if (dl->dict == NULL) { /* No local dictionary. */ assert(dl->dictBuffer == NULL); @@ -1248,65 +854,59 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) return 0; } if (dl->cdict != NULL) { - /* Local dictionary already initialized. */ assert(cctx->cdict == dl->cdict); + /* Local dictionary already initialized. */ return 0; } assert(dl->dictSize > 0); assert(cctx->cdict == NULL); assert(cctx->prefixDict.dict == NULL); - dl->cdict = ZSTD_createCDict_advanced2( + dl->cdict = ZSTD_createCDict_advanced( dl->dict, dl->dictSize, ZSTD_dlm_byRef, dl->dictContentType, - &cctx->requestedParams, + cParams, cctx->customMem); - RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed"); + RETURN_ERROR_IF(!dl->cdict, memory_allocation); cctx->cdict = dl->cdict; return 0; } size_t ZSTD_CCtx_loadDictionary_advanced( - ZSTD_CCtx* cctx, - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType) + ZSTD_CCtx* cctx, const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) { + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); + RETURN_ERROR_IF(cctx->staticSize, memory_allocation, + "no malloc for static CCtx"); DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't load a dictionary when cctx is not in init stage."); - ZSTD_clearAllDicts(cctx); /* erase any previously set dictionary */ - if (dict == NULL || dictSize == 0) /* no dictionary */ + ZSTD_clearAllDicts(cctx); /* in case one already exists */ + if (dict == NULL || dictSize == 0) /* no dictionary mode */ return 0; if (dictLoadMethod == ZSTD_dlm_byRef) { cctx->localDict.dict = dict; } else { - /* copy dictionary content inside CCtx to own its lifetime */ - void* dictBuffer; - RETURN_ERROR_IF(cctx->staticSize, memory_allocation, - "static CCtx can't allocate for an internal copy of dictionary"); - dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem); - RETURN_ERROR_IF(dictBuffer==NULL, memory_allocation, - "allocation failed for dictionary content"); - ZSTD_memcpy(dictBuffer, dict, dictSize); - cctx->localDict.dictBuffer = dictBuffer; /* owned ptr to free */ - cctx->localDict.dict = dictBuffer; /* read-only reference */ + void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); + RETURN_ERROR_IF(!dictBuffer, memory_allocation); + memcpy(dictBuffer, dict, dictSize); + cctx->localDict.dictBuffer = dictBuffer; + cctx->localDict.dict = dictBuffer; } cctx->localDict.dictSize = dictSize; cctx->localDict.dictContentType = dictContentType; return 0; } -size_t ZSTD_CCtx_loadDictionary_byReference( +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); } -size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); @@ -1315,22 +915,13 @@ size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSi size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't ref a dict when ctx not in init stage."); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); /* Free the existing local cdict (if any) to save memory. */ ZSTD_clearAllDicts(cctx); cctx->cdict = cdict; return 0; } -size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool) -{ - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't ref a pool when ctx not in init stage."); - cctx->pool = pool; - return 0; -} - size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) { return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); @@ -1339,14 +930,11 @@ size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSiz size_t ZSTD_CCtx_refPrefix_advanced( ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't ref a prefix when ctx not in init stage."); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); ZSTD_clearAllDicts(cctx); - if (prefix != NULL && prefixSize > 0) { - cctx->prefixDict.dict = prefix; - cctx->prefixDict.dictSize = prefixSize; - cctx->prefixDict.dictContentType = dictContentType; - } + cctx->prefixDict.dict = prefix; + cctx->prefixDict.dictSize = prefixSize; + cctx->prefixDict.dictContentType = dictContentType; return 0; } @@ -1361,10 +949,8 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) } if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Reset parameters is only possible during init stage."); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); ZSTD_clearAllDicts(cctx); - ZSTD_memset(&cctx->externalMatchCtx, 0, sizeof(cctx->externalMatchCtx)); return ZSTD_CCtxParams_reset(&cctx->requestedParams); } return 0; @@ -1410,147 +996,50 @@ ZSTD_clampCParams(ZSTD_compressionParameters cParams) /** ZSTD_cycleLog() : * condition for correct operation : hashLog > 1 */ -U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) +static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) { U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); return hashLog - btScale; } -/** ZSTD_dictAndWindowLog() : - * Returns an adjusted window log that is large enough to fit the source and the dictionary. - * The zstd format says that the entire dictionary is valid if one byte of the dictionary - * is within the window. So the hashLog and chainLog should be large enough to reference both - * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing - * the hashLog and windowLog. - * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. - */ -static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) -{ - const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; - /* No dictionary ==> No change */ - if (dictSize == 0) { - return windowLog; - } - assert(windowLog <= ZSTD_WINDOWLOG_MAX); - assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ - { - U64 const windowSize = 1ULL << windowLog; - U64 const dictAndWindowSize = dictSize + windowSize; - /* If the window size is already large enough to fit both the source and the dictionary - * then just use the window size. Otherwise adjust so that it fits the dictionary and - * the window. - */ - if (windowSize >= dictSize + srcSize) { - return windowLog; /* Window size large enough already */ - } else if (dictAndWindowSize >= maxWindowSize) { - return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ - } else { - return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; - } - } -} - /** ZSTD_adjustCParams_internal() : * optimize `cPar` for a specified input (`srcSize` and `dictSize`). * mostly downsize to reduce memory consumption and initialization latency. * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. - * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`. - * note : `srcSize==0` means 0! + * note : for the time being, `srcSize==0` means "unknown" too, for compatibility with older convention. * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ static ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, - size_t dictSize, - ZSTD_cParamMode_e mode, - ZSTD_paramSwitch_e useRowMatchFinder) + size_t dictSize) { - const U64 minSrcSize = 513; /* (1<<9) + 1 */ - const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); + static const U64 minSrcSize = 513; /* (1<<9) + 1 */ + static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); assert(ZSTD_checkCParams(cPar)==0); - switch (mode) { - case ZSTD_cpm_unknown: - case ZSTD_cpm_noAttachDict: - /* If we don't know the source size, don't make any - * assumptions about it. We will already have selected - * smaller parameters if a dictionary is in use. - */ - break; - case ZSTD_cpm_createCDict: - /* Assume a small source size when creating a dictionary - * with an unknown source size. - */ - if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) - srcSize = minSrcSize; - break; - case ZSTD_cpm_attachDict: - /* Dictionary has its own dedicated parameters which have - * already been selected. We are selecting parameters - * for only the source. - */ - dictSize = 0; - break; - default: - assert(0); - break; - } + if (dictSize && (srcSize+1<2) /* ZSTD_CONTENTSIZE_UNKNOWN and 0 mean "unknown" */ ) + srcSize = minSrcSize; /* presumed small when there is a dictionary */ + else if (srcSize == 0) + srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ /* resize windowLog if input is small enough, to use less memory */ - if ( (srcSize <= maxWindowResize) - && (dictSize <= maxWindowResize) ) { + if ( (srcSize < maxWindowResize) + && (dictSize < maxWindowResize) ) { U32 const tSize = (U32)(srcSize + dictSize); static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : ZSTD_highbit32(tSize-1) + 1; if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; } - if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); - U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); - if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; - if (cycleLog > dictAndWindowLog) - cPar.chainLog -= (cycleLog - dictAndWindowLog); + if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; + { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); + if (cycleLog > cPar.windowLog) + cPar.chainLog -= (cycleLog - cPar.windowLog); } if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ - /* We can't use more than 32 bits of hash in total, so that means that we require: - * (hashLog + 8) <= 32 && (chainLog + 8) <= 32 - */ - if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(&cPar)) { - U32 const maxShortCacheHashLog = 32 - ZSTD_SHORT_CACHE_TAG_BITS; - if (cPar.hashLog > maxShortCacheHashLog) { - cPar.hashLog = maxShortCacheHashLog; - } - if (cPar.chainLog > maxShortCacheHashLog) { - cPar.chainLog = maxShortCacheHashLog; - } - } - - - /* At this point, we aren't 100% sure if we are using the row match finder. - * Unless it is explicitly disabled, conservatively assume that it is enabled. - * In this case it will only be disabled for small sources, so shrinking the - * hash log a little bit shouldn't result in any ratio loss. - */ - if (useRowMatchFinder == ZSTD_ps_auto) - useRowMatchFinder = ZSTD_ps_enable; - - /* We can't hash more than 32-bits in total. So that means that we require: - * (hashLog - rowLog + 8) <= 32 - */ - if (ZSTD_rowMatchFinderUsed(cPar.strategy, useRowMatchFinder)) { - /* Switch to 32-entry rows if searchLog is 5 (or more) */ - U32 const rowLog = BOUNDED(4, cPar.searchLog, 6); - U32 const maxRowHashLog = 32 - ZSTD_ROW_HASH_TAG_BITS; - U32 const maxHashLog = maxRowHashLog + rowLog; - assert(cPar.hashLog >= rowLog); - if (cPar.hashLog > maxHashLog) { - cPar.hashLog = maxHashLog; - } - } - return cPar; } @@ -1560,51 +1049,34 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar, size_t dictSize) { cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ - if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown, ZSTD_ps_auto); -} - -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); - -static void ZSTD_overrideCParams( - ZSTD_compressionParameters* cParams, - const ZSTD_compressionParameters* overrides) -{ - if (overrides->windowLog) cParams->windowLog = overrides->windowLog; - if (overrides->hashLog) cParams->hashLog = overrides->hashLog; - if (overrides->chainLog) cParams->chainLog = overrides->chainLog; - if (overrides->searchLog) cParams->searchLog = overrides->searchLog; - if (overrides->minMatch) cParams->minMatch = overrides->minMatch; - if (overrides->targetLength) cParams->targetLength = overrides->targetLength; - if (overrides->strategy) cParams->strategy = overrides->strategy; + return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); } ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) { ZSTD_compressionParameters cParams; if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { srcSizeHint = CCtxParams->srcSizeHint; } - cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); - if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; - ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); + cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); + if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; + if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; + if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; + if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; + if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; + if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; + if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; + if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; assert(!ZSTD_checkCParams(cParams)); - /* srcSizeHint == 0 means 0 */ - return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode, CCtxParams->useRowMatchFinder); + return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); } static size_t ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, - const ZSTD_paramSwitch_e useRowMatchFinder, - const U32 enableDedicatedDictSearch, const U32 forCCtx) { - /* chain table size should be 0 for fast or row-hash strategies */ - size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx) - ? ((size_t)1 << cParams->chainLog) - : 0; + size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; @@ -1614,131 +1086,58 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, + hSize * sizeof(U32) + h3Size * sizeof(U32); size_t const optPotentialSpace = - ZSTD_cwksp_aligned_alloc_size((MaxML+1) * sizeof(U32)) - + ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32)) - + ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32)) - + ZSTD_cwksp_aligned_alloc_size((1<strategy, useRowMatchFinder) - ? ZSTD_cwksp_aligned_alloc_size(hSize) - : 0; + ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32)) + + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32)) + + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32)) + + ZSTD_cwksp_alloc_size((1<strategy >= ZSTD_btopt)) ? optPotentialSpace : 0; - size_t const slackSpace = ZSTD_cwksp_slack_space_required(); - - /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */ - ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4); - assert(useRowMatchFinder != ZSTD_ps_auto); - DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", (U32)chainSize, (U32)hSize, (U32)h3Size); - return tableSpace + optSpace + slackSpace + lazyAdditionalSpace; -} - -/* Helper function for calculating memory requirements. - * Gives a tighter bound than ZSTD_sequenceBound() by taking minMatch into account. */ -static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useSequenceProducer) { - U32 const divider = (minMatch==3 || useSequenceProducer) ? 3 : 4; - return blockSize / divider; -} - -static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( - const ZSTD_compressionParameters* cParams, - const ldmParams_t* ldmParams, - const int isStatic, - const ZSTD_paramSwitch_e useRowMatchFinder, - const size_t buffInSize, - const size_t buffOutSize, - const U64 pledgedSrcSize, - int useSequenceProducer, - size_t maxBlockSize) -{ - size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); - size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(maxBlockSize), windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useSequenceProducer); - size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) - + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef)) - + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); - size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE); - size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); - - size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); - size_t const ldmSeqSpace = ldmParams->enableLdm == ZSTD_ps_enable ? - ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; - - - size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) - + ZSTD_cwksp_alloc_size(buffOutSize); - - size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; - - size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); - size_t const externalSeqSpace = useSequenceProducer - ? ZSTD_cwksp_aligned_alloc_size(maxNbExternalSeq * sizeof(ZSTD_Sequence)) - : 0; - - size_t const neededSpace = - cctxSpace + - entropySpace + - blockStateSpace + - ldmSpace + - ldmSeqSpace + - matchStateSize + - tokenSpace + - bufferSpace + - externalSeqSpace; - - DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); - return neededSpace; + return tableSpace + optSpace; } size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) { - ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, - &cParams); - RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); - /* estimateCCtxSize is for one-shot compression. So no buffers should - * be needed. However, we still allocate two 0-sized buffers, which can - * take space under ASAN. */ - return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize); + { ZSTD_compressionParameters const cParams = + ZSTD_getCParamsFromCCtxParams(params, 0, 0); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + U32 const divider = (cParams.minMatch==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) + + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); + size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); + size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); + size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); + + size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); + size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq)); + + size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + + matchStateSize + ldmSpace + ldmSeqSpace; + size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)); + + DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)cctxSpace); + DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); + return cctxSpace + neededSpace; + } } size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); - if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { - /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ - size_t noRowCCtxSize; - size_t rowCCtxSize; - initialParams.useRowMatchFinder = ZSTD_ps_disable; - noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); - initialParams.useRowMatchFinder = ZSTD_ps_enable; - rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); - return MAX(noRowCCtxSize, rowCCtxSize); - } else { - return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); - } + ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); } static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) { - int tier = 0; - size_t largestSize = 0; - static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; - for (; tier < 4; ++tier) { - /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); - largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); - } - return largestSize; + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); + return ZSTD_estimateCCtxSize_usingCParams(cParams); } size_t ZSTD_estimateCCtxSize(int compressionLevel) @@ -1746,7 +1145,6 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) int level; size_t memBudget = 0; for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { - /* Ensure monotonically increasing memory usage as compression level increases */ size_t const newMB = ZSTD_estimateCCtxSize_internal(level); if (newMB > memBudget) memBudget = newMB; } @@ -1757,42 +1155,27 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) { RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), (size_t)1 << cParams.windowLog); - size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) - ? ((size_t)1 << cParams.windowLog) + blockSize - : 0; - size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) - ? ZSTD_compressBound(blockSize) + 1 - : 0; - ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); - - return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, - ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize); + ZSTD_getCParamsFromCCtxParams(params, 0, 0); + size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; + size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; + size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize) + + ZSTD_cwksp_alloc_size(outBuffSize); + + return CCtxSize + streamingSize; } } size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); - if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { - /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ - size_t noRowCCtxSize; - size_t rowCCtxSize; - initialParams.useRowMatchFinder = ZSTD_ps_disable; - noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); - initialParams.useRowMatchFinder = ZSTD_ps_enable; - rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); - return MAX(noRowCCtxSize, rowCCtxSize); - } else { - return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); - } + ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); } static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); return ZSTD_estimateCStreamSize_usingCParams(cParams); } @@ -1860,7 +1243,7 @@ static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, assert(cParams1.strategy == cParams2.strategy); } -void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) +static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) @@ -1885,6 +1268,16 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) ms->dictMatchState = NULL; } +/** + * Indicates whether this compression proceeds directly from user-provided + * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or + * whether the context needs to buffer the input/output (ZSTDb_buffered). + */ +typedef enum { + ZSTDb_not_buffered, + ZSTDb_buffered +} ZSTD_buffered_policy_e; + /** * Controls, for this matchState reset, whether the tables need to be cleared / * prepared for the coming compression (ZSTDcrp_makeClean), or whether the @@ -1912,47 +1305,29 @@ typedef enum { ZSTD_resetTarget_CCtx } ZSTD_resetTarget_e; -/* Mixes bits in a 64 bits in a value, based on XXH3_rrmxmx */ -static U64 ZSTD_bitmix(U64 val, U64 len) { - val ^= ZSTD_rotateRight_U64(val, 49) ^ ZSTD_rotateRight_U64(val, 24); - val *= 0x9FB21C651E98DF25ULL; - val ^= (val >> 35) + len ; - val *= 0x9FB21C651E98DF25ULL; - return val ^ (val >> 28); -} - -/* Mixes in the hashSalt and hashSaltEntropy to create a new hashSalt */ -static void ZSTD_advanceHashSalt(ZSTD_matchState_t* ms) { - ms->hashSalt = ZSTD_bitmix(ms->hashSalt, 8) ^ ZSTD_bitmix((U64) ms->hashSaltEntropy, 4); -} - static size_t ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, const ZSTD_compressionParameters* cParams, - const ZSTD_paramSwitch_e useRowMatchFinder, const ZSTD_compResetPolicy_e crp, const ZSTD_indexResetPolicy_e forceResetIndex, const ZSTD_resetTarget_e forWho) { - /* disable chain table allocation for fast or row-based strategies */ - size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, - ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict)) - ? ((size_t)1 << cParams->chainLog) - : 0; + size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); - assert(useRowMatchFinder != ZSTD_ps_auto); if (forceResetIndex == ZSTDirp_reset) { - ZSTD_window_init(&ms->window); + memset(&ms->window, 0, sizeof(ms->window)); + ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ + ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ + ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ ZSTD_cwksp_mark_tables_dirty(ws); } ms->hashLog3 = hashLog3; - ms->lazySkipping = 0; ZSTD_invalidateMatchState(ms); @@ -1974,27 +1349,6 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp_clean_tables(ws); } - if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) { - /* Row match finder needs an additional table of hashes ("tags") */ - size_t const tagTableSize = hSize; - /* We want to generate a new salt in case we reset a Cctx, but we always want to use - * 0 when we reset a Cdict */ - if(forWho == ZSTD_resetTarget_CCtx) { - ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned_init_once(ws, tagTableSize); - ZSTD_advanceHashSalt(ms); - } else { - /* When we are not salting we want to always memset the memory */ - ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned(ws, tagTableSize); - ZSTD_memset(ms->tagTable, 0, tagTableSize); - ms->hashSalt = 0; - } - { /* Switch to 32-entry rows if searchLog is 5 (or more) */ - U32 const rowLog = BOUNDED(4, cParams->searchLog, 6); - assert(cParams->hashLog >= rowLog); - ms->rowHashLog = cParams->hashLog - rowLog; - } - } - /* opt parser space */ if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { DEBUGLOG(4, "reserving optimal parser space"); @@ -2010,6 +1364,7 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, "failed a workspace allocation in ZSTD_reset_matchState"); + return 0; } @@ -2026,87 +1381,75 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); } -/** ZSTD_dictTooBig(): - * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in - * one go generically. So we ensure that in that case we reset the tables to zero, - * so that we can load as much of the dictionary as possible. - */ -static int ZSTD_dictTooBig(size_t const loadedDictSize) -{ - return loadedDictSize > ZSTD_CHUNKSIZE_MAX; -} - /*! ZSTD_resetCCtx_internal() : - * @param loadedDictSize The size of the dictionary to be loaded - * into the context, if any. If no dictionary is used, or the - * dictionary is being attached / copied, then pass 0. - * note : `params` are assumed fully validated at this stage. - */ + note : `params` are assumed fully validated at this stage */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, - ZSTD_CCtx_params const* params, + ZSTD_CCtx_params params, U64 const pledgedSrcSize, - size_t const loadedDictSize, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { ZSTD_cwksp* const ws = &zc->workspace; - DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d useBlockSplitter=%d", - (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder, (int)params->useBlockSplitter); - assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); + DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", + (U32)pledgedSrcSize, params.cParams.windowLog); + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); zc->isFirstBlock = 1; - /* Set applied params early so we can modify them for LDM, - * and point params at the applied params. - */ - zc->appliedParams = *params; - params = &zc->appliedParams; - - assert(params->useRowMatchFinder != ZSTD_ps_auto); - assert(params->useBlockSplitter != ZSTD_ps_auto); - assert(params->ldmParams.enableLdm != ZSTD_ps_auto); - assert(params->maxBlockSize != 0); - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + if (params.ldmParams.enableLdm) { /* Adjust long distance matching parameters */ - ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams); - assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog); - assert(params->ldmParams.hashRateLog < 32); - } + ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); + assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); + assert(params.ldmParams.hashRateLog < 32); + zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); + } + + { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); + U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) + + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); + size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; + size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; + size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); + + ZSTD_indexResetPolicy_e needsIndexReset = ZSTDirp_continue; + + if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { + needsIndexReset = ZSTDirp_reset; + } + + ZSTD_cwksp_bump_oversized_duration(ws, 0); + + /* Check if workspace is large enough, alloc a new one if needed */ + { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; + size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); + size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); + size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize); + size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); + size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)); + + size_t const neededSpace = + cctxSpace + + entropySpace + + blockStateSpace + + ldmSpace + + ldmSeqSpace + + matchStateSize + + tokenSpace + + bufferSpace; - { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize)); - size_t const blockSize = MIN(params->maxBlockSize, windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, params->useSequenceProducer); - size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) - ? ZSTD_compressBound(blockSize) + 1 - : 0; - size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered) - ? windowSize + blockSize - : 0; - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize); - - int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window); - int const dictTooBig = ZSTD_dictTooBig(loadedDictSize); - ZSTD_indexResetPolicy_e needsIndexReset = - (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue; - - size_t const neededSpace = - ZSTD_estimateCCtxSize_usingCCtxParams_internal( - ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, - buffInSize, buffOutSize, pledgedSrcSize, params->useSequenceProducer, params->maxBlockSize); - int resizeWorkspace; - - FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); - - if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); - - { /* Check if workspace is large enough, alloc a new one if needed */ int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); - resizeWorkspace = workspaceTooSmall || workspaceWasteful; - DEBUGLOG(4, "Need %zu B workspace", neededSpace); + + DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", + neededSpace>>10, matchStateSize>>10, bufferSpace>>10); DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); - if (resizeWorkspace) { + if (workspaceTooSmall || workspaceWasteful) { DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", ZSTD_cwksp_sizeof(ws) >> 10, neededSpace >> 10); @@ -2116,7 +1459,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, needsIndexReset = ZSTDirp_reset; ZSTD_cwksp_free(ws, zc->customMem); - FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), ""); + FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem)); DEBUGLOG(5, "reserving object space"); /* Statically sized space. @@ -2127,15 +1470,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); - zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE); - RETURN_ERROR_IF(zc->entropyWorkspace == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); + zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE); + RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); } } ZSTD_cwksp_clear(ws); /* init params */ - zc->blockState.matchState.cParams = params->cParams; - zc->blockState.matchState.prefetchCDictTables = params->prefetchCDictTables == ZSTD_ps_enable; + zc->appliedParams = params; + zc->blockState.matchState.cParams = params.cParams; zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; zc->producedCSize = 0; @@ -2148,64 +1491,29 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, XXH64_reset(&zc->xxhState, 0); zc->stage = ZSTDcs_init; zc->dictID = 0; - zc->dictContentSize = 0; ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); - FORWARD_IF_ERROR(ZSTD_reset_matchState( - &zc->blockState.matchState, - ws, - ¶ms->cParams, - params->useRowMatchFinder, - crp, - needsIndexReset, - ZSTD_resetTarget_CCtx), ""); - - zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); - - /* ldm hash table */ - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { - /* TODO: avoid memset? */ - size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog; - zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); - ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); - zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); - zc->maxNbLdmSequences = maxNbLdmSeq; - - ZSTD_window_init(&zc->ldmState.window); - zc->ldmState.loadedDictEnd = 0; - } - - /* reserve space for block-level external sequences */ - if (params->useSequenceProducer) { - size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); - zc->externalMatchCtx.seqBufferCapacity = maxNbExternalSeq; - zc->externalMatchCtx.seqBuffer = - (ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence)); - } - - /* buffers */ - /* ZSTD_wildcopy() is used to copy into the literals buffer, * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. */ zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); zc->seqStore.maxNbLit = blockSize; - zc->bufferedPolicy = zbuff; + /* buffers */ zc->inBuffSize = buffInSize; zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); zc->outBuffSize = buffOutSize; zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); /* ldm bucketOffsets table */ - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + if (params.ldmParams.enableLdm) { /* TODO: avoid memset? */ - size_t const numBuckets = - ((size_t)1) << (params->ldmParams.hashLog - - params->ldmParams.bucketSizeLog); - zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); - ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); + size_t const ldmBucketSize = + ((size_t)1) << (params.ldmParams.hashLog - + params.ldmParams.bucketSizeLog); + zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize); + memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize); } /* sequences storage */ @@ -2214,11 +1522,30 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); + zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); - DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); - assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace)); + FORWARD_IF_ERROR(ZSTD_reset_matchState( + &zc->blockState.matchState, + ws, + ¶ms.cParams, + crp, + needsIndexReset, + ZSTD_resetTarget_CCtx)); + + /* ldm hash table */ + if (params.ldmParams.enableLdm) { + /* TODO: avoid memset? */ + size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; + zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); + memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); + zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); + zc->maxNbLdmSequences = maxNbLdmSeq; + + memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); + ZSTD_window_clear(&zc->ldmState.window); + } - zc->initialized = 1; + DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); return 0; } @@ -2256,14 +1583,12 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, U64 pledgedSrcSize) { size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; - int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; - return dedicatedDictSearch - || ( ( pledgedSrcSize <= cutoff - || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || params->attachDictPref == ZSTD_dictForceAttach ) - && params->attachDictPref != ZSTD_dictForceCopy - && !params->forceWindow ); /* dictMatchState isn't correctly - * handled in _enforceMaxDist */ + return ( pledgedSrcSize <= cutoff + || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN + || params->attachDictPref == ZSTD_dictForceAttach ) + && params->attachDictPref != ZSTD_dictForceCopy + && !params->forceWindow; /* dictMatchState isn't correctly + * handled in _enforceMaxDist */ } static size_t @@ -2273,29 +1598,16 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu", - (unsigned long long)pledgedSrcSize); - { - ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; + { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Resize working context table params for input only, since the dict * has its own tables. */ - /* pledgedSrcSize == 0 means 0! */ - - if (cdict->matchState.dedicatedDictSearch) { - ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); - } - - params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, - cdict->dictContentSize, ZSTD_cpm_attachDict, - params.useRowMatchFinder); + params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); params.cParams.windowLog = windowLog; - params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */ - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, - /* loadedDictSize */ 0, - ZSTDcrp_makeClean, zbuff), ""); - assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + ZSTDcrp_makeClean, zbuff)); + assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); } { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc @@ -2320,30 +1632,13 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, } } cctx->dictID = cdict->dictID; - cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } -static void ZSTD_copyCDictTableIntoCCtx(U32* dst, U32 const* src, size_t tableSize, - ZSTD_compressionParameters const* cParams) { - if (ZSTD_CDictIndicesAreTagged(cParams)){ - /* Remove tags from the CDict table if they are present. - * See docs on "short cache" in zstd_compress_internal.h for context. */ - size_t i; - for (i = 0; i < tableSize; i++) { - U32 const taggedIndex = src[i]; - U32 const index = taggedIndex >> ZSTD_SHORT_CACHE_TAG_BITS; - dst[i] = index; - } - } else { - ZSTD_memcpy(dst, src, tableSize * sizeof(U32)); - } -} - static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, @@ -2352,58 +1647,39 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, { const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; - assert(!cdict->matchState.dedicatedDictSearch); - DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu", - (unsigned long long)pledgedSrcSize); + DEBUGLOG(4, "copying dictionary into context"); { unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Copy only compression parameters related to tables. */ params.cParams = *cdict_cParams; params.cParams.windowLog = windowLog; - params.useRowMatchFinder = cdict->useRowMatchFinder; - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, - /* loadedDictSize */ 0, - ZSTDcrp_leaveDirty, zbuff), ""); + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + ZSTDcrp_leaveDirty, zbuff)); assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); } ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); - assert(params.useRowMatchFinder != ZSTD_ps_auto); /* copy tables */ - { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */) - ? ((size_t)1 << cdict_cParams->chainLog) - : 0; + { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); size_t const hSize = (size_t)1 << cdict_cParams->hashLog; - ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.hashTable, - cdict->matchState.hashTable, - hSize, cdict_cParams); - - /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */ - if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) { - ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.chainTable, - cdict->matchState.chainTable, - chainSize, cdict_cParams); - } - /* copy tag table */ - if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) { - size_t const tagTableSize = hSize; - ZSTD_memcpy(cctx->blockState.matchState.tagTable, - cdict->matchState.tagTable, - tagTableSize); - cctx->blockState.matchState.hashSalt = cdict->matchState.hashSalt; - } - } + memcpy(cctx->blockState.matchState.hashTable, + cdict->matchState.hashTable, + hSize * sizeof(U32)); + memcpy(cctx->blockState.matchState.chainTable, + cdict->matchState.chainTable, + chainSize * sizeof(U32)); + } /* Zero the hashTable3, since the cdict never fills it */ { int const h3log = cctx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; assert(cdict->matchState.hashLog3 == 0); - ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); + memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); } ZSTD_cwksp_mark_tables_clean(&cctx->workspace); @@ -2417,10 +1693,9 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, } cctx->dictID = cdict->dictID; - cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } @@ -2460,23 +1735,15 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong, - "Can't copy a ctx that's not in init stage."); DEBUGLOG(5, "ZSTD_copyCCtx_internal"); - ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); + RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong); + + memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); { ZSTD_CCtx_params params = dstCCtx->requestedParams; /* Copy only compression parameters related to tables. */ params.cParams = srcCCtx->appliedParams.cParams; - assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_ps_auto); - assert(srcCCtx->appliedParams.useBlockSplitter != ZSTD_ps_auto); - assert(srcCCtx->appliedParams.ldmParams.enableLdm != ZSTD_ps_auto); - params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder; - params.useBlockSplitter = srcCCtx->appliedParams.useBlockSplitter; - params.ldmParams = srcCCtx->appliedParams.ldmParams; params.fParams = fParams; - params.maxBlockSize = srcCCtx->appliedParams.maxBlockSize; - ZSTD_resetCCtx_internal(dstCCtx, ¶ms, pledgedSrcSize, - /* loadedDictSize */ 0, + ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_leaveDirty, zbuff); assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); @@ -2488,22 +1755,18 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); /* copy tables */ - { size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy, - srcCCtx->appliedParams.useRowMatchFinder, - 0 /* forDDSDict */) - ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog) - : 0; + { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; int const h3log = srcCCtx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; - ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable, + memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, hSize * sizeof(U32)); - ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable, + memcpy(dstCCtx->blockState.matchState.chainTable, srcCCtx->blockState.matchState.chainTable, chainSize * sizeof(U32)); - ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3, + memcpy(dstCCtx->blockState.matchState.hashTable3, srcCCtx->blockState.matchState.hashTable3, h3Size * sizeof(U32)); } @@ -2519,10 +1782,9 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; } dstCCtx->dictID = srcCCtx->dictID; - dstCCtx->dictContentSize = srcCCtx->dictContentSize; /* copy block state */ - ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); + memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); return 0; } @@ -2535,7 +1797,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) { ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy; + ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); @@ -2559,12 +1821,10 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa int const nbRows = (int)size / ZSTD_ROWSIZE; int cellNb = 0; int rowNb; - /* Protect special index values < ZSTD_WINDOW_START_INDEX. */ - U32 const reducerThreshold = reducerValue + ZSTD_WINDOW_START_INDEX; assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ assert(size < (1U<<31)); /* can be casted to int */ -#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) +#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) /* To validate that the table re-use logic is sound, and that we don't * access table space that we haven't cleaned, we re-"poison" the table * space every time we mark it dirty. @@ -2580,17 +1840,12 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa for (rowNb=0 ; rowNb < nbRows ; rowNb++) { int column; for (column=0; columnhashTable, hSize, reducerValue); } - if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) { + if (params->cParams.strategy != ZSTD_fast) { U32 const chainSize = (U32)1 << params->cParams.chainLog; if (params->cParams.strategy == ZSTD_btlazy2) ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); @@ -2634,7 +1889,17 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par /* See doc/zstd_compression_format.md for detailed format description */ -int ZSTD_seqToCodes(const seqStore_t* seqStorePtr) +static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) +{ + U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); + RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, + dstSize_tooSmall); + MEM_writeLE24(dst, cBlockHeader24); + memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); + return ZSTD_blockHeaderSize + srcSize; +} + +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) { const seqDef* const sequences = seqStorePtr->sequencesStart; BYTE* const llCodeTable = seqStorePtr->llCode; @@ -2642,280 +1907,192 @@ int ZSTD_seqToCodes(const seqStore_t* seqStorePtr) BYTE* const mlCodeTable = seqStorePtr->mlCode; U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); U32 u; - int longOffsets = 0; assert(nbSeq <= seqStorePtr->maxNbSeq); for (u=0; u= STREAM_ACCUMULATOR_MIN)); - if (MEM_32bits() && ofCode >= STREAM_ACCUMULATOR_MIN) - longOffsets = 1; } - if (seqStorePtr->longLengthType==ZSTD_llt_literalLength) + if (seqStorePtr->longLengthID==1) llCodeTable[seqStorePtr->longLengthPos] = MaxLL; - if (seqStorePtr->longLengthType==ZSTD_llt_matchLength) + if (seqStorePtr->longLengthID==2) mlCodeTable[seqStorePtr->longLengthPos] = MaxML; - return longOffsets; } -/* ZSTD_useTargetCBlockSize(): - * Returns if target compressed block size param is being used. - * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize. - * Returns 1 if true, 0 otherwise. */ -static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams) +static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) { - DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize); - return (cctxParams->targetCBlockSize != 0); + switch (cctxParams->literalCompressionMode) { + case ZSTD_lcm_huffman: + return 0; + case ZSTD_lcm_uncompressed: + return 1; + default: + assert(0 /* impossible: pre-validated */); + /* fall-through */ + case ZSTD_lcm_auto: + return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); + } } -/* ZSTD_blockSplitterEnabled(): - * Returns if block splitting param is being used - * If used, compression will do best effort to split a block in order to improve compression ratio. - * At the time this function is called, the parameter must be finalized. - * Returns 1 if true, 0 otherwise. */ -static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams) +/* ZSTD_compressSequences_internal(): + * actually compresses both literals and sequences */ +MEM_STATIC size_t +ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + void* entropyWorkspace, size_t entropyWkspSize, + const int bmi2) { - DEBUGLOG(5, "ZSTD_blockSplitterEnabled (useBlockSplitter=%d)", cctxParams->useBlockSplitter); - assert(cctxParams->useBlockSplitter != ZSTD_ps_auto); - return (cctxParams->useBlockSplitter == ZSTD_ps_enable); -} - -/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types - * and size of the sequences statistics - */ -typedef struct { - U32 LLtype; - U32 Offtype; - U32 MLtype; - size_t size; - size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ - int longOffsets; -} ZSTD_symbolEncodingTypeStats_t; - -/* ZSTD_buildSequencesStatistics(): - * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field. - * Modifies `nextEntropy` to have the appropriate values as a side effect. - * nbSeq must be greater than 0. - * - * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32) - */ -static ZSTD_symbolEncodingTypeStats_t -ZSTD_buildSequencesStatistics( - const seqStore_t* seqStorePtr, size_t nbSeq, - const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy, - BYTE* dst, const BYTE* const dstEnd, - ZSTD_strategy strategy, unsigned* countWorkspace, - void* entropyWorkspace, size_t entropyWkspSize) -{ - BYTE* const ostart = dst; - const BYTE* const oend = dstEnd; - BYTE* op = ostart; - FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; - FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; - FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; + const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; + ZSTD_strategy const strategy = cctxParams->cParams.strategy; + unsigned count[MaxSeq+1]; + FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; + FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; + FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; + U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ + const seqDef* const sequences = seqStorePtr->sequencesStart; const BYTE* const ofCodeTable = seqStorePtr->ofCode; const BYTE* const llCodeTable = seqStorePtr->llCode; const BYTE* const mlCodeTable = seqStorePtr->mlCode; - ZSTD_symbolEncodingTypeStats_t stats; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + dstCapacity; + BYTE* op = ostart; + size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + BYTE* seqHead; + BYTE* lastNCount = NULL; - stats.lastCountSize = 0; - /* convert length/distances into codes */ - stats.longOffsets = ZSTD_seqToCodes(seqStorePtr); + DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq); + ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<litStart; + size_t const litSize = (size_t)(seqStorePtr->lit - literals); + size_t const cSize = ZSTD_compressLiterals( + &prevEntropy->huf, &nextEntropy->huf, + cctxParams->cParams.strategy, + ZSTD_disableLiteralsCompression(cctxParams), + op, dstCapacity, + literals, litSize, + entropyWorkspace, entropyWkspSize, + bmi2); + FORWARD_IF_ERROR(cSize); + assert(cSize <= dstCapacity); + op += cSize; + } + + /* Sequences Header */ + RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, + dstSize_tooSmall); + if (nbSeq < 128) { + *op++ = (BYTE)nbSeq; + } else if (nbSeq < LONGNBSEQ) { + op[0] = (BYTE)((nbSeq>>8) + 0x80); + op[1] = (BYTE)nbSeq; + op+=2; + } else { + op[0]=0xFF; + MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)); + op+=3; + } + assert(op <= oend); + if (nbSeq==0) { + /* Copy the old tables over as if we repeated them */ + memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); + return (size_t)(op - ostart); + } + + /* seqHead : flags for FSE encoding type */ + seqHead = op++; assert(op <= oend); - assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */ + + /* convert length/distances into codes */ + ZSTD_seqToCodes(seqStorePtr); /* build CTable for Literal Lengths */ { unsigned max = MaxLL; - size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ DEBUGLOG(5, "Building LL table"); - nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; - stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, - countWorkspace, max, mostFrequent, nbSeq, - LLFSELog, prevEntropy->litlengthCTable, + nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; + LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, + count, max, mostFrequent, nbSeq, + LLFSELog, prevEntropy->fse.litlengthCTable, LL_defaultNorm, LL_defaultNormLog, ZSTD_defaultAllowed, strategy); assert(set_basic < set_compressed && set_rle < set_compressed); - assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ { size_t const countSize = ZSTD_buildCTable( op, (size_t)(oend - op), - CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype, - countWorkspace, max, llCodeTable, nbSeq, + CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, + count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, - prevEntropy->litlengthCTable, - sizeof(prevEntropy->litlengthCTable), + prevEntropy->fse.litlengthCTable, + sizeof(prevEntropy->fse.litlengthCTable), entropyWorkspace, entropyWkspSize); - if (ZSTD_isError(countSize)) { - DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed"); - stats.size = countSize; - return stats; - } - if (stats.LLtype == set_compressed) - stats.lastCountSize = countSize; + FORWARD_IF_ERROR(countSize); + if (LLtype == set_compressed) + lastNCount = op; op += countSize; assert(op <= oend); } } /* build CTable for Offsets */ { unsigned max = MaxOff; size_t const mostFrequent = HIST_countFast_wksp( - countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; DEBUGLOG(5, "Building OF table"); - nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; - stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, - countWorkspace, max, mostFrequent, nbSeq, - OffFSELog, prevEntropy->offcodeCTable, + nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; + Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, + count, max, mostFrequent, nbSeq, + OffFSELog, prevEntropy->fse.offcodeCTable, OF_defaultNorm, OF_defaultNormLog, defaultPolicy, strategy); - assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ { size_t const countSize = ZSTD_buildCTable( op, (size_t)(oend - op), - CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype, - countWorkspace, max, ofCodeTable, nbSeq, + CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, + count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, - prevEntropy->offcodeCTable, - sizeof(prevEntropy->offcodeCTable), + prevEntropy->fse.offcodeCTable, + sizeof(prevEntropy->fse.offcodeCTable), entropyWorkspace, entropyWkspSize); - if (ZSTD_isError(countSize)) { - DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed"); - stats.size = countSize; - return stats; - } - if (stats.Offtype == set_compressed) - stats.lastCountSize = countSize; + FORWARD_IF_ERROR(countSize); + if (Offtype == set_compressed) + lastNCount = op; op += countSize; assert(op <= oend); } } /* build CTable for MatchLengths */ { unsigned max = MaxML; size_t const mostFrequent = HIST_countFast_wksp( - countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); - nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; - stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, - countWorkspace, max, mostFrequent, nbSeq, - MLFSELog, prevEntropy->matchlengthCTable, + nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; + MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, + count, max, mostFrequent, nbSeq, + MLFSELog, prevEntropy->fse.matchlengthCTable, ML_defaultNorm, ML_defaultNormLog, ZSTD_defaultAllowed, strategy); - assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ { size_t const countSize = ZSTD_buildCTable( op, (size_t)(oend - op), - CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype, - countWorkspace, max, mlCodeTable, nbSeq, + CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, + count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, - prevEntropy->matchlengthCTable, - sizeof(prevEntropy->matchlengthCTable), + prevEntropy->fse.matchlengthCTable, + sizeof(prevEntropy->fse.matchlengthCTable), entropyWorkspace, entropyWkspSize); - if (ZSTD_isError(countSize)) { - DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed"); - stats.size = countSize; - return stats; - } - if (stats.MLtype == set_compressed) - stats.lastCountSize = countSize; + FORWARD_IF_ERROR(countSize); + if (MLtype == set_compressed) + lastNCount = op; op += countSize; assert(op <= oend); } } - stats.size = (size_t)(op-ostart); - return stats; -} - -/* ZSTD_entropyCompressSeqStore_internal(): - * compresses both literals and sequences - * Returns compressed size of block, or a zstd error. - */ -#define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20 -MEM_STATIC size_t -ZSTD_entropyCompressSeqStore_internal( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - void* entropyWorkspace, size_t entropyWkspSize, - const int bmi2) -{ - ZSTD_strategy const strategy = cctxParams->cParams.strategy; - unsigned* count = (unsigned*)entropyWorkspace; - FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; - FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; - FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; - const seqDef* const sequences = seqStorePtr->sequencesStart; - const size_t nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - const BYTE* const ofCodeTable = seqStorePtr->ofCode; - const BYTE* const llCodeTable = seqStorePtr->llCode; - const BYTE* const mlCodeTable = seqStorePtr->mlCode; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ostart + dstCapacity; - BYTE* op = ostart; - size_t lastCountSize; - int longOffsets = 0; - - entropyWorkspace = count + (MaxSeq + 1); - entropyWkspSize -= (MaxSeq + 1) * sizeof(*count); - - DEBUGLOG(5, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu, dstCapacity=%zu)", nbSeq, dstCapacity); - ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= HUF_WORKSPACE_SIZE); - - /* Compress literals */ - { const BYTE* const literals = seqStorePtr->litStart; - size_t const numSequences = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - size_t const numLiterals = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); - /* Base suspicion of uncompressibility on ratio of literals to sequences */ - unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO); - size_t const litSize = (size_t)(seqStorePtr->lit - literals); - - size_t const cSize = ZSTD_compressLiterals( - op, dstCapacity, - literals, litSize, - entropyWorkspace, entropyWkspSize, - &prevEntropy->huf, &nextEntropy->huf, - cctxParams->cParams.strategy, - ZSTD_literalsCompressionIsDisabled(cctxParams), - suspectUncompressible, bmi2); - FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); - assert(cSize <= dstCapacity); - op += cSize; - } - /* Sequences Header */ - RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, - dstSize_tooSmall, "Can't fit seq hdr in output buf!"); - if (nbSeq < 128) { - *op++ = (BYTE)nbSeq; - } else if (nbSeq < LONGNBSEQ) { - op[0] = (BYTE)((nbSeq>>8) + 0x80); - op[1] = (BYTE)nbSeq; - op+=2; - } else { - op[0]=0xFF; - MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)); - op+=3; - } - assert(op <= oend); - if (nbSeq==0) { - /* Copy the old tables over as if we repeated them */ - ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); - return (size_t)(op - ostart); - } - { BYTE* const seqHead = op++; - /* build stats for sequences */ - const ZSTD_symbolEncodingTypeStats_t stats = - ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, - &prevEntropy->fse, &nextEntropy->fse, - op, oend, - strategy, count, - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); - *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2)); - lastCountSize = stats.lastCountSize; - op += stats.size; - longOffsets = stats.longOffsets; - } + *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); { size_t const bitstreamSize = ZSTD_encodeSequences( op, (size_t)(oend - op), @@ -2924,7 +2101,7 @@ ZSTD_entropyCompressSeqStore_internal( CTable_LitLength, llCodeTable, sequences, nbSeq, longOffsets, bmi2); - FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); + FORWARD_IF_ERROR(bitstreamSize); op += bitstreamSize; assert(op <= oend); /* zstd versions <= 1.3.4 mistakenly report corruption when @@ -2935,9 +2112,9 @@ ZSTD_entropyCompressSeqStore_internal( * In this exceedingly rare case, we will simply emit an uncompressed * block, since it isn't worth optimizing. */ - if (lastCountSize && (lastCountSize + bitstreamSize) < 4) { - /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ - assert(lastCountSize + bitstreamSize == 3); + if (lastNCount && (op - lastNCount) < 4) { + /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ + assert(op - lastNCount == 3); DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " "emitting an uncompressed block."); return 0; @@ -2949,17 +2126,16 @@ ZSTD_entropyCompressSeqStore_internal( } MEM_STATIC size_t -ZSTD_entropyCompressSeqStore( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - size_t srcSize, - void* entropyWorkspace, size_t entropyWkspSize, - int bmi2) -{ - size_t const cSize = ZSTD_entropyCompressSeqStore_internal( +ZSTD_compressSequences(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + size_t srcSize, + void* entropyWorkspace, size_t entropyWkspSize, + int bmi2) +{ + size_t const cSize = ZSTD_compressSequences_internal( seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, entropyWorkspace, entropyWkspSize, bmi2); @@ -2967,30 +2143,24 @@ ZSTD_entropyCompressSeqStore( /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. */ - if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) { - DEBUGLOG(4, "not enough dstCapacity (%zu) for ZSTD_entropyCompressSeqStore_internal()=> do not compress block", dstCapacity); + if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) return 0; /* block not compressed */ - } - FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed"); + FORWARD_IF_ERROR(cSize); /* Check compressibility */ { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); if (cSize >= maxCSize) return 0; /* block not compressed */ } - DEBUGLOG(5, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize); - /* libzstd decoder before > v1.5.4 is not compatible with compressed blocks of size ZSTD_BLOCKSIZE_MAX exactly. - * This restriction is indirectly already fulfilled by respecting ZSTD_minGain() condition above. - */ - assert(cSize < ZSTD_BLOCKSIZE_MAX); + return cSize; } /* ZSTD_selectBlockCompressor() : * Not static, but internal use only (used by long distance matcher) * assumption : strat is a valid strategy */ -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e useRowMatchFinder, ZSTD_dictMode_e dictMode) +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) { - static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = { + static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { { ZSTD_compressBlock_fast /* default for 0 */, ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, @@ -3020,44 +2190,13 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramS ZSTD_compressBlock_btlazy2_dictMatchState, ZSTD_compressBlock_btopt_dictMatchState, ZSTD_compressBlock_btultra_dictMatchState, - ZSTD_compressBlock_btultra_dictMatchState }, - { NULL /* default for 0 */, - NULL, - NULL, - ZSTD_compressBlock_greedy_dedicatedDictSearch, - ZSTD_compressBlock_lazy_dedicatedDictSearch, - ZSTD_compressBlock_lazy2_dedicatedDictSearch, - NULL, - NULL, - NULL, - NULL } + ZSTD_compressBlock_btultra_dictMatchState } }; ZSTD_blockCompressor selectedCompressor; ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); - DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder); - if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) { - static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = { - { ZSTD_compressBlock_greedy_row, - ZSTD_compressBlock_lazy_row, - ZSTD_compressBlock_lazy2_row }, - { ZSTD_compressBlock_greedy_extDict_row, - ZSTD_compressBlock_lazy_extDict_row, - ZSTD_compressBlock_lazy2_extDict_row }, - { ZSTD_compressBlock_greedy_dictMatchState_row, - ZSTD_compressBlock_lazy_dictMatchState_row, - ZSTD_compressBlock_lazy2_dictMatchState_row }, - { ZSTD_compressBlock_greedy_dedicatedDictSearch_row, - ZSTD_compressBlock_lazy_dedicatedDictSearch_row, - ZSTD_compressBlock_lazy2_dedicatedDictSearch_row } - }; - DEBUGLOG(4, "Selecting a row-based matchfinder"); - assert(useRowMatchFinder != ZSTD_ps_auto); - selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy]; - } else { - selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; - } + selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; assert(selectedCompressor != NULL); return selectedCompressor; } @@ -3065,7 +2204,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramS static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, const BYTE* anchor, size_t lastLLSize) { - ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize); + memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -3073,73 +2212,7 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) { ssPtr->lit = ssPtr->litStart; ssPtr->sequences = ssPtr->sequencesStart; - ssPtr->longLengthType = ZSTD_llt_none; -} - -/* ZSTD_postProcessSequenceProducerResult() : - * Validates and post-processes sequences obtained through the external matchfinder API: - * - Checks whether nbExternalSeqs represents an error condition. - * - Appends a block delimiter to outSeqs if one is not already present. - * See zstd.h for context regarding block delimiters. - * Returns the number of sequences after post-processing, or an error code. */ -static size_t ZSTD_postProcessSequenceProducerResult( - ZSTD_Sequence* outSeqs, size_t nbExternalSeqs, size_t outSeqsCapacity, size_t srcSize -) { - RETURN_ERROR_IF( - nbExternalSeqs > outSeqsCapacity, - sequenceProducer_failed, - "External sequence producer returned error code %lu", - (unsigned long)nbExternalSeqs - ); - - RETURN_ERROR_IF( - nbExternalSeqs == 0 && srcSize > 0, - sequenceProducer_failed, - "Got zero sequences from external sequence producer for a non-empty src buffer!" - ); - - if (srcSize == 0) { - ZSTD_memset(&outSeqs[0], 0, sizeof(ZSTD_Sequence)); - return 1; - } - - { - ZSTD_Sequence const lastSeq = outSeqs[nbExternalSeqs - 1]; - - /* We can return early if lastSeq is already a block delimiter. */ - if (lastSeq.offset == 0 && lastSeq.matchLength == 0) { - return nbExternalSeqs; - } - - /* This error condition is only possible if the external matchfinder - * produced an invalid parse, by definition of ZSTD_sequenceBound(). */ - RETURN_ERROR_IF( - nbExternalSeqs == outSeqsCapacity, - sequenceProducer_failed, - "nbExternalSeqs == outSeqsCapacity but lastSeq is not a block delimiter!" - ); - - /* lastSeq is not a block delimiter, so we need to append one. */ - ZSTD_memset(&outSeqs[nbExternalSeqs], 0, sizeof(ZSTD_Sequence)); - return nbExternalSeqs + 1; - } -} - -/* ZSTD_fastSequenceLengthSum() : - * Returns sum(litLen) + sum(matchLen) + lastLits for *seqBuf*. - * Similar to another function in zstd_compress.c (determine_blockSize), - * except it doesn't check for a block delimiter to end summation. - * Removing the early exit allows the compiler to auto-vectorize (https://godbolt.org/z/cY1cajz9P). - * This function can be deleted and replaced by determine_blockSize after we resolve issue #3456. */ -static size_t ZSTD_fastSequenceLengthSum(ZSTD_Sequence const* seqBuf, size_t seqBufSize) { - size_t matchLenSum, litLenSum, i; - matchLenSum = 0; - litLenSum = 0; - for (i = 0; i < seqBufSize; i++) { - litLenSum += seqBuf[i].litLength; - matchLenSum += seqBuf[i].matchLength; - } - return litLenSum + matchLenSum; + ssPtr->longLengthID = 0; } typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; @@ -3151,14 +2224,8 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) assert(srcSize <= ZSTD_BLOCKSIZE_MAX); /* Assert that we have correctly flushed the ctx params into the ms's copy */ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); - /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding - * additional 1. We need to revisit and change this logic to be more consistent */ - if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { - if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) { - ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize); - } else { - ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); - } + if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { + ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ } ZSTD_resetSeqStore(&(zc->seqStore)); @@ -3174,10 +2241,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) /* limited update after a very long match */ { const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const U32 curr = (U32)(istart-base); + const U32 current = (U32)(istart-base); if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ - if (curr > ms->nextToUpdate + 384) - ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); + if (current > ms->nextToUpdate + 384) + ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); } /* select and store sequences */ @@ -3188,115 +2255,32 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; } if (zc->externSeqStore.pos < zc->externSeqStore.size) { - assert(zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_disable); - - /* External matchfinder + LDM is technically possible, just not implemented yet. - * We need to revisit soon and implement it. */ - RETURN_ERROR_IF( - zc->appliedParams.useSequenceProducer, - parameter_combination_unsupported, - "Long-distance matching with external sequence producer enabled is not currently supported." - ); - + assert(!zc->appliedParams.ldmParams.enableLdm); /* Updates ldmSeqStore.pos */ lastLLSize = ZSTD_ldm_blockCompress(&zc->externSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, - zc->appliedParams.useRowMatchFinder, src, srcSize); assert(zc->externSeqStore.pos <= zc->externSeqStore.size); - } else if (zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { - rawSeqStore_t ldmSeqStore = kNullRawSeqStore; - - /* External matchfinder + LDM is technically possible, just not implemented yet. - * We need to revisit soon and implement it. */ - RETURN_ERROR_IF( - zc->appliedParams.useSequenceProducer, - parameter_combination_unsupported, - "Long-distance matching with external sequence producer enabled is not currently supported." - ); + } else if (zc->appliedParams.ldmParams.enableLdm) { + rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; ldmSeqStore.seq = zc->ldmSequences; ldmSeqStore.capacity = zc->maxNbLdmSequences; /* Updates ldmSeqStore.size */ FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, &zc->appliedParams.ldmParams, - src, srcSize), ""); + src, srcSize)); /* Updates ldmSeqStore.pos */ lastLLSize = ZSTD_ldm_blockCompress(&ldmSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, - zc->appliedParams.useRowMatchFinder, src, srcSize); assert(ldmSeqStore.pos == ldmSeqStore.size); - } else if (zc->appliedParams.useSequenceProducer) { - assert( - zc->externalMatchCtx.seqBufferCapacity >= ZSTD_sequenceBound(srcSize) - ); - assert(zc->externalMatchCtx.mFinder != NULL); - - { U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog; - - size_t const nbExternalSeqs = (zc->externalMatchCtx.mFinder)( - zc->externalMatchCtx.mState, - zc->externalMatchCtx.seqBuffer, - zc->externalMatchCtx.seqBufferCapacity, - src, srcSize, - NULL, 0, /* dict and dictSize, currently not supported */ - zc->appliedParams.compressionLevel, - windowSize - ); - - size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult( - zc->externalMatchCtx.seqBuffer, - nbExternalSeqs, - zc->externalMatchCtx.seqBufferCapacity, - srcSize - ); - - /* Return early if there is no error, since we don't need to worry about last literals */ - if (!ZSTD_isError(nbPostProcessedSeqs)) { - ZSTD_sequencePosition seqPos = {0,0,0}; - size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs); - RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!"); - FORWARD_IF_ERROR( - ZSTD_copySequencesToSeqStoreExplicitBlockDelim( - zc, &seqPos, - zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs, - src, srcSize, - zc->appliedParams.searchForExternalRepcodes - ), - "Failed to copy external sequences to seqStore!" - ); - ms->ldmSeqStore = NULL; - DEBUGLOG(5, "Copied %lu sequences from external sequence producer to internal seqStore.", (unsigned long)nbExternalSeqs); - return ZSTDbss_compress; - } - - /* Propagate the error if fallback is disabled */ - if (!zc->appliedParams.enableMatchFinderFallback) { - return nbPostProcessedSeqs; - } - - /* Fallback to software matchfinder */ - { ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, - zc->appliedParams.useRowMatchFinder, - dictMode); - ms->ldmSeqStore = NULL; - DEBUGLOG( - 5, - "External sequence producer returned error code %lu. Falling back to internal parser.", - (unsigned long)nbExternalSeqs - ); - lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); - } } - } else { /* not long range mode and no external matchfinder */ - ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, - zc->appliedParams.useRowMatchFinder, - dictMode); - ms->ldmSeqStore = NULL; + } else { /* not long range mode */ + ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); } { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; @@ -3308,79 +2292,62 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) { const seqStore_t* seqStore = ZSTD_getSeqStore(zc); - const seqDef* seqStoreSeqs = seqStore->sequencesStart; - size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs; - size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart); - size_t literalsRead = 0; - size_t lastLLSize; + const seqDef* seqs = seqStore->sequencesStart; + size_t seqsSize = seqStore->sequences - seqs; ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex]; - size_t i; - repcodes_t updatedRepcodes; + size_t i; size_t position; int repIdx; assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences); - /* Ensure we have enough space for last literals "sequence" */ - assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1); - ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); - for (i = 0; i < seqStoreSeqSize; ++i) { - U32 rawOffset = seqStoreSeqs[i].offBase - ZSTD_REP_NUM; - outSeqs[i].litLength = seqStoreSeqs[i].litLength; - outSeqs[i].matchLength = seqStoreSeqs[i].mlBase + MINMATCH; - outSeqs[i].rep = 0; + for (i = 0, position = 0; i < seqsSize; ++i) { + outSeqs[i].offset = seqs[i].offset; + outSeqs[i].litLength = seqs[i].litLength; + outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH; if (i == seqStore->longLengthPos) { - if (seqStore->longLengthType == ZSTD_llt_literalLength) { + if (seqStore->longLengthID == 1) { outSeqs[i].litLength += 0x10000; - } else if (seqStore->longLengthType == ZSTD_llt_matchLength) { + } else if (seqStore->longLengthID == 2) { outSeqs[i].matchLength += 0x10000; } } - if (seqStoreSeqs[i].offBase <= ZSTD_REP_NUM) { - /* Derive the correct offset corresponding to a repcode */ - outSeqs[i].rep = seqStoreSeqs[i].offBase; - if (outSeqs[i].litLength != 0) { - rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1]; - } else { - if (outSeqs[i].rep == 3) { - rawOffset = updatedRepcodes.rep[0] - 1; + if (outSeqs[i].offset <= ZSTD_REP_NUM) { + outSeqs[i].rep = outSeqs[i].offset; + repIdx = (unsigned int)i - outSeqs[i].offset; + + if (outSeqs[i].litLength == 0) { + if (outSeqs[i].offset < 3) { + --repIdx; } else { - rawOffset = updatedRepcodes.rep[outSeqs[i].rep]; + repIdx = (unsigned int)i - 1; } + ++outSeqs[i].rep; + } + assert(repIdx >= -3); + outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1]; + if (outSeqs[i].rep == 4) { + --outSeqs[i].offset; } + } else { + outSeqs[i].offset -= ZSTD_REP_NUM; } - outSeqs[i].offset = rawOffset; - /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode - so we provide seqStoreSeqs[i].offset - 1 */ - ZSTD_updateRep(updatedRepcodes.rep, - seqStoreSeqs[i].offBase, - seqStoreSeqs[i].litLength == 0); - literalsRead += outSeqs[i].litLength; - } - /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0. - * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker - * for the block boundary, according to the API. - */ - assert(seqStoreLiteralsSize >= literalsRead); - lastLLSize = seqStoreLiteralsSize - literalsRead; - outSeqs[i].litLength = (U32)lastLLSize; - outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0; - seqStoreSeqSize++; - zc->seqCollector.seqIndex += seqStoreSeqSize; -} -size_t ZSTD_sequenceBound(size_t srcSize) { - return (srcSize / ZSTD_MINMATCH_MIN) + 1; + position += outSeqs[i].litLength; + outSeqs[i].matchPos = (unsigned int)position; + position += outSeqs[i].matchLength; + } + zc->seqCollector.seqIndex += seqsSize; } -size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, - size_t outSeqsSize, const void* src, size_t srcSize) +size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize) { const size_t dstCapacity = ZSTD_compressBound(srcSize); - void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem); + void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem); SeqCollector seqCollector; - RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!"); + RETURN_ERROR_IF(dst == NULL, memory_allocation); seqCollector.collectSequences = 1; seqCollector.seqStart = outSeqs; @@ -3389,997 +2356,108 @@ size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, zc->seqCollector = seqCollector; ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); - ZSTD_customFree(dst, ZSTD_defaultCMem); + ZSTD_free(dst, ZSTD_defaultCMem); return zc->seqCollector.seqIndex; } -size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) { - size_t in = 0; - size_t out = 0; - for (; in < seqsSize; ++in) { - if (sequences[in].offset == 0 && sequences[in].matchLength == 0) { - if (in != seqsSize - 1) { - sequences[in+1].litLength += sequences[in].litLength; - } - } else { - sequences[out] = sequences[in]; - ++out; - } - } - return out; -} - -/* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */ -static int ZSTD_isRLE(const BYTE* src, size_t length) { - const BYTE* ip = src; - const BYTE value = ip[0]; - const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL); - const size_t unrollSize = sizeof(size_t) * 4; - const size_t unrollMask = unrollSize - 1; - const size_t prefixLength = length & unrollMask; +/* Returns true if the given block is a RLE block */ +static int ZSTD_isRLE(const BYTE *ip, size_t length) { size_t i; - if (length == 1) return 1; - /* Check if prefix is RLE first before using unrolled loop */ - if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) { - return 0; + if (length < 2) return 1; + for (i = 1; i < length; ++i) { + if (ip[0] != ip[i]) return 0; } - for (i = prefixLength; i != length; i += unrollSize) { - size_t u; - for (u = 0; u < unrollSize; u += sizeof(size_t)) { - if (MEM_readST(ip + i + u) != valueST) { - return 0; - } } } return 1; } -/* Returns true if the given block may be RLE. - * This is just a heuristic based on the compressibility. - * It may return both false positives and false negatives. - */ -static int ZSTD_maybeRLE(seqStore_t const* seqStore) -{ - size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); - size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart); - - return nbSeqs < 4 && nbLits < 10; -} - -static void -ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs) +static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, U32 frame) { - ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock; - bs->prevCBlock = bs->nextCBlock; - bs->nextCBlock = tmp; -} + /* This the upper bound for the length of an rle block. + * This isn't the actual upper bound. Finding the real threshold + * needs further investigation. + */ + const U32 rleMaxLength = 25; + size_t cSize; + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, + (unsigned)zc->blockState.matchState.nextToUpdate); -/* Writes the block header */ -static void -writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) -{ - U32 const cBlockHeader = cSize == 1 ? - lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : - lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); - MEM_writeLE24(op, cBlockHeader); - DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock); -} + { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + FORWARD_IF_ERROR(bss); + if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } + } -/** ZSTD_buildBlockEntropyStats_literals() : - * Builds entropy for the literals. - * Stores literals block type (raw, rle, compressed, repeat) and - * huffman description table to hufMetadata. - * Requires ENTROPY_WORKSPACE_SIZE workspace - * @return : size of huffman description table, or an error code - */ -static size_t -ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize, - const ZSTD_hufCTables_t* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_hufCTablesMetadata_t* hufMetadata, - const int literalsCompressionIsDisabled, - void* workspace, size_t wkspSize, - int hufFlags) -{ - BYTE* const wkspStart = (BYTE*)workspace; - BYTE* const wkspEnd = wkspStart + wkspSize; - BYTE* const countWkspStart = wkspStart; - unsigned* const countWksp = (unsigned*)workspace; - const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); - BYTE* const nodeWksp = countWkspStart + countWkspSize; - const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); - unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; - unsigned huffLog = LitHufLog; - HUF_repeat repeat = prevHuf->repeatMode; - DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize); - - /* Prepare nextEntropy assuming reusing the existing table */ - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - - if (literalsCompressionIsDisabled) { - DEBUGLOG(5, "set_basic - disabled"); - hufMetadata->hType = set_basic; + if (zc->seqCollector.collectSequences) { + ZSTD_copyBlockSequences(zc); return 0; } - /* small ? don't even attempt compression (speed opt) */ -#ifndef COMPRESS_LITERALS_SIZE_MIN -# define COMPRESS_LITERALS_SIZE_MIN 63 /* heuristic */ -#endif - { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; - if (srcSize <= minLitSize) { - DEBUGLOG(5, "set_basic - too small"); - hufMetadata->hType = set_basic; - return 0; - } } - - /* Scan input and build symbol stats */ - { size_t const largest = - HIST_count_wksp (countWksp, &maxSymbolValue, - (const BYTE*)src, srcSize, - workspace, wkspSize); - FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); - if (largest == srcSize) { - /* only one literal symbol */ - DEBUGLOG(5, "set_rle"); - hufMetadata->hType = set_rle; - return 0; - } - if (largest <= (srcSize >> 7)+4) { - /* heuristic: likely not compressible */ - DEBUGLOG(5, "set_basic - no gain"); - hufMetadata->hType = set_basic; - return 0; - } } + /* encode sequences and literals */ + cSize = ZSTD_compressSequences(&zc->seqStore, + &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + dst, dstCapacity, + srcSize, + zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + zc->bmi2); - /* Validate the previous Huffman table */ - if (repeat == HUF_repeat_check - && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { - repeat = HUF_repeat_none; + if (frame && + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + !zc->isFirstBlock && + cSize < rleMaxLength && + ZSTD_isRLE(ip, srcSize)) + { + cSize = 1; + op[0] = ip[0]; } - /* Build Huffman Tree */ - ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); - huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, nodeWksp, nodeWkspSize, nextHuf->CTable, countWksp, hufFlags); - assert(huffLog <= LitHufLog); - { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, - maxSymbolValue, huffLog, - nodeWksp, nodeWkspSize); - FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); - huffLog = (U32)maxBits; - } - { /* Build and write the CTable */ - size_t const newCSize = HUF_estimateCompressedSize( - (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); - size_t const hSize = HUF_writeCTable_wksp( - hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), - (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog, - nodeWksp, nodeWkspSize); - /* Check against repeating the previous CTable */ - if (repeat != HUF_repeat_none) { - size_t const oldCSize = HUF_estimateCompressedSize( - (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); - if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { - DEBUGLOG(5, "set_repeat - smaller"); - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - hufMetadata->hType = set_repeat; - return 0; - } } - if (newCSize + hSize >= srcSize) { - DEBUGLOG(5, "set_basic - no gains"); - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - hufMetadata->hType = set_basic; - return 0; - } - DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); - hufMetadata->hType = set_compressed; - nextHuf->repeatMode = HUF_repeat_check; - return hSize; +out: + if (!ZSTD_isError(cSize) && cSize > 1) { + /* confirm repcodes and entropy tables when emitting a compressed block */ + ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; + zc->blockState.prevCBlock = zc->blockState.nextCBlock; + zc->blockState.nextCBlock = tmp; } + /* We check that dictionaries have offset codes available for the first + * block. After the first block, the offcode table might not have large + * enough codes to represent the offsets in the data. + */ + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + return cSize; } -/* ZSTD_buildDummySequencesStatistics(): - * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic, - * and updates nextEntropy to the appropriate repeatMode. - */ -static ZSTD_symbolEncodingTypeStats_t -ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) +static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, + ZSTD_cwksp* ws, + ZSTD_CCtx_params const* params, + void const* ip, + void const* iend) { - ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0, 0}; - nextEntropy->litlength_repeatMode = FSE_repeat_none; - nextEntropy->offcode_repeatMode = FSE_repeat_none; - nextEntropy->matchlength_repeatMode = FSE_repeat_none; - return stats; -} - -/** ZSTD_buildBlockEntropyStats_sequences() : - * Builds entropy for the sequences. - * Stores symbol compression modes and fse table to fseMetadata. - * Requires ENTROPY_WORKSPACE_SIZE wksp. - * @return : size of fse tables or error code */ -static size_t -ZSTD_buildBlockEntropyStats_sequences( - const seqStore_t* seqStorePtr, - const ZSTD_fseCTables_t* prevEntropy, - ZSTD_fseCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_fseCTablesMetadata_t* fseMetadata, - void* workspace, size_t wkspSize) -{ - ZSTD_strategy const strategy = cctxParams->cParams.strategy; - size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - BYTE* const ostart = fseMetadata->fseTablesBuffer; - BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); - BYTE* op = ostart; - unsigned* countWorkspace = (unsigned*)workspace; - unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1); - size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace); - ZSTD_symbolEncodingTypeStats_t stats; - - DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq); - stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, - prevEntropy, nextEntropy, op, oend, - strategy, countWorkspace, - entropyWorkspace, entropyWorkspaceSize) - : ZSTD_buildDummySequencesStatistics(nextEntropy); - FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); - fseMetadata->llType = (symbolEncodingType_e) stats.LLtype; - fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype; - fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype; - fseMetadata->lastCountSize = stats.lastCountSize; - return stats.size; -} - - -/** ZSTD_buildBlockEntropyStats() : - * Builds entropy for the block. - * Requires workspace size ENTROPY_WORKSPACE_SIZE - * @return : 0 on success, or an error code - * Note : also employed in superblock - */ -size_t ZSTD_buildBlockEntropyStats( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize) -{ - size_t const litSize = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); - int const huf_useOptDepth = (cctxParams->cParams.strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD); - int const hufFlags = huf_useOptDepth ? HUF_flags_optimalDepth : 0; - - entropyMetadata->hufMetadata.hufDesSize = - ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize, - &prevEntropy->huf, &nextEntropy->huf, - &entropyMetadata->hufMetadata, - ZSTD_literalsCompressionIsDisabled(cctxParams), - workspace, wkspSize, hufFlags); - - FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed"); - entropyMetadata->fseMetadata.fseTablesSize = - ZSTD_buildBlockEntropyStats_sequences(seqStorePtr, - &prevEntropy->fse, &nextEntropy->fse, - cctxParams, - &entropyMetadata->fseMetadata, - workspace, wkspSize); - FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed"); - return 0; -} - -/* Returns the size estimate for the literals section (header + content) of a block */ -static size_t -ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize, - const ZSTD_hufCTables_t* huf, - const ZSTD_hufCTablesMetadata_t* hufMetadata, - void* workspace, size_t wkspSize, - int writeEntropy) -{ - unsigned* const countWksp = (unsigned*)workspace; - unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; - size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB); - U32 singleStream = litSize < 256; - - if (hufMetadata->hType == set_basic) return litSize; - else if (hufMetadata->hType == set_rle) return 1; - else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { - size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); - if (ZSTD_isError(largest)) return litSize; - { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); - if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; - if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */ - return cLitSizeEstimate + literalSectionHeaderSize; - } } - assert(0); /* impossible */ - return 0; -} - -/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */ -static size_t -ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type, - const BYTE* codeTable, size_t nbSeq, unsigned maxCode, - const FSE_CTable* fseCTable, - const U8* additionalBits, - short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, - void* workspace, size_t wkspSize) -{ - unsigned* const countWksp = (unsigned*)workspace; - const BYTE* ctp = codeTable; - const BYTE* const ctStart = ctp; - const BYTE* const ctEnd = ctStart + nbSeq; - size_t cSymbolTypeSizeEstimateInBits = 0; - unsigned max = maxCode; - - HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ - if (type == set_basic) { - /* We selected this encoding type, so it must be valid. */ - assert(max <= defaultMax); - (void)defaultMax; - cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); - } else if (type == set_rle) { - cSymbolTypeSizeEstimateInBits = 0; - } else if (type == set_compressed || type == set_repeat) { - cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); - } - if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) { - return nbSeq * 10; - } - while (ctp < ctEnd) { - if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; - else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ - ctp++; - } - return cSymbolTypeSizeEstimateInBits >> 3; -} - -/* Returns the size estimate for the sequences section (header + content) of a block */ -static size_t -ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable, - const BYTE* llCodeTable, - const BYTE* mlCodeTable, - size_t nbSeq, - const ZSTD_fseCTables_t* fseTables, - const ZSTD_fseCTablesMetadata_t* fseMetadata, - void* workspace, size_t wkspSize, - int writeEntropy) -{ - size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ); - size_t cSeqSizeEstimate = 0; - cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff, - fseTables->offcodeCTable, NULL, - OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, - workspace, wkspSize); - cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL, - fseTables->litlengthCTable, LL_bits, - LL_defaultNorm, LL_defaultNormLog, MaxLL, - workspace, wkspSize); - cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML, - fseTables->matchlengthCTable, ML_bits, - ML_defaultNorm, ML_defaultNormLog, MaxML, - workspace, wkspSize); - if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; - return cSeqSizeEstimate + sequencesSectionHeaderSize; -} - -/* Returns the size estimate for a given stream of literals, of, ll, ml */ -static size_t -ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize, - const BYTE* ofCodeTable, - const BYTE* llCodeTable, - const BYTE* mlCodeTable, - size_t nbSeq, - const ZSTD_entropyCTables_t* entropy, - const ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize, - int writeLitEntropy, int writeSeqEntropy) -{ - size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize, - &entropy->huf, &entropyMetadata->hufMetadata, - workspace, wkspSize, writeLitEntropy); - size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, - nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, - workspace, wkspSize, writeSeqEntropy); - return seqSize + literalsSize + ZSTD_blockHeaderSize; -} - -/* Builds entropy statistics and uses them for blocksize estimation. - * - * @return: estimated compressed size of the seqStore, or a zstd error. - */ -static size_t -ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, ZSTD_CCtx* zc) -{ - ZSTD_entropyCTablesMetadata_t* const entropyMetadata = &zc->blockSplitCtx.entropyMetadata; - DEBUGLOG(6, "ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize()"); - FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore, - &zc->blockState.prevCBlock->entropy, - &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - entropyMetadata, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE), ""); - return ZSTD_estimateBlockSize( - seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart), - seqStore->ofCode, seqStore->llCode, seqStore->mlCode, - (size_t)(seqStore->sequences - seqStore->sequencesStart), - &zc->blockState.nextCBlock->entropy, - entropyMetadata, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE, - (int)(entropyMetadata->hufMetadata.hType == set_compressed), 1); -} - -/* Returns literals bytes represented in a seqStore */ -static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) -{ - size_t literalsBytes = 0; - size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); - size_t i; - for (i = 0; i < nbSeqs; ++i) { - seqDef const seq = seqStore->sequencesStart[i]; - literalsBytes += seq.litLength; - if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) { - literalsBytes += 0x10000; - } } - return literalsBytes; -} - -/* Returns match bytes represented in a seqStore */ -static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) -{ - size_t matchBytes = 0; - size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); - size_t i; - for (i = 0; i < nbSeqs; ++i) { - seqDef seq = seqStore->sequencesStart[i]; - matchBytes += seq.mlBase + MINMATCH; - if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) { - matchBytes += 0x10000; - } } - return matchBytes; -} - -/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx). - * Stores the result in resultSeqStore. - */ -static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore, - const seqStore_t* originalSeqStore, - size_t startIdx, size_t endIdx) -{ - *resultSeqStore = *originalSeqStore; - if (startIdx > 0) { - resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx; - resultSeqStore->litStart += ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); - } - - /* Move longLengthPos into the correct position if necessary */ - if (originalSeqStore->longLengthType != ZSTD_llt_none) { - if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) { - resultSeqStore->longLengthType = ZSTD_llt_none; - } else { - resultSeqStore->longLengthPos -= (U32)startIdx; - } - } - resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx; - resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx; - if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) { - /* This accounts for possible last literals if the derived chunk reaches the end of the block */ - assert(resultSeqStore->lit == originalSeqStore->lit); - } else { - size_t const literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); - resultSeqStore->lit = resultSeqStore->litStart + literalsBytes; - } - resultSeqStore->llCode += startIdx; - resultSeqStore->mlCode += startIdx; - resultSeqStore->ofCode += startIdx; -} - -/** - * Returns the raw offset represented by the combination of offBase, ll0, and repcode history. - * offBase must represent a repcode in the numeric representation of ZSTD_storeSeq(). - */ -static U32 -ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offBase, const U32 ll0) -{ - U32 const adjustedRepCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; /* [ 0 - 3 ] */ - assert(OFFBASE_IS_REPCODE(offBase)); - if (adjustedRepCode == ZSTD_REP_NUM) { - assert(ll0); - /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 - * This is only valid if it results in a valid offset value, aka > 0. - * Note : it may happen that `rep[0]==1` in exceptional circumstances. - * In which case this function will return 0, which is an invalid offset. - * It's not an issue though, since this value will be - * compared and discarded within ZSTD_seqStore_resolveOffCodes(). - */ - return rep[0] - 1; - } - return rep[adjustedRepCode]; -} - -/** - * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise - * due to emission of RLE/raw blocks that disturb the offset history, - * and replaces any repcodes within the seqStore that may be invalid. - * - * dRepcodes are updated as would be on the decompression side. - * cRepcodes are updated exactly in accordance with the seqStore. - * - * Note : this function assumes seq->offBase respects the following numbering scheme : - * 0 : invalid - * 1-3 : repcode 1-3 - * 4+ : real_offset+3 - */ -static void -ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes, - const seqStore_t* const seqStore, U32 const nbSeq) -{ - U32 idx = 0; - U32 const longLitLenIdx = seqStore->longLengthType == ZSTD_llt_literalLength ? seqStore->longLengthPos : nbSeq; - for (; idx < nbSeq; ++idx) { - seqDef* const seq = seqStore->sequencesStart + idx; - U32 const ll0 = (seq->litLength == 0) && (idx != longLitLenIdx); - U32 const offBase = seq->offBase; - assert(offBase > 0); - if (OFFBASE_IS_REPCODE(offBase)) { - U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offBase, ll0); - U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offBase, ll0); - /* Adjust simulated decompression repcode history if we come across a mismatch. Replace - * the repcode with the offset it actually references, determined by the compression - * repcode history. - */ - if (dRawOffset != cRawOffset) { - seq->offBase = OFFSET_TO_OFFBASE(cRawOffset); - } - } - /* Compression repcode history is always updated with values directly from the unmodified seqStore. - * Decompression repcode history may use modified seq->offset value taken from compression repcode history. - */ - ZSTD_updateRep(dRepcodes->rep, seq->offBase, ll0); - ZSTD_updateRep(cRepcodes->rep, offBase, ll0); - } -} - -/* ZSTD_compressSeqStore_singleBlock(): - * Compresses a seqStore into a block with a block header, into the buffer dst. - * - * Returns the total size of that block (including header) or a ZSTD error code. - */ -static size_t -ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, - const seqStore_t* const seqStore, - repcodes_t* const dRep, repcodes_t* const cRep, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - U32 lastBlock, U32 isPartition) -{ - const U32 rleMaxLength = 25; - BYTE* op = (BYTE*)dst; - const BYTE* ip = (const BYTE*)src; - size_t cSize; - size_t cSeqsSize; - - /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */ - repcodes_t const dRepOriginal = *dRep; - DEBUGLOG(5, "ZSTD_compressSeqStore_singleBlock"); - if (isPartition) - ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart)); - - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "Block header doesn't fit"); - cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore, - &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, - srcSize, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - zc->bmi2); - FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!"); - - if (!zc->isFirstBlock && - cSeqsSize < rleMaxLength && - ZSTD_isRLE((BYTE const*)src, srcSize)) { - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - cSeqsSize = 1; - } - - if (zc->seqCollector.collectSequences) { - ZSTD_copyBlockSequences(zc); - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - return 0; - } - - if (cSeqsSize == 0) { - cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock); - FORWARD_IF_ERROR(cSize, "Nocompress block failed"); - DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize); - *dRep = dRepOriginal; /* reset simulated decompression repcode history */ - } else if (cSeqsSize == 1) { - cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock); - FORWARD_IF_ERROR(cSize, "RLE compress block failed"); - DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize); - *dRep = dRepOriginal; /* reset simulated decompression repcode history */ - } else { - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - writeBlockHeader(op, cSeqsSize, srcSize, lastBlock); - cSize = ZSTD_blockHeaderSize + cSeqsSize; - DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize); - } - - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - return cSize; -} - -/* Struct to keep track of where we are in our recursive calls. */ -typedef struct { - U32* splitLocations; /* Array of split indices */ - size_t idx; /* The current index within splitLocations being worked on */ -} seqStoreSplits; - -#define MIN_SEQUENCES_BLOCK_SPLITTING 300 - -/* Helper function to perform the recursive search for block splits. - * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half. - * If advantageous to split, then we recurse down the two sub-blocks. - * If not, or if an error occurred in estimation, then we do not recurse. - * - * Note: The recursion depth is capped by a heuristic minimum number of sequences, - * defined by MIN_SEQUENCES_BLOCK_SPLITTING. - * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING). - * In practice, recursion depth usually doesn't go beyond 4. - * - * Furthermore, the number of splits is capped by ZSTD_MAX_NB_BLOCK_SPLITS. - * At ZSTD_MAX_NB_BLOCK_SPLITS == 196 with the current existing blockSize - * maximum of 128 KB, this value is actually impossible to reach. - */ -static void -ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx, - ZSTD_CCtx* zc, const seqStore_t* origSeqStore) -{ - seqStore_t* const fullSeqStoreChunk = &zc->blockSplitCtx.fullSeqStoreChunk; - seqStore_t* const firstHalfSeqStore = &zc->blockSplitCtx.firstHalfSeqStore; - seqStore_t* const secondHalfSeqStore = &zc->blockSplitCtx.secondHalfSeqStore; - size_t estimatedOriginalSize; - size_t estimatedFirstHalfSize; - size_t estimatedSecondHalfSize; - size_t midIdx = (startIdx + endIdx)/2; - - DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); - assert(endIdx >= startIdx); - if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= ZSTD_MAX_NB_BLOCK_SPLITS) { - DEBUGLOG(6, "ZSTD_deriveBlockSplitsHelper: Too few sequences (%zu)", endIdx - startIdx); - return; - } - ZSTD_deriveSeqStoreChunk(fullSeqStoreChunk, origSeqStore, startIdx, endIdx); - ZSTD_deriveSeqStoreChunk(firstHalfSeqStore, origSeqStore, startIdx, midIdx); - ZSTD_deriveSeqStoreChunk(secondHalfSeqStore, origSeqStore, midIdx, endIdx); - estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(fullSeqStoreChunk, zc); - estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(firstHalfSeqStore, zc); - estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(secondHalfSeqStore, zc); - DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu", - estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize); - if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) { - return; - } - if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) { - DEBUGLOG(5, "split decided at seqNb:%zu", midIdx); - ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore); - splits->splitLocations[splits->idx] = (U32)midIdx; - splits->idx++; - ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore); - } -} - -/* Base recursive function. - * Populates a table with intra-block partition indices that can improve compression ratio. - * - * @return: number of splits made (which equals the size of the partition table - 1). - */ -static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) -{ - seqStoreSplits splits; - splits.splitLocations = partitions; - splits.idx = 0; - if (nbSeq <= 4) { - DEBUGLOG(5, "ZSTD_deriveBlockSplits: Too few sequences to split (%u <= 4)", nbSeq); - /* Refuse to try and split anything with less than 4 sequences */ - return 0; - } - ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore); - splits.splitLocations[splits.idx] = nbSeq; - DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1); - return splits.idx; -} - -/* ZSTD_compressBlock_splitBlock(): - * Attempts to split a given block into multiple blocks to improve compression ratio. - * - * Returns combined size of all blocks (which includes headers), or a ZSTD error code. - */ -static size_t -ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t blockSize, - U32 lastBlock, U32 nbSeq) -{ - size_t cSize = 0; - const BYTE* ip = (const BYTE*)src; - BYTE* op = (BYTE*)dst; - size_t i = 0; - size_t srcBytesTotal = 0; - U32* const partitions = zc->blockSplitCtx.partitions; /* size == ZSTD_MAX_NB_BLOCK_SPLITS */ - seqStore_t* const nextSeqStore = &zc->blockSplitCtx.nextSeqStore; - seqStore_t* const currSeqStore = &zc->blockSplitCtx.currSeqStore; - size_t const numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq); - - /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history - * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two - * separate repcode histories that simulate repcode history on compression and decompression side, - * and use the histories to determine whether we must replace a particular repcode with its raw offset. - * - * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed - * or RLE. This allows us to retrieve the offset value that an invalid repcode references within - * a nocompress/RLE block. - * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use - * the replacement offset value rather than the original repcode to update the repcode history. - * dRep also will be the final repcode history sent to the next block. - * - * See ZSTD_seqStore_resolveOffCodes() for more details. - */ - repcodes_t dRep; - repcodes_t cRep; - ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); - ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); - ZSTD_memset(nextSeqStore, 0, sizeof(seqStore_t)); - - DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", - (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, - (unsigned)zc->blockState.matchState.nextToUpdate); - - if (numSplits == 0) { - size_t cSizeSingleBlock = - ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore, - &dRep, &cRep, - op, dstCapacity, - ip, blockSize, - lastBlock, 0 /* isPartition */); - FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!"); - DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits"); - assert(zc->blockSize <= ZSTD_BLOCKSIZE_MAX); - assert(cSizeSingleBlock <= zc->blockSize + ZSTD_blockHeaderSize); - return cSizeSingleBlock; - } - - ZSTD_deriveSeqStoreChunk(currSeqStore, &zc->seqStore, 0, partitions[0]); - for (i = 0; i <= numSplits; ++i) { - size_t cSizeChunk; - U32 const lastPartition = (i == numSplits); - U32 lastBlockEntireSrc = 0; - - size_t srcBytes = ZSTD_countSeqStoreLiteralsBytes(currSeqStore) + ZSTD_countSeqStoreMatchBytes(currSeqStore); - srcBytesTotal += srcBytes; - if (lastPartition) { - /* This is the final partition, need to account for possible last literals */ - srcBytes += blockSize - srcBytesTotal; - lastBlockEntireSrc = lastBlock; - } else { - ZSTD_deriveSeqStoreChunk(nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]); - } - - cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, currSeqStore, - &dRep, &cRep, - op, dstCapacity, - ip, srcBytes, - lastBlockEntireSrc, 1 /* isPartition */); - DEBUGLOG(5, "Estimated size: %zu vs %zu : actual size", - ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(currSeqStore, zc), cSizeChunk); - FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!"); - - ip += srcBytes; - op += cSizeChunk; - dstCapacity -= cSizeChunk; - cSize += cSizeChunk; - *currSeqStore = *nextSeqStore; - assert(cSizeChunk <= zc->blockSize + ZSTD_blockHeaderSize); - } - /* cRep and dRep may have diverged during the compression. - * If so, we use the dRep repcodes for the next block. - */ - ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t)); - return cSize; -} - -static size_t -ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, U32 lastBlock) -{ - U32 nbSeq; - size_t cSize; - DEBUGLOG(4, "ZSTD_compressBlock_splitBlock"); - assert(zc->appliedParams.useBlockSplitter == ZSTD_ps_enable); - - { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); - if (bss == ZSTDbss_noCompress) { - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - cSize = ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); - DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block"); - return cSize; - } - nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart); - } - - cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq); - FORWARD_IF_ERROR(cSize, "Splitting blocks failed!"); - return cSize; -} - -static size_t -ZSTD_compressBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, U32 frame) -{ - /* This is an estimated upper bound for the length of an rle block. - * This isn't the actual upper bound. - * Finding the real threshold needs further investigation. - */ - const U32 rleMaxLength = 25; - size_t cSize; - const BYTE* ip = (const BYTE*)src; - BYTE* op = (BYTE*)dst; - DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", - (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, - (unsigned)zc->blockState.matchState.nextToUpdate); - - { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); - if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } - } - - if (zc->seqCollector.collectSequences) { - ZSTD_copyBlockSequences(zc); - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - return 0; - } - - /* encode sequences and literals */ - cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore, - &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - dst, dstCapacity, - srcSize, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - zc->bmi2); - - if (frame && - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - !zc->isFirstBlock && - cSize < rleMaxLength && - ZSTD_isRLE(ip, srcSize)) - { - cSize = 1; - op[0] = ip[0]; - } - -out: - if (!ZSTD_isError(cSize) && cSize > 1) { - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - } - /* We check that dictionaries have offset codes available for the first - * block. After the first block, the offcode table might not have large - * enough codes to represent the offsets in the data. - */ - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - return cSize; -} - -static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const size_t bss, U32 lastBlock) -{ - DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()"); - if (bss == ZSTDbss_compress) { - if (/* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - !zc->isFirstBlock && - ZSTD_maybeRLE(&zc->seqStore) && - ZSTD_isRLE((BYTE const*)src, srcSize)) - { - return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock); - } - /* Attempt superblock compression. - * - * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the - * standard ZSTD_compressBound(). This is a problem, because even if we have - * space now, taking an extra byte now could cause us to run out of space later - * and violate ZSTD_compressBound(). - * - * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize. - * - * In order to respect ZSTD_compressBound() we must attempt to emit a raw - * uncompressed block in these cases: - * * cSize == 0: Return code for an uncompressed block. - * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize). - * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of - * output space. - * * cSize >= blockBound(srcSize): We have expanded the block too much so - * emit an uncompressed block. - */ - { size_t const cSize = - ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); - if (cSize != ERROR(dstSize_tooSmall)) { - size_t const maxCSize = - srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); - FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed"); - if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) { - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - return cSize; - } - } - } - } /* if (bss == ZSTDbss_compress)*/ - - DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()"); - /* Superblock compression failed, attempt to emit a single no compress block. - * The decoder will be able to stream this block since it is uncompressed. - */ - return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); -} - -static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - U32 lastBlock) -{ - size_t cSize = 0; - const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)", - (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize); - FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); - - cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed"); - - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - return cSize; -} - -static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, - ZSTD_cwksp* ws, - ZSTD_CCtx_params const* params, - void const* ip, - void const* iend) -{ - U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); - U32 const maxDist = (U32)1 << params->cParams.windowLog; - if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) { - U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); - ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); - ZSTD_cwksp_mark_tables_dirty(ws); - ZSTD_reduceIndex(ms, params, correction); - ZSTD_cwksp_mark_tables_clean(ws); - if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; - else ms->nextToUpdate -= correction; - /* invalidate dictionaries on overflow correction */ - ms->loadedDictEnd = 0; - ms->dictMatchState = NULL; - } + if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { + U32 const maxDist = (U32)1 << params->cParams.windowLog; + U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); + U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); + ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); + ZSTD_cwksp_mark_tables_dirty(ws); + ZSTD_reduceIndex(ms, params, correction); + ZSTD_cwksp_mark_tables_clean(ws); + if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; + else ms->nextToUpdate -= correction; + /* invalidate dictionaries on overflow correction */ + ms->loadedDictEnd = 0; + ms->dictMatchState = NULL; + } } /*! ZSTD_compress_frameChunk() : @@ -4387,9 +2465,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, * All blocks will be terminated, all input will be consumed. * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. * Frame is supposed already started (header already produced) -* @return : compressed size, or an error code +* @return : compressed size, or an error code */ -static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, +static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastFrameChunk) @@ -4400,10 +2478,9 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; - assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); - DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); + DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); if (cctx->appliedParams.fParams.checksumFlag && srcSize) XXH64_update(&cctx->xxhState, src, srcSize); @@ -4411,9 +2488,7 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, ZSTD_matchState_t* const ms = &cctx->blockState.matchState; U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); - /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding - * additional 1. We need to revisit and change this logic to be more consistent */ - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE + 1, + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, dstSize_tooSmall, "not enough space to store compressed block"); if (remaining < blockSize) blockSize = remaining; @@ -4421,39 +2496,24 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, ZSTD_overflowCorrectIfNeeded( ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); - ZSTD_window_enforceMaxDist(&ms->window, ip, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; - { size_t cSize; - if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) { - cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed"); - assert(cSize > 0); - assert(cSize <= blockSize + ZSTD_blockHeaderSize); - } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) { - cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed"); - assert(cSize > 0 || cctx->seqCollector.collectSequences == 1); + { size_t cSize = ZSTD_compressBlock_internal(cctx, + op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, + ip, blockSize, 1 /* frame */); + FORWARD_IF_ERROR(cSize); + if (cSize == 0) { /* block is not compressible */ + cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cSize); } else { - cSize = ZSTD_compressBlock_internal(cctx, - op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, - ip, blockSize, 1 /* frame */); - FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed"); - - if (cSize == 0) { /* block is not compressible */ - cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); - } else { - U32 const cBlockHeader = cSize == 1 ? - lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : - lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); - MEM_writeLE24(op, cBlockHeader); - cSize += ZSTD_blockHeaderSize; - } - } /* if (ZSTD_useTargetCBlockSize(&cctx->appliedParams))*/ - + const U32 cBlockHeader = cSize == 1 ? + lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : + lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); + MEM_writeLE24(op, cBlockHeader); + cSize += ZSTD_blockHeaderSize; + } ip += blockSize; assert(remaining >= blockSize); @@ -4486,10 +2546,10 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, size_t pos=0; assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); - RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall, - "dst buf is too small to fit worst-case frame header size."); + RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall); DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); + if (params->format == ZSTD_f_zstd1) { MEM_writeLE32(dst, ZSTD_MAGICNUMBER); pos = 4; @@ -4498,9 +2558,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, if (!singleSegment) op[pos++] = windowLogByte; switch(dictIDSizeCode) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : break; case 1 : op[pos] = (BYTE)(dictID); pos++; break; case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; @@ -4508,9 +2566,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, } switch(fcsCode) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; @@ -4519,26 +2575,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, return pos; } -/* ZSTD_writeSkippableFrame_advanced() : - * Writes out a skippable frame with the specified magic number variant (16 are supported), - * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data. - * - * Returns the total number of bytes written, or a ZSTD error code. - */ -size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, - const void* src, size_t srcSize, unsigned magicVariant) { - BYTE* op = (BYTE*)dst; - RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */, - dstSize_tooSmall, "Not enough room for skippable frame"); - RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame"); - RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported"); - - MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant)); - MEM_writeLE32(op+4, (U32)srcSize); - ZSTD_memcpy(op+8, src, srcSize); - return srcSize + ZSTD_SKIPPABLEHEADERSIZE; -} - /* ZSTD_writeLastEmptyBlock() : * output an empty Block with end-of-frame mark to complete a frame * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) @@ -4546,8 +2582,7 @@ size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, */ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) { - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, - "dst buf is too small to write frame trailer empty block."); + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall); { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ MEM_writeLE24(dst, cBlockHeader24); return ZSTD_blockHeaderSize; @@ -4556,16 +2591,13 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) { - RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong, - "wrong cctx stage"); - RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable, - parameter_unsupported, - "incompatible with ldm"); + RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong); + RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, + parameter_unsupported); cctx->externSeqStore.seq = seq; cctx->externSeqStore.size = nbSeq; cctx->externSeqStore.capacity = nbSeq; cctx->externSeqStore.pos = 0; - cctx->externSeqStore.posInSequence = 0; return 0; } @@ -4586,7 +2618,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (frame && (cctx->stage==ZSTDcs_init)) { fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, cctx->pledgedSrcSizePlusOne-1, cctx->dictID); - FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); + FORWARD_IF_ERROR(fhSize); assert(fhSize <= dstCapacity); dstCapacity -= fhSize; dst = (char*)dst + fhSize; @@ -4595,12 +2627,11 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (!srcSize) return fhSize; /* do not generate an empty block if no input */ - if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) { - ms->forceNonContiguous = 0; + if (!ZSTD_window_update(&ms->window, src, srcSize)) { ms->nextToUpdate = ms->window.dictLimit; } - if (cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0); + if (cctx->appliedParams.ldmParams.enableLdm) { + ZSTD_window_update(&cctx->ldmState.window, src, srcSize); } if (!frame) { @@ -4614,7 +2645,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, { size_t const cSize = frame ? ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */); - FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed"); + FORWARD_IF_ERROR(cSize); cctx->consumedSrcSize += srcSize; cctx->producedCSize += (cSize + fhSize); assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); @@ -4631,170 +2662,87 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, } } -size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); } -/* NOTE: Must just wrap ZSTD_compressContinue_public() */ -size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - return ZSTD_compressContinue_public(cctx, dst, dstCapacity, src, srcSize); -} -static size_t ZSTD_getBlockSize_deprecated(const ZSTD_CCtx* cctx) +size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; assert(!ZSTD_checkCParams(cParams)); - return MIN(cctx->appliedParams.maxBlockSize, (size_t)1 << cParams.windowLog); + return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); } -/* NOTE: Must just wrap ZSTD_getBlockSize_deprecated() */ -size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) -{ - return ZSTD_getBlockSize_deprecated(cctx); -} - -/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ -size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); - { size_t const blockSizeMax = ZSTD_getBlockSize_deprecated(cctx); - RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); } + { size_t const blockSizeMax = ZSTD_getBlockSize(cctx); + RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong); } return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); } -/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ -size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - return ZSTD_compressBlock_deprecated(cctx, dst, dstCapacity, src, srcSize); -} - /*! ZSTD_loadDictionaryContent() : * @return : 0, or an error code */ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, - ldmState_t* ls, ZSTD_cwksp* ws, ZSTD_CCtx_params const* params, const void* src, size_t srcSize, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp) + ZSTD_dictTableLoadMethod_e dtlm) { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; - int const loadLdmDict = params->ldmParams.enableLdm == ZSTD_ps_enable && ls != NULL; - - /* Assert that the ms params match the params we're being given */ - ZSTD_assertEqualCParams(params->cParams, ms->cParams); - - { /* Ensure large dictionaries can't cause index overflow */ - /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX. - * Dictionaries right at the edge will immediately trigger overflow - * correction, but I don't want to insert extra constraints here. - */ - U32 maxDictSize = ZSTD_CURRENT_MAX - ZSTD_WINDOW_START_INDEX; - - int const CDictTaggedIndices = ZSTD_CDictIndicesAreTagged(¶ms->cParams); - if (CDictTaggedIndices && tfp == ZSTD_tfp_forCDict) { - /* Some dictionary matchfinders in zstd use "short cache", - * which treats the lower ZSTD_SHORT_CACHE_TAG_BITS of each - * CDict hashtable entry as a tag rather than as part of an index. - * When short cache is used, we need to truncate the dictionary - * so that its indices don't overlap with the tag. */ - U32 const shortCacheMaxDictSize = (1u << (32 - ZSTD_SHORT_CACHE_TAG_BITS)) - ZSTD_WINDOW_START_INDEX; - maxDictSize = MIN(maxDictSize, shortCacheMaxDictSize); - assert(!loadLdmDict); - } - - /* If the dictionary is too large, only load the suffix of the dictionary. */ - if (srcSize > maxDictSize) { - ip = iend - maxDictSize; - src = ip; - srcSize = maxDictSize; - } - } - - if (srcSize > ZSTD_CHUNKSIZE_MAX) { - /* We must have cleared our windows when our source is this large. */ - assert(ZSTD_window_isEmpty(ms->window)); - if (loadLdmDict) assert(ZSTD_window_isEmpty(ls->window)); - } - ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0); + ZSTD_window_update(&ms->window, src, srcSize); + ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); - DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder); + /* Assert that we the ms params match the params we're being given */ + ZSTD_assertEqualCParams(params->cParams, ms->cParams); - if (loadLdmDict) { /* Load the entire dict into LDM matchfinders. */ - ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0); - ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); - ZSTD_ldm_fillHashTable(ls, ip, iend, ¶ms->ldmParams); - } + if (srcSize <= HASH_READ_SIZE) return 0; - /* If the dict is larger than we can reasonably index in our tables, only load the suffix. */ - if (params->cParams.strategy < ZSTD_btultra) { - U32 maxDictSize = 8U << MIN(MAX(params->cParams.hashLog, params->cParams.chainLog), 28); - if (srcSize > maxDictSize) { - ip = iend - maxDictSize; - src = ip; - srcSize = maxDictSize; - } - } + while (iend - ip > HASH_READ_SIZE) { + size_t const remaining = (size_t)(iend - ip); + size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); + const BYTE* const ichunk = ip + chunk; - ms->nextToUpdate = (U32)(ip - ms->window.base); - ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); - ms->forceNonContiguous = params->deterministicRefPrefix; + ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk); - if (srcSize <= HASH_READ_SIZE) return 0; + switch(params->cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(ms, ichunk, dtlm); + break; + case ZSTD_dfast: + ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); + break; - ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend); + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + if (chunk >= HASH_READ_SIZE) + ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); + break; - switch(params->cParams.strategy) - { - case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, dtlm, tfp); - break; - case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, iend, dtlm, tfp); - break; + case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + if (chunk >= HASH_READ_SIZE) + ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); + break; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - assert(srcSize >= HASH_READ_SIZE); - if (ms->dedicatedDictSearch) { - assert(ms->chainTable != NULL); - ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE); - } else { - assert(params->useRowMatchFinder != ZSTD_ps_auto); - if (params->useRowMatchFinder == ZSTD_ps_enable) { - size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog); - ZSTD_memset(ms->tagTable, 0, tagTableSize); - ZSTD_row_update(ms, iend-HASH_READ_SIZE); - DEBUGLOG(4, "Using row-based hash table for lazy dict"); - } else { - ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); - DEBUGLOG(4, "Using chain-based hash table for lazy dict"); - } + default: + assert(0); /* not possible : not a valid strategy id */ } - break; - case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - assert(srcSize >= HASH_READ_SIZE); - ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); - break; - - default: - assert(0); /* not possible : not a valid strategy id */ + ip = ichunk; } ms->nextToUpdate = (U32)(iend - ms->window.base); @@ -4803,91 +2751,102 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, /* Dictionaries that assign zero probability to symbols that show up causes problems - * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check - * and only dictionaries with 100% valid symbols can be assumed valid. - */ -static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) -{ + when FSE encoding. Refuse dictionaries that assign zero probability to symbols + that we may encounter during compression. + NOTE: This behavior is not standard and could be improved in the future. */ +static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { U32 s; - if (dictMaxSymbolValue < maxSymbolValue) { - return FSE_repeat_check; - } + RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted); for (s = 0; s <= maxSymbolValue; ++s) { - if (normalizedCounter[s] == 0) { - return FSE_repeat_check; - } + RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted); } - return FSE_repeat_valid; + return 0; } -size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, - const void* const dict, size_t dictSize) + +/* Dictionary format : + * See : + * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format + */ +/*! ZSTD_loadZstdDictionary() : + * @return : dictID, or an error code + * assumptions : magic number supposed already checked + * dictSize supposed >= 8 + */ +static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, + ZSTD_matchState_t* ms, + ZSTD_cwksp* ws, + ZSTD_CCtx_params const* params, + const void* dict, size_t dictSize, + ZSTD_dictTableLoadMethod_e dtlm, + void* workspace) { + const BYTE* dictPtr = (const BYTE*)dict; + const BYTE* const dictEnd = dictPtr + dictSize; short offcodeNCount[MaxOff+1]; unsigned offcodeMaxValue = MaxOff; - const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */ - const BYTE* const dictEnd = dictPtr + dictSize; - dictPtr += 8; - bs->entropy.huf.repeatMode = HUF_repeat_check; + size_t dictID; - { unsigned maxSymbolValue = 255; - unsigned hasZeroWeights = 1; - size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, - dictEnd-dictPtr, &hasZeroWeights); + ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= 8); + assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); - /* We only set the loaded table as valid if it contains all non-zero - * weights. Otherwise, we set it to check */ - if (!hasZeroWeights) - bs->entropy.huf.repeatMode = HUF_repeat_valid; + dictPtr += 4; /* skip magic number */ + dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); + dictPtr += 4; - RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, ""); + { unsigned maxSymbolValue = 255; + size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); + RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted); dictPtr += hufHeaderSize; } { unsigned offcodeLog; size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); + /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ /* fill all offset symbols to avoid garbage at end of table */ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE)), - dictionary_corrupted, ""); - /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ + dictionary_corrupted); dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); + /* Every match length code must have non-zero probability */ + FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE)), - dictionary_corrupted, ""); - bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML); + dictionary_corrupted); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); + /* Every literal length code must have non-zero probability */ + FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE)), - dictionary_corrupted, ""); - bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL); + dictionary_corrupted); dictPtr += litlengthHeaderSize; } - RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); bs->rep[0] = MEM_readLE32(dictPtr+0); bs->rep[1] = MEM_readLE32(dictPtr+4); bs->rep[2] = MEM_readLE32(dictPtr+8); @@ -4899,56 +2858,23 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ } - /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */ - bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)); - - /* All repCodes must be <= dictContentSize and != 0 */ + /* All offset values <= dictContentSize + 128 KB must be representable */ + FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); + /* All repCodes must be <= dictContentSize and != 0*/ { U32 u; for (u=0; u<3; u++) { - RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); - RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); - } } } - - return dictPtr - (const BYTE*)dict; -} - -/* Dictionary format : - * See : - * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format - */ -/*! ZSTD_loadZstdDictionary() : - * @return : dictID, or an error code - * assumptions : magic number supposed already checked - * dictSize supposed >= 8 - */ -static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, - ZSTD_matchState_t* ms, - ZSTD_cwksp* ws, - ZSTD_CCtx_params const* params, - const void* dict, size_t dictSize, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp, - void* workspace) -{ - const BYTE* dictPtr = (const BYTE*)dict; - const BYTE* const dictEnd = dictPtr + dictSize; - size_t dictID; - size_t eSize; - ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= 8); - assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); - - dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ ); - eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize); - FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed"); - dictPtr += eSize; + RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted); + RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted); + } } - { - size_t const dictContentSize = (size_t)(dictEnd - dictPtr); + bs->entropy.huf.repeatMode = HUF_repeat_valid; + bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; + bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; + bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( - ms, NULL, ws, params, dictPtr, dictContentSize, dtlm, tfp), ""); + ms, ws, params, dictPtr, dictContentSize, dtlm)); + return dictID; } - return dictID; } /** ZSTD_compress_insertDictionary() : @@ -4956,18 +2882,16 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, - ldmState_t* ls, ZSTD_cwksp* ws, const ZSTD_CCtx_params* params, const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp, void* workspace) { DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); if ((dict==NULL) || (dictSize<8)) { - RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); + RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); return 0; } @@ -4975,28 +2899,27 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, /* dict restricted modes */ if (dictContentType == ZSTD_dct_rawContent) - return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm, tfp); + return ZSTD_loadDictionaryContent(ms, ws, params, dict, dictSize, dtlm); if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { if (dictContentType == ZSTD_dct_auto) { DEBUGLOG(4, "raw content dictionary detected"); return ZSTD_loadDictionaryContent( - ms, ls, ws, params, dict, dictSize, dtlm, tfp); + ms, ws, params, dict, dictSize, dtlm); } - RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); + RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); assert(0); /* impossible */ } /* dict as full zstd dictionary */ return ZSTD_loadZstdDictionary( - bs, ms, ws, params, dict, dictSize, dtlm, tfp, workspace); + bs, ms, ws, params, dict, dictSize, dtlm, workspace); } #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) -#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL) +#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6) /*! ZSTD_compressBegin_internal() : - * Assumption : either @dict OR @cdict (or none) is non-NULL, never both * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, @@ -5006,10 +2929,6 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize; -#if ZSTD_TRACE - cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; -#endif DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); @@ -5024,23 +2943,20 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); } - FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, - dictContentSize, - ZSTDcrp_makeClean, zbuff) , ""); + FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize, + ZSTDcrp_makeClean, zbuff) ); { size_t const dictID = cdict ? ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, - &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent, - cdict->dictContentSize, cdict->dictContentType, dtlm, - ZSTD_tfp_forCCtx, cctx->entropyWorkspace) + &cctx->workspace, params, cdict->dictContent, cdict->dictContentSize, + dictContentType, dtlm, cctx->entropyWorkspace) : ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, - &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize, - dictContentType, dtlm, ZSTD_tfp_forCCtx, cctx->entropyWorkspace); - FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); + &cctx->workspace, params, dict, dictSize, + dictContentType, dtlm, cctx->entropyWorkspace); + FORWARD_IF_ERROR(dictID); assert(dictID <= UINT_MAX); cctx->dictID = (U32)dictID; - cctx->dictContentSize = dictContentSize; } return 0; } @@ -5055,7 +2971,7 @@ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, { DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog); /* compression parameters verification and optimization */ - FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , ""); + FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) ); return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictContentType, dtlm, cdict, @@ -5069,35 +2985,27 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams; - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); + ZSTD_CCtx_params const cctxParams = + ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL /*cdict*/, &cctxParams, pledgedSrcSize); } -static size_t -ZSTD_compressBegin_usingDict_deprecated(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) +size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_CCtx_params cctxParams; - { ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); - } + ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); + ZSTD_CCtx_params const cctxParams = + ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); } -size_t -ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) -{ - return ZSTD_compressBegin_usingDict_deprecated(cctx, dict, dictSize, compressionLevel); -} - size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) { - return ZSTD_compressBegin_usingDict_deprecated(cctx, NULL, 0, compressionLevel); + return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); } @@ -5116,7 +3024,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); - FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); + FORWARD_IF_ERROR(fhSize); dstCapacity -= fhSize; op += fhSize; cctx->stage = ZSTDcs_ongoing; @@ -5125,7 +3033,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) if (cctx->stage != ZSTDcs_ending) { /* write one last empty block, make it the "last" block */ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue"); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); MEM_writeLE32(op, cBlockHeader24); op += ZSTD_blockHeaderSize; dstCapacity -= ZSTD_blockHeaderSize; @@ -5133,7 +3041,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) if (cctx->appliedParams.fParams.checksumFlag) { U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); MEM_writeLE32(op, checksum); op += 4; @@ -5143,41 +3051,17 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) return op-ostart; } -void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize) -{ -#if ZSTD_TRACE - if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) { - int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0; - ZSTD_Trace trace; - ZSTD_memset(&trace, 0, sizeof(trace)); - trace.version = ZSTD_VERSION_NUMBER; - trace.streaming = streaming; - trace.dictionaryID = cctx->dictID; - trace.dictionarySize = cctx->dictContentSize; - trace.uncompressedSize = cctx->consumedSrcSize; - trace.compressedSize = cctx->producedCSize + extraCSize; - trace.params = &cctx->appliedParams; - trace.cctx = cctx; - ZSTD_trace_compress_end(cctx->traceCtx, &trace); - } - cctx->traceCtx = 0; -#else - (void)cctx; - (void)extraCSize; -#endif -} - -size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { size_t endResult; size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 1 /* last chunk */); - FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed"); + FORWARD_IF_ERROR(cSize); endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); - FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed"); + FORWARD_IF_ERROR(endResult); assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); @@ -5189,16 +3073,24 @@ size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize); } - ZSTD_CCtx_trace(cctx, endResult); return cSize + endResult; } -/* NOTE: Must just wrap ZSTD_compressEnd_public() */ -size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) + +static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params) { - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); + ZSTD_CCtx_params const cctxParams = + ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); + DEBUGLOG(4, "ZSTD_compress_internal"); + return ZSTD_compress_advanced_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + &cctxParams); } size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, @@ -5208,13 +3100,12 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, ZSTD_parameters params) { DEBUGLOG(4, "ZSTD_compress_advanced"); - FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); - ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, ZSTD_NO_CLEVEL); - return ZSTD_compress_advanced_internal(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - &cctx->simpleApiParams); + FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams)); + return ZSTD_compress_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + params); } /* Internal */ @@ -5228,8 +3119,8 @@ size_t ZSTD_compress_advanced_internal( DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, - params, srcSize, ZSTDb_not_buffered) , ""); - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); + params, srcSize, ZSTDb_not_buffered) ); + return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, @@ -5238,13 +3129,10 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - { - ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); - assert(params.fParams.contentSizeFlag == 1); - ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); - } - DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); - return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams); + ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); + ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); + assert(params.fParams.contentSizeFlag == 1); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams); } size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, @@ -5262,17 +3150,10 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, int compressionLevel) { size_t result; -#if ZSTD_COMPRESS_HEAPMODE - ZSTD_CCtx* cctx = ZSTD_createCCtx(); - RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed"); - result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); - ZSTD_freeCCtx(cctx); -#else ZSTD_CCtx ctxBody; ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ -#endif return result; } @@ -5288,17 +3169,14 @@ size_t ZSTD_estimateCDictSize_advanced( DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) - /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small - * in case we are using DDS with row-hash. */ - + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams), - /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0) + + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); } @@ -5316,22 +3194,20 @@ static size_t ZSTD_initCDict_internal( const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, - ZSTD_CCtx_params params) + ZSTD_compressionParameters cParams) { DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); - assert(!ZSTD_checkCParams(params.cParams)); - cdict->matchState.cParams = params.cParams; - cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; + assert(!ZSTD_checkCParams(cParams)); + cdict->matchState.cParams = cParams; if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { cdict->dictContent = dictBuffer; } else { void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); - RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!"); + RETURN_ERROR_IF(!internalBuffer, memory_allocation); cdict->dictContent = internalBuffer; - ZSTD_memcpy(internalBuffer, dictBuffer, dictSize); + memcpy(internalBuffer, dictBuffer, dictSize); } cdict->dictContentSize = dictSize; - cdict->dictContentType = dictContentType; cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); @@ -5341,21 +3217,23 @@ static size_t ZSTD_initCDict_internal( FORWARD_IF_ERROR(ZSTD_reset_matchState( &cdict->matchState, &cdict->workspace, - ¶ms.cParams, - params.useRowMatchFinder, + &cParams, ZSTDcrp_makeClean, ZSTDirp_reset, - ZSTD_resetTarget_CDict), ""); + ZSTD_resetTarget_CDict)); /* (Maybe) load the dictionary * Skips loading the dictionary if it is < 8 bytes. */ - { params.compressionLevel = ZSTD_CLEVEL_DEFAULT; + { ZSTD_CCtx_params params; + memset(¶ms, 0, sizeof(params)); + params.compressionLevel = ZSTD_CLEVEL_DEFAULT; params.fParams.contentSizeFlag = 1; + params.cParams = cParams; { size_t const dictID = ZSTD_compress_insertDictionary( - &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace, + &cdict->cBlockState, &cdict->matchState, &cdict->workspace, ¶ms, cdict->dictContent, cdict->dictContentSize, - dictContentType, ZSTD_dtlm_full, ZSTD_tfp_forCDict, cdict->entropyWorkspace); - FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); + dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace); + FORWARD_IF_ERROR(dictID); assert(dictID <= (size_t)(U32)-1); cdict->dictID = (U32)dictID; } @@ -5364,129 +3242,66 @@ static size_t ZSTD_initCDict_internal( return 0; } -static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize, +ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_compressionParameters cParams, - ZSTD_paramSwitch_e useRowMatchFinder, - U32 enableDedicatedDictSearch, - ZSTD_customMem customMem) + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; { size_t const workspaceSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + - ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) + + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); - void* const workspace = ZSTD_customMalloc(workspaceSize, customMem); + void* const workspace = ZSTD_malloc(workspaceSize, customMem); ZSTD_cwksp ws; ZSTD_CDict* cdict; if (!workspace) { - ZSTD_customFree(workspace, customMem); + ZSTD_free(workspace, customMem); return NULL; } - ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc); + ZSTD_cwksp_init(&ws, workspace, workspaceSize); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); assert(cdict != NULL); ZSTD_cwksp_move(&cdict->workspace, &ws); cdict->customMem = customMem; - cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ - cdict->useRowMatchFinder = useRowMatchFinder; - return cdict; - } -} - -ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams, - ZSTD_customMem customMem) -{ - ZSTD_CCtx_params cctxParams; - ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); - ZSTD_CCtxParams_init(&cctxParams, 0); - cctxParams.cParams = cParams; - cctxParams.customMem = customMem; - return ZSTD_createCDict_advanced2( - dictBuffer, dictSize, - dictLoadMethod, dictContentType, - &cctxParams, customMem); -} - -ZSTD_CDict* ZSTD_createCDict_advanced2( - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - const ZSTD_CCtx_params* originalCctxParams, - ZSTD_customMem customMem) -{ - ZSTD_CCtx_params cctxParams = *originalCctxParams; - ZSTD_compressionParameters cParams; - ZSTD_CDict* cdict; - - DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + cdict->compressionLevel = 0; /* signals advanced API usage */ - if (cctxParams.enableDedicatedDictSearch) { - cParams = ZSTD_dedicatedDictSearch_getCParams( - cctxParams.compressionLevel, dictSize); - ZSTD_overrideCParams(&cParams, &cctxParams.cParams); - } else { - cParams = ZSTD_getCParamsFromCCtxParams( - &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - } - - if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { - /* Fall back to non-DDSS params */ - cctxParams.enableDedicatedDictSearch = 0; - cParams = ZSTD_getCParamsFromCCtxParams( - &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - } - - DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch); - cctxParams.cParams = cParams; - cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); - - cdict = ZSTD_createCDict_advanced_internal(dictSize, - dictLoadMethod, cctxParams.cParams, - cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch, - customMem); + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, + dictBuffer, dictSize, + dictLoadMethod, dictContentType, + cParams) )) { + ZSTD_freeCDict(cdict); + return NULL; + } - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, - dict, dictSize, - dictLoadMethod, dictContentType, - cctxParams) )) { - ZSTD_freeCDict(cdict); - return NULL; + return cdict; } - - return cdict; } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); + ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, cParams, ZSTD_defaultCMem); if (cdict) - cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel; return cdict; } ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); + return ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem); - if (cdict) - cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; - return cdict; } size_t ZSTD_freeCDict(ZSTD_CDict* cdict) @@ -5496,7 +3311,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); ZSTD_cwksp_free(&cdict->workspace, cMem); if (!cdictInWorkspace) { - ZSTD_customFree(cdict, cMem); + ZSTD_free(cdict, cMem); } return 0; } @@ -5522,22 +3337,19 @@ const ZSTD_CDict* ZSTD_initStaticCDict( ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams) { - ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams); - /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */ - size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0); + size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + matchStateSize; ZSTD_CDict* cdict; - ZSTD_CCtx_params params; if ((size_t)workspace & 7) return NULL; /* 8-aligned */ { ZSTD_cwksp ws; - ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); + ZSTD_cwksp_init(&ws, workspace, workspaceSize); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); if (cdict == NULL) return NULL; ZSTD_cwksp_move(&cdict->workspace, &ws); @@ -5547,16 +3359,10 @@ const ZSTD_CDict* ZSTD_initStaticCDict( (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); if (workspaceSize < neededSize) return NULL; - ZSTD_CCtxParams_init(¶ms, 0); - params.cParams = cParams; - params.useRowMatchFinder = useRowMatchFinder; - cdict->useRowMatchFinder = useRowMatchFinder; - cdict->compressionLevel = ZSTD_NO_CLEVEL; - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, dictLoadMethod, dictContentType, - params) )) + cParams) )) return NULL; return cdict; @@ -5568,101 +3374,59 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) return cdict->matchState.cParams; } -/*! ZSTD_getDictID_fromCDict() : - * Provides the dictID of the dictionary loaded into `cdict`. - * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. - * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ -unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) -{ - if (cdict==NULL) return 0; - return cdict->dictID; -} - -/* ZSTD_compressBegin_usingCDict_internal() : - * Implementation of various ZSTD_compressBegin_usingCDict* functions. - */ -static size_t ZSTD_compressBegin_usingCDict_internal( +/* ZSTD_compressBegin_usingCDict_advanced() : + * cdict must be != NULL */ +size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { - ZSTD_CCtx_params cctxParams; - DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal"); - RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); - /* Initialize the cctxParams from the cdict */ - { - ZSTD_parameters params; - params.fParams = fParams; + DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); + RETURN_ERROR_IF(cdict==NULL, dictionary_wrong); + { ZSTD_CCtx_params params = cctx->requestedParams; params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0 ) ? + || cdict->compressionLevel == 0 ) + && (params.attachDictPref != ZSTD_dictForceLoad) ? ZSTD_getCParamsFromCDict(cdict) : ZSTD_getCParams(cdict->compressionLevel, pledgedSrcSize, cdict->dictContentSize); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); - } - /* Increase window log to fit the entire dictionary and source if the - * source size is known. Limit the increase to 19, which is the - * window log for compression level 1 with the largest source size. - */ - if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); - U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; - cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); + /* Increase window log to fit the entire dictionary and source if the + * source size is known. Limit the increase to 19, which is the + * window log for compression level 1 with the largest source size. + */ + if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { + U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); + U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; + params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); + } + params.fParams = fParams; + return ZSTD_compressBegin_internal(cctx, + NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, + cdict, + ¶ms, pledgedSrcSize, + ZSTDb_not_buffered); } - return ZSTD_compressBegin_internal(cctx, - NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, - cdict, - &cctxParams, pledgedSrcSize, - ZSTDb_not_buffered); -} - - -/* ZSTD_compressBegin_usingCDict_advanced() : - * This function is DEPRECATED. - * cdict must be != NULL */ -size_t ZSTD_compressBegin_usingCDict_advanced( - ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, - ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) -{ - return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize); } /* ZSTD_compressBegin_usingCDict() : - * cdict must be != NULL */ -size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) -{ - ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); -} - + * pledgedSrcSize=0 means "unknown" + * if pledgedSrcSize>0, it will enable contentSizeFlag */ size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { - return ZSTD_compressBegin_usingCDict_deprecated(cctx, cdict); -} - -/*! ZSTD_compress_usingCDict_internal(): - * Implementation of various ZSTD_compress_usingCDict* functions. - */ -static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) -{ - FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); + ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; + DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); + return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); } -/*! ZSTD_compress_usingCDict_advanced(): - * This function is DEPRECATED. - */ size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) { - return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ + return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } /*! ZSTD_compress_usingCDict() : @@ -5676,7 +3440,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); } @@ -5717,12 +3481,32 @@ size_t ZSTD_CStreamOutSize(void) return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize) +static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, + const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, + const ZSTD_CDict* const cdict, + ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) { - if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) - return ZSTD_cpm_attachDict; - else - return ZSTD_cpm_noAttachDict; + DEBUGLOG(4, "ZSTD_resetCStream_internal"); + /* Finalize the compression parameters */ + params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); + /* params are supposed to be fully validated at this point */ + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + + FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, + dict, dictSize, dictContentType, ZSTD_dtlm_fast, + cdict, + ¶ms, pledgedSrcSize, + ZSTDb_buffered) ); + + cctx->inToCompress = 0; + cctx->inBuffPos = 0; + cctx->inBuffTarget = cctx->blockSize + + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */ + cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; + cctx->streamStage = zcss_load; + cctx->frameEnded = 0; + return 0; /* ready to go */ } /* ZSTD_resetCStream(): @@ -5735,8 +3519,8 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) */ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); return 0; } @@ -5750,16 +3534,16 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_initCStream_internal"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); zcs->requestedParams = *params; assert(!((dict) && (cdict))); /* either dict or cdict, not both */ if (dict) { - FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); } else { /* Dictionary is cleared if !cdict */ - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); } return 0; } @@ -5772,10 +3556,10 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); zcs->requestedParams.fParams = fParams; - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); return 0; } @@ -5783,8 +3567,8 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) { DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); return 0; } @@ -5803,20 +3587,20 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, */ U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; DEBUGLOG(4, "ZSTD_initCStream_advanced"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); - FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); - ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, ¶ms); - FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); + FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); + zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, params); + FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); return 0; } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { DEBUGLOG(4, "ZSTD_initCStream_usingDict"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); + FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); return 0; } @@ -5828,19 +3612,19 @@ size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigne */ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; DEBUGLOG(4, "ZSTD_initCStream_srcSize"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); return 0; } size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) { DEBUGLOG(4, "ZSTD_initCStream"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); - FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); + FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); return 0; } @@ -5848,54 +3632,44 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) { - if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { - return cctx->blockSize - cctx->stableIn_notConsumed; - } - assert(cctx->appliedParams.inBufferMode == ZSTD_bm_buffered); - { size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; - if (hintInSize==0) hintInSize = cctx->blockSize; - return hintInSize; - } + size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; + if (hintInSize==0) hintInSize = cctx->blockSize; + return hintInSize; +} + +static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + size_t const length = MIN(dstCapacity, srcSize); + if (length) memcpy(dst, src, length); + return length; } /** ZSTD_compressStream_generic(): * internal function for all *compressStream*() variants - * @return : hint size for next input to complete ongoing block */ + * non-static, because can be called from zstdmt_compress.c + * @return : hint size for next input */ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input, ZSTD_EndDirective const flushMode) { - const char* const istart = (assert(input != NULL), (const char*)input->src); - const char* const iend = (istart != NULL) ? istart + input->size : istart; - const char* ip = (istart != NULL) ? istart + input->pos : istart; - char* const ostart = (assert(output != NULL), (char*)output->dst); - char* const oend = (ostart != NULL) ? ostart + output->size : ostart; - char* op = (ostart != NULL) ? ostart + output->pos : ostart; + const char* const istart = (const char*)input->src; + const char* const iend = istart + input->size; + const char* ip = istart + input->pos; + char* const ostart = (char*)output->dst; + char* const oend = ostart + output->size; + char* op = ostart + output->pos; U32 someMoreWork = 1; /* check expectations */ - DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%i, srcSize = %zu", (int)flushMode, input->size - input->pos); - assert(zcs != NULL); - if (zcs->appliedParams.inBufferMode == ZSTD_bm_stable) { - assert(input->pos >= zcs->stableIn_notConsumed); - input->pos -= zcs->stableIn_notConsumed; - ip -= zcs->stableIn_notConsumed; - zcs->stableIn_notConsumed = 0; - } - if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { - assert(zcs->inBuff != NULL); - assert(zcs->inBuffSize > 0); - } - if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) { - assert(zcs->outBuff != NULL); - assert(zcs->outBuffSize > 0); - } - if (input->src == NULL) assert(input->size == 0); - assert(input->pos <= input->size); - if (output->dst == NULL) assert(output->size == 0); + DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); + assert(zcs->inBuff != NULL); + assert(zcs->inBuffSize > 0); + assert(zcs->outBuff != NULL); + assert(zcs->outBuffSize > 0); assert(output->pos <= output->size); - assert((U32)flushMode <= (U32)ZSTD_e_end); + assert(input->pos <= input->size); while (someMoreWork) { switch(zcs->streamStage) @@ -5905,28 +3679,26 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, case zcss_load: if ( (flushMode == ZSTD_e_end) - && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */ - || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */ + && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ && (zcs->inBuffPos == 0) ) { /* shortcut to compression pass directly into output buffer */ - size_t const cSize = ZSTD_compressEnd_public(zcs, + size_t const cSize = ZSTD_compressEnd(zcs, op, oend-op, ip, iend-ip); DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); - FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed"); + FORWARD_IF_ERROR(cSize); ip = iend; op += cSize; zcs->frameEnded = 1; ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); someMoreWork = 0; break; } - /* complete loading into inBuffer in buffered mode */ - if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { - size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; + /* complete loading into inBuffer */ + { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; size_t const loaded = ZSTD_limitCopy( zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip); zcs->inBuffPos += loaded; - if (ip) ip += loaded; + ip += loaded; if ( (flushMode == ZSTD_e_continue) && (zcs->inBuffPos < zcs->inBuffTarget) ) { /* not enough input to fill full block : stop here */ @@ -5937,62 +3709,34 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, /* empty */ someMoreWork = 0; break; } - } else { - assert(zcs->appliedParams.inBufferMode == ZSTD_bm_stable); - if ( (flushMode == ZSTD_e_continue) - && ( (size_t)(iend - ip) < zcs->blockSize) ) { - /* can't compress a full block : stop here */ - zcs->stableIn_notConsumed = (size_t)(iend - ip); - ip = iend; /* pretend to have consumed input */ - someMoreWork = 0; break; - } - if ( (flushMode == ZSTD_e_flush) - && (ip == iend) ) { - /* empty */ - someMoreWork = 0; break; - } } /* compress current block (note : this stage cannot be stopped in the middle) */ DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); - { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered); - void* cDst; + { void* cDst; size_t cSize; + size_t const iSize = zcs->inBuffPos - zcs->inToCompress; size_t oSize = oend-op; - size_t const iSize = inputBuffered ? zcs->inBuffPos - zcs->inToCompress - : MIN((size_t)(iend - ip), zcs->blockSize); - if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); + if (oSize >= ZSTD_compressBound(iSize)) cDst = op; /* compress into output buffer, to skip flush stage */ else cDst = zcs->outBuff, oSize = zcs->outBuffSize; - if (inputBuffered) { - unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); - cSize = lastBlock ? - ZSTD_compressEnd_public(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize) : - ZSTD_compressContinue_public(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize); - FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); - zcs->frameEnded = lastBlock; - /* prepare next block */ - zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; - if (zcs->inBuffTarget > zcs->inBuffSize) - zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; - DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", - (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); - if (!lastBlock) - assert(zcs->inBuffTarget <= zcs->inBuffSize); - zcs->inToCompress = zcs->inBuffPos; - } else { /* !inputBuffered, hence ZSTD_bm_stable */ - unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip + iSize == iend); - cSize = lastBlock ? - ZSTD_compressEnd_public(zcs, cDst, oSize, ip, iSize) : - ZSTD_compressContinue_public(zcs, cDst, oSize, ip, iSize); - /* Consume the input prior to error checking to mirror buffered mode. */ - if (ip) ip += iSize; - FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); - zcs->frameEnded = lastBlock; - if (lastBlock) assert(ip == iend); - } + cSize = lastBlock ? + ZSTD_compressEnd(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize) : + ZSTD_compressContinue(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize); + FORWARD_IF_ERROR(cSize); + zcs->frameEnded = lastBlock; + /* prepare next block */ + zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; + if (zcs->inBuffTarget > zcs->inBuffSize) + zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; + DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", + (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); + if (!lastBlock) + assert(zcs->inBuffTarget <= zcs->inBuffSize); + zcs->inToCompress = zcs->inBuffPos; if (cDst == op) { /* no need to flush */ op += cSize; if (zcs->frameEnded) { @@ -6006,17 +3750,15 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, zcs->outBuffFlushedSize = 0; zcs->streamStage = zcss_flush; /* pass-through to flush stage */ } - ZSTD_FALLTHROUGH; + /* fall-through */ case zcss_flush: DEBUGLOG(5, "flush stage"); - assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered); { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), zcs->outBuff + zcs->outBuffFlushedSize, toFlush); DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); - if (flushed) - op += flushed; + op += flushed; zcs->outBuffFlushedSize += flushed; if (toFlush!=flushed) { /* flush not fully completed, presumably because dst is too small */ @@ -6060,145 +3802,11 @@ static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) { - FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , ""); + FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) ); return ZSTD_nextInputSizeHint_MTorST(zcs); } -/* After a compression call set the expected input/output buffer. - * This is validated at the start of the next compression call. - */ -static void -ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, const ZSTD_outBuffer* output, const ZSTD_inBuffer* input) -{ - DEBUGLOG(5, "ZSTD_setBufferExpectations (for advanced stable in/out modes)"); - if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { - cctx->expectedInBuffer = *input; - } - if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { - cctx->expectedOutBufferSize = output->size - output->pos; - } -} - -/* Validate that the input/output buffers match the expectations set by - * ZSTD_setBufferExpectations. - */ -static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx, - ZSTD_outBuffer const* output, - ZSTD_inBuffer const* input, - ZSTD_EndDirective endOp) -{ - if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { - ZSTD_inBuffer const expect = cctx->expectedInBuffer; - if (expect.src != input->src || expect.pos != input->pos) - RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableInBuffer enabled but input differs!"); - } - (void)endOp; - if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { - size_t const outBufferSize = output->size - output->pos; - if (cctx->expectedOutBufferSize != outBufferSize) - RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableOutBuffer enabled but output size differs!"); - } - return 0; -} - -static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, - ZSTD_EndDirective endOp, - size_t inSize) -{ - ZSTD_CCtx_params params = cctx->requestedParams; - ZSTD_prefixDict const prefixDict = cctx->prefixDict; - FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ - ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ - assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ - if (cctx->cdict && !cctx->localDict.cdict) { - /* Let the cdict's compression level take priority over the requested params. - * But do not take the cdict's compression level if the "cdict" is actually a localDict - * generated from ZSTD_initLocalDict(). - */ - params.compressionLevel = cctx->cdict->compressionLevel; - } - DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); - if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-determine pledgedSrcSize */ - - { size_t const dictSize = prefixDict.dict - ? prefixDict.dictSize - : (cctx->cdict ? cctx->cdict->dictContentSize : 0); - ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); - params.cParams = ZSTD_getCParamsFromCCtxParams( - ¶ms, cctx->pledgedSrcSizePlusOne-1, - dictSize, mode); - } - - params.useBlockSplitter = ZSTD_resolveBlockSplitterMode(params.useBlockSplitter, ¶ms.cParams); - params.ldmParams.enableLdm = ZSTD_resolveEnableLdm(params.ldmParams.enableLdm, ¶ms.cParams); - params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, ¶ms.cParams); - params.validateSequences = ZSTD_resolveExternalSequenceValidation(params.validateSequences); - params.maxBlockSize = ZSTD_resolveMaxBlockSize(params.maxBlockSize); - params.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(params.searchForExternalRepcodes, params.compressionLevel); - -#ifdef ZSTD_MULTITHREAD - /* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */ - RETURN_ERROR_IF( - params.useSequenceProducer == 1 && params.nbWorkers >= 1, - parameter_combination_unsupported, - "External sequence producer isn't supported with nbWorkers >= 1" - ); - - if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { - params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ - } - if (params.nbWorkers > 0) { -#if ZSTD_TRACE - cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; -#endif - /* mt context creation */ - if (cctx->mtctx == NULL) { - DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", - params.nbWorkers); - cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool); - RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); - } - /* mt compression */ - DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); - FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( - cctx->mtctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, - cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); - cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0; - cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize; - cctx->consumedSrcSize = 0; - cctx->producedCSize = 0; - cctx->streamStage = zcss_load; - cctx->appliedParams = params; - } else -#endif /* ZSTD_MULTITHREAD */ - { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, - cctx->cdict, - ¶ms, pledgedSrcSize, - ZSTDb_buffered) , ""); - assert(cctx->appliedParams.nbWorkers == 0); - cctx->inToCompress = 0; - cctx->inBuffPos = 0; - if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) { - /* for small input: avoid automatic flush on reaching end of block, since - * it would require to add a 3-bytes null block to end frame - */ - cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize); - } else { - cctx->inBuffTarget = 0; - } - cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; - cctx->streamStage = zcss_load; - cctx->frameEnded = 0; - } - return 0; -} -/* @return provides a minimum amount of data remaining to be flushed from internal buffers - */ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, @@ -6206,95 +3814,82 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, { DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); /* check conditions */ - RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer"); - RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer"); - RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective"); - assert(cctx != NULL); + RETURN_ERROR_IF(output->pos > output->size, GENERIC); + RETURN_ERROR_IF(input->pos > input->size, GENERIC); + assert(cctx!=NULL); /* transparent initialization stage */ if (cctx->streamStage == zcss_init) { - size_t const inputSize = input->size - input->pos; /* no obligation to start from pos==0 */ - size_t const totalInputSize = inputSize + cctx->stableIn_notConsumed; - if ( (cctx->requestedParams.inBufferMode == ZSTD_bm_stable) /* input is presumed stable, across invocations */ - && (endOp == ZSTD_e_continue) /* no flush requested, more input to come */ - && (totalInputSize < ZSTD_BLOCKSIZE_MAX) ) { /* not even reached one block yet */ - if (cctx->stableIn_notConsumed) { /* not the first time */ - /* check stable source guarantees */ - RETURN_ERROR_IF(input->src != cctx->expectedInBuffer.src, stabilityCondition_notRespected, "stableInBuffer condition not respected: wrong src pointer"); - RETURN_ERROR_IF(input->pos != cctx->expectedInBuffer.size, stabilityCondition_notRespected, "stableInBuffer condition not respected: externally modified pos"); - } - /* pretend input was consumed, to give a sense forward progress */ - input->pos = input->size; - /* save stable inBuffer, for later control, and flush/end */ - cctx->expectedInBuffer = *input; - /* but actually input wasn't consumed, so keep track of position from where compression shall resume */ - cctx->stableIn_notConsumed += inputSize; - /* don't initialize yet, wait for the first block of flush() order, for better parameters adaptation */ - return ZSTD_FRAMEHEADERSIZE_MIN(cctx->requestedParams.format); /* at least some header to produce */ + ZSTD_CCtx_params params = cctx->requestedParams; + ZSTD_prefixDict const prefixDict = cctx->prefixDict; + FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) ); /* Init the local dict if present. */ + memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ + assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ + DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); + if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ + params.cParams = ZSTD_getCParamsFromCCtxParams( + &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); + + +#ifdef ZSTD_MULTITHREAD + if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { + params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ } - FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, totalInputSize), "compressStream2 initialization failed"); - ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */ - } + if (params.nbWorkers > 0) { + /* mt context creation */ + if (cctx->mtctx == NULL) { + DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", + params.nbWorkers); + cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem); + RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation); + } + /* mt compression */ + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); + FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( + cctx->mtctx, + prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, + cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + cctx->streamStage = zcss_load; + cctx->appliedParams.nbWorkers = params.nbWorkers; + } else +#endif + { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, + cctx->cdict, + params, cctx->pledgedSrcSizePlusOne-1) ); + assert(cctx->streamStage == zcss_load); + assert(cctx->appliedParams.nbWorkers == 0); + } } /* end of transparent initialization stage */ - FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers"); /* compression stage */ #ifdef ZSTD_MULTITHREAD if (cctx->appliedParams.nbWorkers > 0) { + int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); size_t flushMin; + assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); if (cctx->cParamsChanged) { ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); cctx->cParamsChanged = 0; } - if (cctx->stableIn_notConsumed) { - assert(cctx->appliedParams.inBufferMode == ZSTD_bm_stable); - /* some early data was skipped - make it available for consumption */ - assert(input->pos >= cctx->stableIn_notConsumed); - input->pos -= cctx->stableIn_notConsumed; - cctx->stableIn_notConsumed = 0; - } - for (;;) { - size_t const ipos = input->pos; - size_t const opos = output->pos; + do { flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); - cctx->consumedSrcSize += (U64)(input->pos - ipos); - cctx->producedCSize += (U64)(output->pos - opos); if ( ZSTD_isError(flushMin) || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ - if (flushMin == 0) - ZSTD_CCtx_trace(cctx, 0); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); } - FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed"); - - if (endOp == ZSTD_e_continue) { - /* We only require some progress with ZSTD_e_continue, not maximal progress. - * We're done if we've consumed or produced any bytes, or either buffer is - * full. - */ - if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size) - break; - } else { - assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end); - /* We require maximal progress. We're done when the flush is complete or the - * output buffer is full. - */ - if (flushMin == 0 || output->pos == output->size) - break; - } - } + FORWARD_IF_ERROR(flushMin); + } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); /* Either we don't require maximum forward progress, we've finished the * flush, or we are out of output space. */ - assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size); - ZSTD_setBufferExpectations(cctx, output, input); + assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); return flushMin; } -#endif /* ZSTD_MULTITHREAD */ - FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); +#endif + FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) ); DEBUGLOG(5, "completed ZSTD_compressStream2"); - ZSTD_setBufferExpectations(cctx, output, input); return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ } @@ -6304,559 +3899,52 @@ size_t ZSTD_compressStream2_simpleArgs ( const void* src, size_t srcSize, size_t* srcPos, ZSTD_EndDirective endOp) { - ZSTD_outBuffer output; - ZSTD_inBuffer input; - output.dst = dst; - output.size = dstCapacity; - output.pos = *dstPos; - input.src = src; - input.size = srcSize; - input.pos = *srcPos; + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ - { size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); - *dstPos = output.pos; - *srcPos = input.pos; - return cErr; - } + size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; } size_t ZSTD_compress2(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode; - ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode; - DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); - /* Enable stable input/output buffers. */ - cctx->requestedParams.inBufferMode = ZSTD_bm_stable; - cctx->requestedParams.outBufferMode = ZSTD_bm_stable; { size_t oPos = 0; size_t iPos = 0; size_t const result = ZSTD_compressStream2_simpleArgs(cctx, dst, dstCapacity, &oPos, src, srcSize, &iPos, ZSTD_e_end); - /* Reset to the original values. */ - cctx->requestedParams.inBufferMode = originalInBufferMode; - cctx->requestedParams.outBufferMode = originalOutBufferMode; - - FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed"); + FORWARD_IF_ERROR(result); if (result != 0) { /* compression not completed, due to lack of output space */ assert(oPos == dstCapacity); - RETURN_ERROR(dstSize_tooSmall, ""); + RETURN_ERROR(dstSize_tooSmall); } assert(iPos == srcSize); /* all input is expected consumed */ return oPos; } } -/* ZSTD_validateSequence() : - * @offCode : is presumed to follow format required by ZSTD_storeSeq() - * @returns a ZSTD error code if sequence is not valid - */ -static size_t -ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch, - size_t posInSrc, U32 windowLog, size_t dictSize, int useSequenceProducer) -{ - U32 const windowSize = 1u << windowLog; - /* posInSrc represents the amount of data the decoder would decode up to this point. - * As long as the amount of data decoded is less than or equal to window size, offsets may be - * larger than the total length of output decoded in order to reference the dict, even larger than - * window size. After output surpasses windowSize, we're limited to windowSize offsets again. - */ - size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; - size_t const matchLenLowerBound = (minMatch == 3 || useSequenceProducer) ? 3 : 4; - RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!"); - /* Validate maxNbSeq is large enough for the given matchLength and minMatch */ - RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch"); - return 0; -} - -/* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */ -static U32 ZSTD_finalizeOffBase(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) -{ - U32 offBase = OFFSET_TO_OFFBASE(rawOffset); - - if (!ll0 && rawOffset == rep[0]) { - offBase = REPCODE1_TO_OFFBASE; - } else if (rawOffset == rep[1]) { - offBase = REPCODE_TO_OFFBASE(2 - ll0); - } else if (rawOffset == rep[2]) { - offBase = REPCODE_TO_OFFBASE(3 - ll0); - } else if (ll0 && rawOffset == rep[0] - 1) { - offBase = REPCODE3_TO_OFFBASE; - } - return offBase; -} - -size_t -ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, - ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, - ZSTD_paramSwitch_e externalRepSearch) -{ - U32 idx = seqPos->idx; - U32 const startIdx = idx; - BYTE const* ip = (BYTE const*)(src); - const BYTE* const iend = ip + blockSize; - repcodes_t updatedRepcodes; - U32 dictSize; - - DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreExplicitBlockDelim (blockSize = %zu)", blockSize); - - if (cctx->cdict) { - dictSize = (U32)cctx->cdict->dictContentSize; - } else if (cctx->prefixDict.dict) { - dictSize = (U32)cctx->prefixDict.dictSize; - } else { - dictSize = 0; - } - ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); - for (; idx < inSeqsSize && (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0); ++idx) { - U32 const litLength = inSeqs[idx].litLength; - U32 const matchLength = inSeqs[idx].matchLength; - U32 offBase; - - if (externalRepSearch == ZSTD_ps_disable) { - offBase = OFFSET_TO_OFFBASE(inSeqs[idx].offset); - } else { - U32 const ll0 = (litLength == 0); - offBase = ZSTD_finalizeOffBase(inSeqs[idx].offset, updatedRepcodes.rep, ll0); - ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); - } - - DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); - if (cctx->appliedParams.validateSequences) { - seqPos->posInSrc += litLength + matchLength; - FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useSequenceProducer), - "Sequence validation failed"); - } - RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, - "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); - ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); - ip += matchLength + litLength; - } - - /* If we skipped repcode search while parsing, we need to update repcodes now */ - assert(externalRepSearch != ZSTD_ps_auto); - assert(idx >= startIdx); - if (externalRepSearch == ZSTD_ps_disable && idx != startIdx) { - U32* const rep = updatedRepcodes.rep; - U32 lastSeqIdx = idx - 1; /* index of last non-block-delimiter sequence */ - - if (lastSeqIdx >= startIdx + 2) { - rep[2] = inSeqs[lastSeqIdx - 2].offset; - rep[1] = inSeqs[lastSeqIdx - 1].offset; - rep[0] = inSeqs[lastSeqIdx].offset; - } else if (lastSeqIdx == startIdx + 1) { - rep[2] = rep[0]; - rep[1] = inSeqs[lastSeqIdx - 1].offset; - rep[0] = inSeqs[lastSeqIdx].offset; - } else { - assert(lastSeqIdx == startIdx); - rep[2] = rep[1]; - rep[1] = rep[0]; - rep[0] = inSeqs[lastSeqIdx].offset; - } - } - - ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); - - if (inSeqs[idx].litLength) { - DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength); - ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength); - ip += inSeqs[idx].litLength; - seqPos->posInSrc += inSeqs[idx].litLength; - } - RETURN_ERROR_IF(ip != iend, externalSequences_invalid, "Blocksize doesn't agree with block delimiter!"); - seqPos->idx = idx+1; - return 0; -} - -size_t -ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch) -{ - U32 idx = seqPos->idx; - U32 startPosInSequence = seqPos->posInSequence; - U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize; - size_t dictSize; - BYTE const* ip = (BYTE const*)(src); - BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */ - repcodes_t updatedRepcodes; - U32 bytesAdjustment = 0; - U32 finalMatchSplit = 0; - - /* TODO(embg) support fast parsing mode in noBlockDelim mode */ - (void)externalRepSearch; - - if (cctx->cdict) { - dictSize = cctx->cdict->dictContentSize; - } else if (cctx->prefixDict.dict) { - dictSize = cctx->prefixDict.dictSize; - } else { - dictSize = 0; - } - DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreNoBlockDelim: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); - DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); - ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); - while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { - const ZSTD_Sequence currSeq = inSeqs[idx]; - U32 litLength = currSeq.litLength; - U32 matchLength = currSeq.matchLength; - U32 const rawOffset = currSeq.offset; - U32 offBase; - - /* Modify the sequence depending on where endPosInSequence lies */ - if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) { - if (startPosInSequence >= litLength) { - startPosInSequence -= litLength; - litLength = 0; - matchLength -= startPosInSequence; - } else { - litLength -= startPosInSequence; - } - /* Move to the next sequence */ - endPosInSequence -= currSeq.litLength + currSeq.matchLength; - startPosInSequence = 0; - } else { - /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence - does not reach the end of the match. So, we have to split the sequence */ - DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u", - currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence); - if (endPosInSequence > litLength) { - U32 firstHalfMatchLength; - litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence; - firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength; - if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) { - /* Only ever split the match if it is larger than the block size */ - U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence; - if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) { - /* Move the endPosInSequence backward so that it creates match of minMatch length */ - endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; - bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; - firstHalfMatchLength -= bytesAdjustment; - } - matchLength = firstHalfMatchLength; - /* Flag that we split the last match - after storing the sequence, exit the loop, - but keep the value of endPosInSequence */ - finalMatchSplit = 1; - } else { - /* Move the position in sequence backwards so that we don't split match, and break to store - * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence - * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so - * would cause the first half of the match to be too small - */ - bytesAdjustment = endPosInSequence - currSeq.litLength; - endPosInSequence = currSeq.litLength; - break; - } - } else { - /* This sequence ends inside the literals, break to store the last literals */ - break; - } - } - /* Check if this offset can be represented with a repcode */ - { U32 const ll0 = (litLength == 0); - offBase = ZSTD_finalizeOffBase(rawOffset, updatedRepcodes.rep, ll0); - ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); - } - - if (cctx->appliedParams.validateSequences) { - seqPos->posInSrc += litLength + matchLength; - FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useSequenceProducer), - "Sequence validation failed"); - } - DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); - RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, - "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); - ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); - ip += matchLength + litLength; - if (!finalMatchSplit) - idx++; /* Next Sequence */ - } - DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); - assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength); - seqPos->idx = idx; - seqPos->posInSequence = endPosInSequence; - ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); - - iend -= bytesAdjustment; - if (ip != iend) { - /* Store any last literals */ - U32 lastLLSize = (U32)(iend - ip); - assert(ip <= iend); - DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize); - ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize); - seqPos->posInSrc += lastLLSize; - } - - return bytesAdjustment; -} - -typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); -static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) -{ - ZSTD_sequenceCopier sequenceCopier = NULL; - assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode)); - if (mode == ZSTD_sf_explicitBlockDelimiters) { - return ZSTD_copySequencesToSeqStoreExplicitBlockDelim; - } else if (mode == ZSTD_sf_noBlockDelimiters) { - return ZSTD_copySequencesToSeqStoreNoBlockDelim; - } - assert(sequenceCopier != NULL); - return sequenceCopier; -} - -/* Discover the size of next block by searching for the delimiter. - * Note that a block delimiter **must** exist in this mode, - * otherwise it's an input error. - * The block size retrieved will be later compared to ensure it remains within bounds */ -static size_t -blockSize_explicitDelimiter(const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) -{ - int end = 0; - size_t blockSize = 0; - size_t spos = seqPos.idx; - DEBUGLOG(6, "blockSize_explicitDelimiter : seq %zu / %zu", spos, inSeqsSize); - assert(spos <= inSeqsSize); - while (spos < inSeqsSize) { - end = (inSeqs[spos].offset == 0); - blockSize += inSeqs[spos].litLength + inSeqs[spos].matchLength; - if (end) { - if (inSeqs[spos].matchLength != 0) - RETURN_ERROR(externalSequences_invalid, "delimiter format error : both matchlength and offset must be == 0"); - break; - } - spos++; - } - if (!end) - RETURN_ERROR(externalSequences_invalid, "Reached end of sequences without finding a block delimiter"); - return blockSize; -} - -/* More a "target" block size */ -static size_t blockSize_noDelimiter(size_t blockSize, size_t remaining) -{ - int const lastBlock = (remaining <= blockSize); - return lastBlock ? remaining : blockSize; -} - -static size_t determine_blockSize(ZSTD_sequenceFormat_e mode, - size_t blockSize, size_t remaining, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) -{ - DEBUGLOG(6, "determine_blockSize : remainingSize = %zu", remaining); - if (mode == ZSTD_sf_noBlockDelimiters) - return blockSize_noDelimiter(blockSize, remaining); - { size_t const explicitBlockSize = blockSize_explicitDelimiter(inSeqs, inSeqsSize, seqPos); - FORWARD_IF_ERROR(explicitBlockSize, "Error while determining block size with explicit delimiters"); - if (explicitBlockSize > blockSize) - RETURN_ERROR(externalSequences_invalid, "sequences incorrectly define a too large block"); - if (explicitBlockSize > remaining) - RETURN_ERROR(externalSequences_invalid, "sequences define a frame longer than source"); - return explicitBlockSize; - } -} - -/* Compress, block-by-block, all of the sequences given. - * - * Returns the cumulative size of all compressed blocks (including their headers), - * otherwise a ZSTD error. - */ -static size_t -ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, - const void* src, size_t srcSize) -{ - size_t cSize = 0; - size_t remaining = srcSize; - ZSTD_sequencePosition seqPos = {0, 0, 0}; - - BYTE const* ip = (BYTE const*)src; - BYTE* op = (BYTE*)dst; - ZSTD_sequenceCopier const sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters); - - DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize); - /* Special case: empty frame */ - if (remaining == 0) { - U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1); - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header"); - MEM_writeLE32(op, cBlockHeader24); - op += ZSTD_blockHeaderSize; - dstCapacity -= ZSTD_blockHeaderSize; - cSize += ZSTD_blockHeaderSize; - } - - while (remaining) { - size_t compressedSeqsSize; - size_t cBlockSize; - size_t additionalByteAdjustment; - size_t blockSize = determine_blockSize(cctx->appliedParams.blockDelimiters, - cctx->blockSize, remaining, - inSeqs, inSeqsSize, seqPos); - U32 const lastBlock = (blockSize == remaining); - FORWARD_IF_ERROR(blockSize, "Error while trying to determine block size"); - assert(blockSize <= remaining); - ZSTD_resetSeqStore(&cctx->seqStore); - DEBUGLOG(5, "Working on new block. Blocksize: %zu (total:%zu)", blockSize, (ip - (const BYTE*)src) + blockSize); - - additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize, cctx->appliedParams.searchForExternalRepcodes); - FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy"); - blockSize -= additionalByteAdjustment; - - /* If blocks are too small, emit as a nocompress block */ - /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding - * additional 1. We need to revisit and change this logic to be more consistent */ - if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { - cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); - DEBUGLOG(5, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize); - cSize += cBlockSize; - ip += blockSize; - op += cBlockSize; - remaining -= blockSize; - dstCapacity -= cBlockSize; - continue; - } - - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "not enough dstCapacity to write a new compressed block"); - compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore, - &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, - &cctx->appliedParams, - op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, - blockSize, - cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - cctx->bmi2); - FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); - DEBUGLOG(5, "Compressed sequences size: %zu", compressedSeqsSize); - - if (!cctx->isFirstBlock && - ZSTD_maybeRLE(&cctx->seqStore) && - ZSTD_isRLE(ip, blockSize)) { - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - compressedSeqsSize = 1; - } - - if (compressedSeqsSize == 0) { - /* ZSTD_noCompressBlock writes the block header as well */ - cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cBlockSize, "ZSTD_noCompressBlock failed"); - DEBUGLOG(5, "Writing out nocompress block, size: %zu", cBlockSize); - } else if (compressedSeqsSize == 1) { - cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cBlockSize, "ZSTD_rleCompressBlock failed"); - DEBUGLOG(5, "Writing out RLE block, size: %zu", cBlockSize); - } else { - U32 cBlockHeader; - /* Error checking and repcodes update */ - ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState); - if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - /* Write block header into beginning of block*/ - cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3); - MEM_writeLE24(op, cBlockHeader); - cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize; - DEBUGLOG(5, "Writing out compressed block, size: %zu", cBlockSize); - } - - cSize += cBlockSize; - - if (lastBlock) { - break; - } else { - ip += blockSize; - op += cBlockSize; - remaining -= blockSize; - dstCapacity -= cBlockSize; - cctx->isFirstBlock = 0; - } - DEBUGLOG(5, "cSize running total: %zu (remaining dstCapacity=%zu)", cSize, dstCapacity); - } - - DEBUGLOG(4, "cSize final total: %zu", cSize); - return cSize; -} - -size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, - const void* src, size_t srcSize) -{ - BYTE* op = (BYTE*)dst; - size_t cSize = 0; - size_t compressedBlocksSize = 0; - size_t frameHeaderSize = 0; - - /* Transparent initialization stage, same as compressStream2() */ - DEBUGLOG(4, "ZSTD_compressSequences (dstCapacity=%zu)", dstCapacity); - assert(cctx != NULL); - FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed"); - /* Begin writing output, starting with frame header */ - frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID); - op += frameHeaderSize; - dstCapacity -= frameHeaderSize; - cSize += frameHeaderSize; - if (cctx->appliedParams.fParams.checksumFlag && srcSize) { - XXH64_update(&cctx->xxhState, src, srcSize); - } - /* cSize includes block header size and compressed sequences size */ - compressedBlocksSize = ZSTD_compressSequences_internal(cctx, - op, dstCapacity, - inSeqs, inSeqsSize, - src, srcSize); - FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!"); - cSize += compressedBlocksSize; - dstCapacity -= compressedBlocksSize; - - if (cctx->appliedParams.fParams.checksumFlag) { - U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); - DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum); - MEM_writeLE32((char*)dst + cSize, checksum); - cSize += 4; - } - - DEBUGLOG(4, "Final compressed size: %zu", cSize); - return cSize; -} - /*====== Finalize ======*/ -static ZSTD_inBuffer inBuffer_forEndFlush(const ZSTD_CStream* zcs) -{ - const ZSTD_inBuffer nullInput = { NULL, 0, 0 }; - const int stableInput = (zcs->appliedParams.inBufferMode == ZSTD_bm_stable); - return stableInput ? zcs->expectedInBuffer : nullInput; -} - /*! ZSTD_flushStream() : * @return : amount of data remaining to flush */ size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); - input.size = input.pos; /* do not ingest more input during flush */ + ZSTD_inBuffer input = { NULL, 0, 0 }; return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); } size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); + ZSTD_inBuffer input = { NULL, 0, 0 }; size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); - FORWARD_IF_ERROR(remainingToFlush , "ZSTD_compressStream2(,,ZSTD_e_end) failed"); + FORWARD_IF_ERROR( remainingToFlush ); if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ /* single thread mode : attempt to calculate remaining to flush more precisely */ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; @@ -6869,167 +3957,147 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) /*-===== Pre-defined compression levels =====-*/ -#include "clevels.h" +#define ZSTD_MAX_CLEVEL 22 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } -int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; } - -static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) -{ - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); - switch (cParams.strategy) { - case ZSTD_fast: - case ZSTD_dfast: - break; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; - break; - case ZSTD_btlazy2: - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - break; - } - return cParams; -} - -static int ZSTD_dedicatedDictSearch_isSupported( - ZSTD_compressionParameters const* cParams) -{ - return (cParams->strategy >= ZSTD_greedy) - && (cParams->strategy <= ZSTD_lazy2) - && (cParams->hashLog > cParams->chainLog) - && (cParams->chainLog <= 24); -} - -/** - * Reverses the adjustment applied to cparams when enabling dedicated dict - * search. This is used to recover the params set to be used in the working - * context. (Otherwise, those tables would also grow.) - */ -static void ZSTD_dedicatedDictSearch_revertCParams( - ZSTD_compressionParameters* cParams) { - switch (cParams->strategy) { - case ZSTD_fast: - case ZSTD_dfast: - break; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG; - if (cParams->hashLog < ZSTD_HASHLOG_MIN) { - cParams->hashLog = ZSTD_HASHLOG_MIN; - } - break; - case ZSTD_btlazy2: - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - break; - } -} -static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) -{ - switch (mode) { - case ZSTD_cpm_unknown: - case ZSTD_cpm_noAttachDict: - case ZSTD_cpm_createCDict: - break; - case ZSTD_cpm_attachDict: - dictSize = 0; - break; - default: - assert(0); - break; - } - { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; - size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; - return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; - } -} +static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { +{ /* "default" - for any srcSize > 256 KB */ + /* W, C, H, S, L, TL, strat */ + { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ + { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ + { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ + { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ + { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ + { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ + { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ + { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ + { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ + { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ + { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ + { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ + { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ + { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ + { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ + { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ + { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ + { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ + { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ + { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ + { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ + { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ + { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ +}, +{ /* for srcSize <= 256 KB */ + /* W, C, H, S, L, T, strat */ + { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ + { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ + { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ + { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ + { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ + { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ + { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ + { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ + { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 128 KB */ + /* W, C, H, S, L, T, strat */ + { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ + { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ + { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ + { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ + { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ + { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ + { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ + { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ + { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ + { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 16 KB */ + /* W, C, H, S, L, T, strat */ + { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ + { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ + { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ + { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ + { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ + { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ + { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ + { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ + { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ + { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ + { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ + { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ + { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ + { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ + { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ + { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +}; -/*! ZSTD_getCParams_internal() : +/*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. - * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. - * Use dictSize == 0 for unknown or unused. - * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */ -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) + * Size values are optional, provide 0 if not known or unused */ +ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { - U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); + size_t const addedSize = srcSizeHint ? 0 : 500; + U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : ZSTD_CONTENTSIZE_UNKNOWN; /* intentional overflow for srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN */ U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); - int row; - DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); - - /* row */ + int row = compressionLevel; + DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ - else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ - else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; - else row = compressionLevel; - + if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ + if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; - DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy); - /* acceleration factor */ - if (compressionLevel < 0) { - int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); - cp.targetLength = (unsigned)(-clampedCompressionLevel); - } - /* refine parameters based on srcSize & dictSize */ - return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode, ZSTD_ps_auto); + if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ + return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); /* refine parameters based on srcSize & dictSize */ } } -/*! ZSTD_getCParams() : - * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. - * Size values are optional, provide 0 if not known or unused */ -ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) -{ - if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); -} - /*! ZSTD_getParams() : * same idea as ZSTD_getCParams() * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). * Fields of `ZSTD_frameParameters` are set to default values */ -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { +ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { ZSTD_parameters params; - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); - ZSTD_memset(¶ms, 0, sizeof(params)); + memset(¶ms, 0, sizeof(params)); params.cParams = cParams; params.fParams.contentSizeFlag = 1; return params; } - -/*! ZSTD_getParams() : - * same idea as ZSTD_getCParams() - * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). - * Fields of `ZSTD_frameParameters` are set to default values */ -ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { - if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); -} - -void ZSTD_registerSequenceProducer( - ZSTD_CCtx* zc, void* mState, - ZSTD_sequenceProducer_F* mFinder -) { - if (mFinder != NULL) { - ZSTD_externalMatchCtx emctx; - emctx.mState = mState; - emctx.mFinder = mFinder; - emctx.seqBuffer = NULL; - emctx.seqBufferCapacity = 0; - zc->externalMatchCtx = emctx; - zc->requestedParams.useSequenceProducer = 1; - } else { - ZSTD_memset(&zc->externalMatchCtx, 0, sizeof(zc->externalMatchCtx)); - zc->requestedParams.useSequenceProducer = 0; - } -} - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_internal.h b/vendor/github.com/DataDog/zstd/zstd_compress_internal.h index c3746035..14036f87 100644 --- a/vendor/github.com/DataDog/zstd/zstd_compress_internal.h +++ b/vendor/github.com/DataDog/zstd/zstd_compress_internal.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -24,12 +23,12 @@ #ifdef ZSTD_MULTITHREAD # include "zstdmt_compress.h" #endif -#include "bits.h" /* ZSTD_highbit32, ZSTD_NbCommonBytes */ #if defined (__cplusplus) extern "C" { #endif + /*-************************************* * Constants ***************************************/ @@ -65,7 +64,7 @@ typedef struct { } ZSTD_localDict; typedef struct { - HUF_CElt CTable[HUF_CTABLE_SIZE_ST(255)]; + U32 CTable[HUF_CTABLE_SIZE_U32(255)]; HUF_repeat repeatMode; } ZSTD_hufCTables_t; @@ -83,82 +82,11 @@ typedef struct { ZSTD_fseCTables_t fse; } ZSTD_entropyCTables_t; -/*********************************************** -* Entropy buffer statistics structs and funcs * -***********************************************/ -/** ZSTD_hufCTablesMetadata_t : - * Stores Literals Block Type for a super-block in hType, and - * huffman tree description in hufDesBuffer. - * hufDesSize refers to the size of huffman tree description in bytes. - * This metadata is populated in ZSTD_buildBlockEntropyStats_literals() */ -typedef struct { - symbolEncodingType_e hType; - BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE]; - size_t hufDesSize; -} ZSTD_hufCTablesMetadata_t; - -/** ZSTD_fseCTablesMetadata_t : - * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and - * fse tables in fseTablesBuffer. - * fseTablesSize refers to the size of fse tables in bytes. - * This metadata is populated in ZSTD_buildBlockEntropyStats_sequences() */ -typedef struct { - symbolEncodingType_e llType; - symbolEncodingType_e ofType; - symbolEncodingType_e mlType; - BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE]; - size_t fseTablesSize; - size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ -} ZSTD_fseCTablesMetadata_t; - -typedef struct { - ZSTD_hufCTablesMetadata_t hufMetadata; - ZSTD_fseCTablesMetadata_t fseMetadata; -} ZSTD_entropyCTablesMetadata_t; - -/** ZSTD_buildBlockEntropyStats() : - * Builds entropy for the block. - * @return : 0 on success or error code */ -size_t ZSTD_buildBlockEntropyStats( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize); - -/********************************* -* Compression internals structs * -*********************************/ - typedef struct { - U32 off; /* Offset sumtype code for the match, using ZSTD_storeSeq() format */ - U32 len; /* Raw length of match */ + U32 off; + U32 len; } ZSTD_match_t; -typedef struct { - U32 offset; /* Offset of sequence */ - U32 litLength; /* Length of literals prior to match */ - U32 matchLength; /* Raw length of match */ -} rawSeq; - -typedef struct { - rawSeq* seq; /* The start of the sequences */ - size_t pos; /* The index in seq where reading stopped. pos <= size. */ - size_t posInSequence; /* The position within the sequence at seq[pos] where reading - stopped. posInSequence <= seq[pos].litLength + seq[pos].matchLength */ - size_t size; /* The number of sequences. <= capacity. */ - size_t capacity; /* The capacity starting from `seq` pointer */ -} rawSeqStore_t; - -typedef struct { - U32 idx; /* Index in array of ZSTD_Sequence */ - U32 posInSequence; /* Position within sequence at idx */ - size_t posInSrc; /* Number of bytes given by sequences provided so far */ -} ZSTD_sequencePosition; - -UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0}; - typedef struct { int price; U32 off; @@ -188,7 +116,7 @@ typedef struct { U32 offCodeSumBasePrice; /* to compare to log2(offreq) */ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */ - ZSTD_paramSwitch_e literalCompressionMode; + ZSTD_literalCompressionMode_e literalCompressionMode; } optState_t; typedef struct { @@ -197,23 +125,14 @@ typedef struct { } ZSTD_compressedBlockState_t; typedef struct { - BYTE const* nextSrc; /* next block here to continue on current prefix */ - BYTE const* base; /* All regular indexes relative to this position */ - BYTE const* dictBase; /* extDict indexes relative to this position */ - U32 dictLimit; /* below that point, need extDict */ - U32 lowLimit; /* below that point, no more valid data */ - U32 nbOverflowCorrections; /* Number of times overflow correction has run since - * ZSTD_window_init(). Useful for debugging coredumps - * and for ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY. - */ + BYTE const* nextSrc; /* next block here to continue on current prefix */ + BYTE const* base; /* All regular indexes relative to this position */ + BYTE const* dictBase; /* extDict indexes relative to this position */ + U32 dictLimit; /* below that point, need extDict */ + U32 lowLimit; /* below that point, no more valid data */ } ZSTD_window_t; -#define ZSTD_WINDOW_START_INDEX 2 - typedef struct ZSTD_matchState_t ZSTD_matchState_t; - -#define ZSTD_ROW_HASH_CACHE_SIZE 8 /* Size of prefetching hash cache for row-based matchfinder */ - struct ZSTD_matchState_t { ZSTD_window_t window; /* State for window round buffer management */ U32 loadedDictEnd; /* index of end of dictionary, within context's referential. @@ -225,38 +144,12 @@ struct ZSTD_matchState_t { */ U32 nextToUpdate; /* index from which to continue table update */ U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */ - - U32 rowHashLog; /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/ - BYTE* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */ - U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */ - U64 hashSalt; /* For row-based matchFinder: salts the hash for re-use of tag table */ - U32 hashSaltEntropy; /* For row-based matchFinder: collects entropy for salt generation */ - U32* hashTable; U32* hashTable3; U32* chainTable; - - U32 forceNonContiguous; /* Non-zero if we should force non-contiguous load for the next window update. */ - - int dedicatedDictSearch; /* Indicates whether this matchState is using the - * dedicated dictionary search structure. - */ optState_t opt; /* optimal parser state */ const ZSTD_matchState_t* dictMatchState; ZSTD_compressionParameters cParams; - const rawSeqStore_t* ldmSeqStore; - - /* Controls prefetching in some dictMatchState matchfinders. - * This behavior is controlled from the cctx ms. - * This parameter has no effect in the cdict ms. */ - int prefetchCDictTables; - - /* When == 0, lazy match finders insert every position. - * When != 0, lazy match finders only insert positions they search. - * This allows them to skip much faster over incompressible data, - * at a small cost to compression ratio. - */ - int lazySkipping; }; typedef struct { @@ -270,26 +163,16 @@ typedef struct { U32 checksum; } ldmEntry_t; -typedef struct { - BYTE const* split; - U32 hash; - U32 checksum; - ldmEntry_t* bucket; -} ldmMatchCandidate_t; - -#define LDM_BATCH_SIZE 64 - typedef struct { ZSTD_window_t window; /* State for the window round buffer management */ ldmEntry_t* hashTable; - U32 loadedDictEnd; BYTE* bucketOffsets; /* Next position in bucket to insert entry */ - size_t splitIndices[LDM_BATCH_SIZE]; - ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE]; + U64 hashPower; /* Used to compute the rolling hash. + * Depends on ldmParams.minMatchLength */ } ldmState_t; typedef struct { - ZSTD_paramSwitch_e enableLdm; /* ZSTD_ps_enable to enable LDM. ZSTD_ps_auto by default */ + U32 enableLdm; /* 1 if enable long distance matching */ U32 hashLog; /* Log size of hashTable */ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */ U32 minMatchLength; /* Minimum match length */ @@ -297,6 +180,19 @@ typedef struct { U32 windowLog; /* Window log for the LDM */ } ldmParams_t; +typedef struct { + U32 offset; + U32 litLength; + U32 matchLength; +} rawSeq; + +typedef struct { + rawSeq* seq; /* The start of the sequences */ + size_t pos; /* The position where reading stopped. <= size. */ + size_t size; /* The number of sequences. <= capacity. */ + size_t capacity; /* The capacity starting from `seq` pointer */ +} rawSeqStore_t; + typedef struct { int collectSequences; ZSTD_Sequence* seqStart; @@ -320,7 +216,7 @@ struct ZSTD_CCtx_params_s { * There is no guarantee that hint is close to actual source size */ ZSTD_dictAttachPref_e attachDictPref; - ZSTD_paramSwitch_e literalCompressionMode; + ZSTD_literalCompressionMode_e literalCompressionMode; /* Multithreading: used to pass parameters to mtctx */ int nbWorkers; @@ -331,94 +227,17 @@ struct ZSTD_CCtx_params_s { /* Long distance matching parameters */ ldmParams_t ldmParams; - /* Dedicated dict search algorithm trigger */ - int enableDedicatedDictSearch; - - /* Input/output buffer modes */ - ZSTD_bufferMode_e inBufferMode; - ZSTD_bufferMode_e outBufferMode; - - /* Sequence compression API */ - ZSTD_sequenceFormat_e blockDelimiters; - int validateSequences; - - /* Block splitting */ - ZSTD_paramSwitch_e useBlockSplitter; - - /* Param for deciding whether to use row-based matchfinder */ - ZSTD_paramSwitch_e useRowMatchFinder; - - /* Always load a dictionary in ext-dict mode (not prefix mode)? */ - int deterministicRefPrefix; - /* Internal use, for createCCtxParams() and freeCCtxParams() only */ ZSTD_customMem customMem; - - /* Controls prefetching in some dictMatchState matchfinders */ - ZSTD_paramSwitch_e prefetchCDictTables; - - /* Controls whether zstd will fall back to an internal matchfinder - * if the external matchfinder returns an error code. */ - int enableMatchFinderFallback; - - /* Indicates whether an external matchfinder has been referenced. - * Users can't set this externally. - * It is set internally in ZSTD_registerSequenceProducer(). */ - int useSequenceProducer; - - /* Adjust the max block size*/ - size_t maxBlockSize; - - /* Controls repcode search in external sequence parsing */ - ZSTD_paramSwitch_e searchForExternalRepcodes; }; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */ -#define COMPRESS_SEQUENCES_WORKSPACE_SIZE (sizeof(unsigned) * (MaxSeq + 2)) -#define ENTROPY_WORKSPACE_SIZE (HUF_WORKSPACE_SIZE + COMPRESS_SEQUENCES_WORKSPACE_SIZE) - -/** - * Indicates whether this compression proceeds directly from user-provided - * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or - * whether the context needs to buffer the input/output (ZSTDb_buffered). - */ -typedef enum { - ZSTDb_not_buffered, - ZSTDb_buffered -} ZSTD_buffered_policy_e; - -/** - * Struct that contains all elements of block splitter that should be allocated - * in a wksp. - */ -#define ZSTD_MAX_NB_BLOCK_SPLITS 196 -typedef struct { - seqStore_t fullSeqStoreChunk; - seqStore_t firstHalfSeqStore; - seqStore_t secondHalfSeqStore; - seqStore_t currSeqStore; - seqStore_t nextSeqStore; - - U32 partitions[ZSTD_MAX_NB_BLOCK_SPLITS]; - ZSTD_entropyCTablesMetadata_t entropyMetadata; -} ZSTD_blockSplitCtx; - -/* Context for block-level external matchfinder API */ -typedef struct { - void* mState; - ZSTD_sequenceProducer_F* mFinder; - ZSTD_Sequence* seqBuffer; - size_t seqBufferCapacity; -} ZSTD_externalMatchCtx; - struct ZSTD_CCtx_s { ZSTD_compressionStage_e stage; int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ ZSTD_CCtx_params requestedParams; ZSTD_CCtx_params appliedParams; - ZSTD_CCtx_params simpleApiParams; /* Param storage used by the simple API - not sticky. Must only be used in top-level simple API functions for storage. */ U32 dictID; - size_t dictContentSize; ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */ size_t blockSize; @@ -427,11 +246,9 @@ struct ZSTD_CCtx_s { unsigned long long producedCSize; XXH64_state_t xxhState; ZSTD_customMem customMem; - ZSTD_threadPool* pool; size_t staticSize; SeqCollector seqCollector; int isFirstBlock; - int initialized; seqStore_t seqStore; /* sequences storage ptrs */ ldmState_t ldmState; /* long distance matching state */ @@ -439,10 +256,7 @@ struct ZSTD_CCtx_s { size_t maxNbLdmSequences; rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */ ZSTD_blockState_t blockState; - U32* entropyWorkspace; /* entropy workspace of ENTROPY_WORKSPACE_SIZE bytes */ - - /* Whether we are streaming or not */ - ZSTD_buffered_policy_e bufferedPolicy; + U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ /* streaming */ char* inBuff; @@ -457,11 +271,6 @@ struct ZSTD_CCtx_s { ZSTD_cStreamStage streamStage; U32 frameEnded; - /* Stable in/out buffer verification */ - ZSTD_inBuffer expectedInBuffer; - size_t stableIn_notConsumed; /* nb bytes within stable input buffer that are said to be consumed but are not */ - size_t expectedOutBufferSize; - /* Dictionary */ ZSTD_localDict localDict; const ZSTD_CDict* cdict; @@ -471,53 +280,17 @@ struct ZSTD_CCtx_s { #ifdef ZSTD_MULTITHREAD ZSTDMT_CCtx* mtctx; #endif - - /* Tracing */ -#if ZSTD_TRACE - ZSTD_TraceCtx traceCtx; -#endif - - /* Workspace for block splitter */ - ZSTD_blockSplitCtx blockSplitCtx; - - /* Workspace for external matchfinder */ - ZSTD_externalMatchCtx externalMatchCtx; }; typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; -typedef enum { ZSTD_tfp_forCCtx, ZSTD_tfp_forCDict } ZSTD_tableFillPurpose_e; - -typedef enum { - ZSTD_noDict = 0, - ZSTD_extDict = 1, - ZSTD_dictMatchState = 2, - ZSTD_dedicatedDictSearch = 3 -} ZSTD_dictMode_e; - -typedef enum { - ZSTD_cpm_noAttachDict = 0, /* Compression with ZSTD_noDict or ZSTD_extDict. - * In this mode we use both the srcSize and the dictSize - * when selecting and adjusting parameters. - */ - ZSTD_cpm_attachDict = 1, /* Compression with ZSTD_dictMatchState or ZSTD_dedicatedDictSearch. - * In this mode we only take the srcSize into account when selecting - * and adjusting parameters. - */ - ZSTD_cpm_createCDict = 2, /* Creating a CDict. - * In this mode we take both the source size and the dictionary size - * into account when selecting and adjusting the parameters. - */ - ZSTD_cpm_unknown = 3 /* ZSTD_getCParams, ZSTD_getParams, ZSTD_adjustParams. - * We don't know what these parameters are for. We default to the legacy - * behavior of taking both the source size and the dict size into account - * when selecting and adjusting parameters. - */ -} ZSTD_cParamMode_e; + +typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e; + typedef size_t (*ZSTD_blockCompressor) ( ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e rowMatchfinderMode, ZSTD_dictMode_e dictMode); +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode); MEM_STATIC U32 ZSTD_LLcode(U32 litLength) @@ -563,33 +336,6 @@ MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value) return 1; } -/* ZSTD_noCompressBlock() : - * Writes uncompressed block to dst buffer from given src. - * Returns the size of the block */ -MEM_STATIC size_t -ZSTD_noCompressBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) -{ - U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); - DEBUGLOG(5, "ZSTD_noCompressBlock (srcSize=%zu, dstCapacity=%zu)", srcSize, dstCapacity); - RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, - dstSize_tooSmall, "dst buf too small for uncompressed block"); - MEM_writeLE24(dst, cBlockHeader24); - ZSTD_memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); - return ZSTD_blockHeaderSize + srcSize; -} - -MEM_STATIC size_t -ZSTD_rleCompressBlock(void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock) -{ - BYTE* const op = (BYTE*)dst; - U32 const cBlockHeader = lastBlock + (((U32)bt_rle)<<1) + (U32)(srcSize << 3); - RETURN_ERROR_IF(dstCapacity < 4, dstSize_tooSmall, ""); - MEM_writeLE24(op, cBlockHeader); - op[3] = src; - return 4; -} - - /* ZSTD_minGain() : * minimum compression required * to generate a compress block or a compressed literals section. @@ -598,33 +344,16 @@ MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) { U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6; ZSTD_STATIC_ASSERT(ZSTD_btultra == 8); - assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, (int)strat)); + assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); return (srcSize >> minlog) + 2; } -MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxParams) -{ - switch (cctxParams->literalCompressionMode) { - case ZSTD_ps_enable: - return 0; - case ZSTD_ps_disable: - return 1; - default: - assert(0 /* impossible: pre-validated */); - ZSTD_FALLTHROUGH; - case ZSTD_ps_auto: - return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); - } -} - /*! ZSTD_safecopyLiterals() : * memcpy() function that won't read beyond more than WILDCOPY_OVERLENGTH bytes past ilimit_w. * Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single * large copies. */ -static void -ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) -{ +static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) { assert(iend > ilimit_w); if (ip <= ilimit_w) { ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap); @@ -634,28 +363,14 @@ ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE con while (ip < iend) *op++ = *ip++; } - -#define REPCODE1_TO_OFFBASE REPCODE_TO_OFFBASE(1) -#define REPCODE2_TO_OFFBASE REPCODE_TO_OFFBASE(2) -#define REPCODE3_TO_OFFBASE REPCODE_TO_OFFBASE(3) -#define REPCODE_TO_OFFBASE(r) (assert((r)>=1), assert((r)<=ZSTD_REP_NUM), (r)) /* accepts IDs 1,2,3 */ -#define OFFSET_TO_OFFBASE(o) (assert((o)>0), o + ZSTD_REP_NUM) -#define OFFBASE_IS_OFFSET(o) ((o) > ZSTD_REP_NUM) -#define OFFBASE_IS_REPCODE(o) ( 1 <= (o) && (o) <= ZSTD_REP_NUM) -#define OFFBASE_TO_OFFSET(o) (assert(OFFBASE_IS_OFFSET(o)), (o) - ZSTD_REP_NUM) -#define OFFBASE_TO_REPCODE(o) (assert(OFFBASE_IS_REPCODE(o)), (o)) /* returns ID 1,2,3 */ - /*! ZSTD_storeSeq() : - * Store a sequence (litlen, litPtr, offBase and matchLength) into seqStore_t. - * @offBase : Users should employ macros REPCODE_TO_OFFBASE() and OFFSET_TO_OFFBASE(). - * @matchLength : must be >= MINMATCH - * Allowed to over-read literals up to litLimit. + * Store a sequence (litlen, litPtr, offCode and mlBase) into seqStore_t. + * `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes). + * `mlBase` : matchLength - MINMATCH + * Allowed to overread literals up to litLimit. */ -HINT_INLINE UNUSED_ATTR void -ZSTD_storeSeq(seqStore_t* seqStorePtr, - size_t litLength, const BYTE* literals, const BYTE* litLimit, - U32 offBase, - size_t matchLength) +HINT_INLINE UNUSED_ATTR +void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t mlBase) { BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH; BYTE const* const litEnd = literals + litLength; @@ -663,8 +378,8 @@ ZSTD_storeSeq(seqStore_t* seqStorePtr, static const BYTE* g_start = NULL; if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ { U32 const pos = (U32)((const BYTE*)literals - g_start); - DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offBase%7u", - pos, (U32)litLength, (U32)matchLength, (U32)offBase); + DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u", + pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offCode); } #endif assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq); @@ -674,9 +389,9 @@ ZSTD_storeSeq(seqStore_t* seqStorePtr, assert(literals + litLength <= litLimit); if (litEnd <= litLimit_w) { /* Common case we can use wildcopy. - * First copy 16 bytes, because literals are likely short. - */ - ZSTD_STATIC_ASSERT(WILDCOPY_OVERLENGTH >= 16); + * First copy 16 bytes, because literals are likely short. + */ + assert(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(seqStorePtr->lit, literals); if (litLength > 16) { ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap); @@ -688,70 +403,99 @@ ZSTD_storeSeq(seqStore_t* seqStorePtr, /* literal Length */ if (litLength>0xFFFF) { - assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ - seqStorePtr->longLengthType = ZSTD_llt_literalLength; + assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ + seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); } seqStorePtr->sequences[0].litLength = (U16)litLength; /* match offset */ - seqStorePtr->sequences[0].offBase = offBase; + seqStorePtr->sequences[0].offset = offCode + 1; /* match Length */ - assert(matchLength >= MINMATCH); - { size_t const mlBase = matchLength - MINMATCH; - if (mlBase>0xFFFF) { - assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ - seqStorePtr->longLengthType = ZSTD_llt_matchLength; - seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - } - seqStorePtr->sequences[0].mlBase = (U16)mlBase; + if (mlBase>0xFFFF) { + assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ + seqStorePtr->longLengthID = 2; + seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); } + seqStorePtr->sequences[0].matchLength = (U16)mlBase; seqStorePtr->sequences++; } -/* ZSTD_updateRep() : - * updates in-place @rep (array of repeat offsets) - * @offBase : sum-type, using numeric representation of ZSTD_storeSeq() - */ -MEM_STATIC void -ZSTD_updateRep(U32 rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) -{ - if (OFFBASE_IS_OFFSET(offBase)) { /* full offset */ - rep[2] = rep[1]; - rep[1] = rep[0]; - rep[0] = OFFBASE_TO_OFFSET(offBase); - } else { /* repcode */ - U32 const repCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; - if (repCode > 0) { /* note : if repCode==0, no change */ - U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - rep[2] = (repCode >= 2) ? rep[1] : rep[2]; - rep[1] = rep[0]; - rep[0] = currentOffset; - } else { /* repCode == 0 */ - /* nothing to do */ - } - } -} - -typedef struct repcodes_s { - U32 rep[3]; -} repcodes_t; - -MEM_STATIC repcodes_t -ZSTD_newRep(U32 const rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) -{ - repcodes_t newReps; - ZSTD_memcpy(&newReps, rep, sizeof(newReps)); - ZSTD_updateRep(newReps.rep, offBase, ll0); - return newReps; -} - /*-************************************* * Match length counter ***************************************/ +static unsigned ZSTD_NbCommonBytes (size_t val) +{ + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, + 0, 3, 1, 3, 1, 4, 2, 7, + 0, 2, 3, 6, 1, 5, 3, 5, + 1, 3, 4, 4, 2, 5, 6, 7, + 7, 0, 1, 2, 3, 3, 4, 6, + 2, 6, 5, 5, 3, 4, 5, 6, + 7, 1, 2, 4, 6, 4, 4, 5, + 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + unsigned long r=0; + _BitScanForward( &r, (U32)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, + 3, 2, 2, 1, 3, 2, 0, 1, + 3, 3, 1, 2, 2, 2, 2, 0, + 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } else { /* Big Endian CPU */ + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (__builtin_clzll(val) >> 3); +# else + unsigned r; + const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ + if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif + } } +} + + MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit) { const BYTE* const pStart = pIn; @@ -797,43 +541,31 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match, * Hashes ***************************************/ static const U32 prime3bytes = 506832829U; -static U32 ZSTD_hash3(U32 u, U32 h, U32 s) { assert(h <= 32); return (((u << (32-24)) * prime3bytes) ^ s) >> (32-h) ; } -MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h, 0); } /* only in zstd_opt.h */ -MEM_STATIC size_t ZSTD_hash3PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash3(MEM_readLE32(ptr), h, s); } +static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; } +MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */ static const U32 prime4bytes = 2654435761U; -static U32 ZSTD_hash4(U32 u, U32 h, U32 s) { assert(h <= 32); return ((u * prime4bytes) ^ s) >> (32-h) ; } -static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_readLE32(ptr), h, 0); } -static size_t ZSTD_hash4PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash4(MEM_readLE32(ptr), h, s); } +static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } +static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); } static const U64 prime5bytes = 889523592379ULL; -static size_t ZSTD_hash5(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-40)) * prime5bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash5PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash5(MEM_readLE64(p), h, s); } +static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; } +static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); } static const U64 prime6bytes = 227718039650203ULL; -static size_t ZSTD_hash6(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-48)) * prime6bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash6PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash6(MEM_readLE64(p), h, s); } +static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } +static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } static const U64 prime7bytes = 58295818150454627ULL; -static size_t ZSTD_hash7(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-56)) * prime7bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash7PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash7(MEM_readLE64(p), h, s); } +static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; } +static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); } static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; -static size_t ZSTD_hash8(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u) * prime8bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash8PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash8(MEM_readLE64(p), h, s); } - +static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } +static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } -MEM_STATIC FORCE_INLINE_ATTR -size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) +MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) { - /* Although some of these hashes do support hBits up to 64, some do not. - * To be on the safe side, always avoid hBits > 32. */ - assert(hBits <= 32); - switch(mls) { default: @@ -845,24 +577,6 @@ size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) } } -MEM_STATIC FORCE_INLINE_ATTR -size_t ZSTD_hashPtrSalted(const void* p, U32 hBits, U32 mls, const U64 hashSalt) { - /* Although some of these hashes do support hBits up to 64, some do not. - * To be on the safe side, always avoid hBits > 32. */ - assert(hBits <= 32); - - switch(mls) - { - default: - case 4: return ZSTD_hash4PtrS(p, hBits, (U32)hashSalt); - case 5: return ZSTD_hash5PtrS(p, hBits, hashSalt); - case 6: return ZSTD_hash6PtrS(p, hBits, hashSalt); - case 7: return ZSTD_hash7PtrS(p, hBits, hashSalt); - case 8: return ZSTD_hash8PtrS(p, hBits, hashSalt); - } -} - - /** ZSTD_ipow() : * Return base^exponent. */ @@ -947,13 +661,6 @@ MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window) window->dictLimit = end; } -MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window) -{ - return window.dictLimit == ZSTD_WINDOW_START_INDEX && - window.lowLimit == ZSTD_WINDOW_START_INDEX && - (window.nextSrc - window.base) == ZSTD_WINDOW_START_INDEX; -} - /** * ZSTD_window_hasExtDict(): * Returns non-zero if the window has a non-empty extDict. @@ -973,76 +680,20 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms) return ZSTD_window_hasExtDict(ms->window) ? ZSTD_extDict : ms->dictMatchState != NULL ? - (ms->dictMatchState->dedicatedDictSearch ? ZSTD_dedicatedDictSearch : ZSTD_dictMatchState) : + ZSTD_dictMatchState : ZSTD_noDict; } -/* Defining this macro to non-zero tells zstd to run the overflow correction - * code much more frequently. This is very inefficient, and should only be - * used for tests and fuzzers. - */ -#ifndef ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY -# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 1 -# else -# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 0 -# endif -#endif - -/** - * ZSTD_window_canOverflowCorrect(): - * Returns non-zero if the indices are large enough for overflow correction - * to work correctly without impacting compression ratio. - */ -MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window, - U32 cycleLog, - U32 maxDist, - U32 loadedDictEnd, - void const* src) -{ - U32 const cycleSize = 1u << cycleLog; - U32 const curr = (U32)((BYTE const*)src - window.base); - U32 const minIndexToOverflowCorrect = cycleSize - + MAX(maxDist, cycleSize) - + ZSTD_WINDOW_START_INDEX; - - /* Adjust the min index to backoff the overflow correction frequency, - * so we don't waste too much CPU in overflow correction. If this - * computation overflows we don't really care, we just need to make - * sure it is at least minIndexToOverflowCorrect. - */ - U32 const adjustment = window.nbOverflowCorrections + 1; - U32 const adjustedIndex = MAX(minIndexToOverflowCorrect * adjustment, - minIndexToOverflowCorrect); - U32 const indexLargeEnough = curr > adjustedIndex; - - /* Only overflow correct early if the dictionary is invalidated already, - * so we don't hurt compression ratio. - */ - U32 const dictionaryInvalidated = curr > maxDist + loadedDictEnd; - - return indexLargeEnough && dictionaryInvalidated; -} - /** * ZSTD_window_needOverflowCorrection(): * Returns non-zero if the indices are getting too large and need overflow * protection. */ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, - U32 cycleLog, - U32 maxDist, - U32 loadedDictEnd, - void const* src, void const* srcEnd) { - U32 const curr = (U32)((BYTE const*)srcEnd - window.base); - if (ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { - if (ZSTD_window_canOverflowCorrect(window, cycleLog, maxDist, loadedDictEnd, src)) { - return 1; - } - } - return curr > ZSTD_CURRENT_MAX; + U32 const current = (U32)((BYTE const*)srcEnd - window.base); + return current > ZSTD_CURRENT_MAX; } /** @@ -1053,6 +704,7 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, * * The least significant cycleLog bits of the indices must remain the same, * which may be 0. Every index up to maxDist in the past must be valid. + * NOTE: (maxDist & cycleMask) must be zero. */ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, U32 maxDist, void const* src) @@ -1076,51 +728,19 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, * 3. (cctx->lowLimit + 1< 3<<29 + 1<base); - U32 const currentCycle = curr & cycleMask; - /* Ensure newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX. */ - U32 const currentCycleCorrection = currentCycle < ZSTD_WINDOW_START_INDEX - ? MAX(cycleSize, ZSTD_WINDOW_START_INDEX) - : 0; - U32 const newCurrent = currentCycle - + currentCycleCorrection - + MAX(maxDist, cycleSize); - U32 const correction = curr - newCurrent; - /* maxDist must be a power of two so that: - * (newCurrent & cycleMask) == (curr & cycleMask) - * This is required to not corrupt the chains / binary tree. - */ - assert((maxDist & (maxDist - 1)) == 0); - assert((curr & cycleMask) == (newCurrent & cycleMask)); - assert(curr > newCurrent); - if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { - /* Loose bound, should be around 1<<29 (see above) */ - assert(correction > 1<<28); - } + U32 const cycleMask = (1U << cycleLog) - 1; + U32 const current = (U32)((BYTE const*)src - window->base); + U32 const newCurrent = (current & cycleMask) + maxDist; + U32 const correction = current - newCurrent; + assert((maxDist & cycleMask) == 0); + assert(current > newCurrent); + /* Loose bound, should be around 1<<29 (see above) */ + assert(correction > 1<<28); window->base += correction; window->dictBase += correction; - if (window->lowLimit < correction + ZSTD_WINDOW_START_INDEX) { - window->lowLimit = ZSTD_WINDOW_START_INDEX; - } else { - window->lowLimit -= correction; - } - if (window->dictLimit < correction + ZSTD_WINDOW_START_INDEX) { - window->dictLimit = ZSTD_WINDOW_START_INDEX; - } else { - window->dictLimit -= correction; - } - - /* Ensure we can still reference the full window. */ - assert(newCurrent >= maxDist); - assert(newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX); - /* Ensure that lowLimit and dictLimit didn't underflow. */ - assert(window->lowLimit <= newCurrent); - assert(window->dictLimit <= newCurrent); - - ++window->nbOverflowCorrections; + window->lowLimit -= correction; + window->dictLimit -= correction; DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, window->lowLimit); @@ -1210,15 +830,10 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd); assert(blockEndIdx >= loadedDictEnd); - if (blockEndIdx > loadedDictEnd + maxDist || loadedDictEnd != window->dictLimit) { + if (blockEndIdx > loadedDictEnd + maxDist) { /* On reaching window size, dictionaries are invalidated. * For simplification, if window size is reached anywhere within next block, * the dictionary is invalidated for the full block. - * - * We also have to invalidate the dictionary if ZSTD_window_update() has detected - * non-contiguous segments, which means that loadedDictEnd != window->dictLimit. - * loadedDictEnd may be 0, if forceWindow is true, but in that case we never use - * dictMatchState, so setting it to NULL is not a problem. */ DEBUGLOG(6, "invalidating dictionary for current block (distance > windowSize)"); *loadedDictEndPtr = 0; @@ -1229,17 +844,6 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, } } } } -MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { - ZSTD_memset(window, 0, sizeof(*window)); - window->base = (BYTE const*)" "; - window->dictBase = (BYTE const*)" "; - ZSTD_STATIC_ASSERT(ZSTD_DUBT_UNSORTED_MARK < ZSTD_WINDOW_START_INDEX); /* Start above ZSTD_DUBT_UNSORTED_MARK */ - window->dictLimit = ZSTD_WINDOW_START_INDEX; /* start from >0, so that 1st position is valid */ - window->lowLimit = ZSTD_WINDOW_START_INDEX; /* it ensures first and later CCtx usages compress the same */ - window->nextSrc = window->base + ZSTD_WINDOW_START_INDEX; /* see issue #1241 */ - window->nbOverflowCorrections = 0; -} - /** * ZSTD_window_update(): * Updates the window by appending [src, src + srcSize) to the window. @@ -1248,18 +852,13 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { * Returns non-zero if the segment is contiguous. */ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, - void const* src, size_t srcSize, - int forceNonContiguous) + void const* src, size_t srcSize) { BYTE const* const ip = (BYTE const*)src; U32 contiguous = 1; DEBUGLOG(5, "ZSTD_window_update"); - if (srcSize == 0) - return contiguous; - assert(window->base != NULL); - assert(window->dictBase != NULL); /* Check if blocks follow each other */ - if (src != window->nextSrc || forceNonContiguous) { + if (src != window->nextSrc) { /* not contiguous */ size_t const distanceFromBase = (size_t)(window->nextSrc - window->base); DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit); @@ -1268,7 +867,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, window->dictLimit = (U32)distanceFromBase; window->dictBase = window->base; window->base = ip - distanceFromBase; - /* ms->nextToUpdate = window->dictLimit; */ + // ms->nextToUpdate = window->dictLimit; if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit; /* too small extDict */ contiguous = 0; } @@ -1284,35 +883,12 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, return contiguous; } -/** - * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix. - */ -MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) -{ - U32 const maxDistance = 1U << windowLog; - U32 const lowestValid = ms->window.lowLimit; - U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; - U32 const isDictionary = (ms->loadedDictEnd != 0); - /* When using a dictionary the entire dictionary is valid if a single byte of the dictionary - * is within the window. We invalidate the dictionary (and set loadedDictEnd to 0) when it isn't - * valid for the entire block. So this check is sufficient to find the lowest valid match index. - */ - U32 const matchLowest = isDictionary ? lowestValid : withinWindow; - return matchLowest; -} - -/** - * Returns the lowest allowed match index in the prefix. - */ -MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog) { U32 const maxDistance = 1U << windowLog; - U32 const lowestValid = ms->window.dictLimit; - U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + U32 const lowestValid = ms->window.lowLimit; + U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; U32 const isDictionary = (ms->loadedDictEnd != 0); - /* When computing the lowest prefix index we need to take the dictionary into account to handle - * the edge case where the dictionary and the source are contiguous in memory. - */ U32 const matchLowest = isDictionary ? lowestValid : withinWindow; return matchLowest; } @@ -1350,61 +926,11 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) #endif -/* Short Cache */ - -/* Normally, zstd matchfinders follow this flow: - * 1. Compute hash at ip - * 2. Load index from hashTable[hash] - * 3. Check if *ip == *(base + index) - * In dictionary compression, loading *(base + index) is often an L2 or even L3 miss. - * - * Short cache is an optimization which allows us to avoid step 3 most of the time - * when the data doesn't actually match. With short cache, the flow becomes: - * 1. Compute (hash, currentTag) at ip. currentTag is an 8-bit independent hash at ip. - * 2. Load (index, matchTag) from hashTable[hash]. See ZSTD_writeTaggedIndex to understand how this works. - * 3. Only if currentTag == matchTag, check *ip == *(base + index). Otherwise, continue. - * - * Currently, short cache is only implemented in CDict hashtables. Thus, its use is limited to - * dictMatchState matchfinders. - */ -#define ZSTD_SHORT_CACHE_TAG_BITS 8 -#define ZSTD_SHORT_CACHE_TAG_MASK ((1u << ZSTD_SHORT_CACHE_TAG_BITS) - 1) - -/* Helper function for ZSTD_fillHashTable and ZSTD_fillDoubleHashTable. - * Unpacks hashAndTag into (hash, tag), then packs (index, tag) into hashTable[hash]. */ -MEM_STATIC void ZSTD_writeTaggedIndex(U32* const hashTable, size_t hashAndTag, U32 index) { - size_t const hash = hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; - U32 const tag = (U32)(hashAndTag & ZSTD_SHORT_CACHE_TAG_MASK); - assert(index >> (32 - ZSTD_SHORT_CACHE_TAG_BITS) == 0); - hashTable[hash] = (index << ZSTD_SHORT_CACHE_TAG_BITS) | tag; -} - -/* Helper function for short cache matchfinders. - * Unpacks tag1 and tag2 from lower bits of packedTag1 and packedTag2, then checks if the tags match. */ -MEM_STATIC int ZSTD_comparePackedTags(size_t packedTag1, size_t packedTag2) { - U32 const tag1 = packedTag1 & ZSTD_SHORT_CACHE_TAG_MASK; - U32 const tag2 = packedTag2 & ZSTD_SHORT_CACHE_TAG_MASK; - return tag1 == tag2; -} #if defined (__cplusplus) } #endif -/* =============================================================== - * Shared internal declarations - * These prototypes may be called from sources not in lib/compress - * =============================================================== */ - -/* ZSTD_loadCEntropy() : - * dict : must point at beginning of a valid zstd dictionary. - * return : size of dictionary header (size of magic number + dict ID + entropy tables) - * assumptions : magic number supposed already checked - * and dictSize >= 8 */ -size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, - const void* const dict, size_t dictSize); - -void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); /* ============================================================== * Private declarations @@ -1414,10 +940,9 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); /* ZSTD_getCParamsFromCCtxParams() : * cParams are built depending on compressionLevel, src size hints, * LDM and manually set compression parameters. - * Note: srcSizeHint == 0 means 0! */ ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize); /*! ZSTD_initCStream_internal() : * Private use only. Init streaming operation. @@ -1474,62 +999,5 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity); */ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq); -/** ZSTD_cycleLog() : - * condition for correct operation : hashLog > 1 */ -U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat); - -/** ZSTD_CCtx_trace() : - * Trace the end of a compression call. - */ -void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize); - -/* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of - * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter. - * Note that the block delimiter must include the last literals of the block. - */ -size_t -ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, - ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); - -/* Returns the number of bytes to move the current read position back by. - * Only non-zero if we ended up splitting a sequence. - * Otherwise, it may return a ZSTD error if something went wrong. - * - * This function will attempt to scan through blockSize bytes - * represented by the sequences in @inSeqs, - * storing any (partial) sequences. - * - * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to - * avoid splitting a match, or to avoid splitting a match such that it would produce a match - * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block. - */ -size_t -ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); - - -/* =============================================================== - * Deprecated definitions that are still used internally to avoid - * deprecation warnings. These functions are exactly equivalent to - * their public variants, but avoid the deprecation warnings. - * =============================================================== */ - -size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); - -size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - -size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - -size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - #endif /* ZSTD_COMPRESS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_literals.c b/vendor/github.com/DataDog/zstd/zstd_compress_literals.c index 7b4e0756..6c133311 100644 --- a/vendor/github.com/DataDog/zstd/zstd_compress_literals.c +++ b/vendor/github.com/DataDog/zstd/zstd_compress_literals.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,37 +13,12 @@ ***************************************/ #include "zstd_compress_literals.h" - -/* ************************************************************** -* Debug Traces -****************************************************************/ -#if DEBUGLEVEL >= 2 - -static size_t showHexa(const void* src, size_t srcSize) -{ - const BYTE* const ip = (const BYTE*)src; - size_t u; - for (u=0; u31) + (srcSize>4095); - DEBUGLOG(5, "ZSTD_noCompressLiterals: srcSize=%zu, dstCapacity=%zu", srcSize, dstCapacity); - - RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, ""); + RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall); switch(flSize) { @@ -61,31 +35,16 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, assert(0); } - ZSTD_memcpy(ostart + flSize, src, srcSize); - DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); + memcpy(ostart + flSize, src, srcSize); return srcSize + flSize; } -static int allBytesIdentical(const void* src, size_t srcSize) -{ - assert(srcSize >= 1); - assert(src != NULL); - { const BYTE b = ((const BYTE*)src)[0]; - size_t p; - for (p=1; p31) + (srcSize>4095); - assert(dstCapacity >= 4); (void)dstCapacity; - assert(allBytesIdentical(src, srcSize)); + (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ switch(flSize) { @@ -103,103 +62,66 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* } ostart[flSize] = *(const BYTE*)src; - DEBUGLOG(5, "RLE : Repeated Literal (%02X: %u times) -> %u bytes encoded", ((const BYTE*)src)[0], (U32)srcSize, (U32)flSize + 1); return flSize+1; } -/* ZSTD_minLiteralsToCompress() : - * returns minimal amount of literals - * for literal compression to even be attempted. - * Minimum is made tighter as compression strategy increases. - */ -static size_t -ZSTD_minLiteralsToCompress(ZSTD_strategy strategy, HUF_repeat huf_repeat) -{ - assert((int)strategy >= 0); - assert((int)strategy <= 9); - /* btultra2 : min 8 bytes; - * then 2x larger for each successive compression strategy - * max threshold 64 bytes */ - { int const shift = MIN(9-(int)strategy, 3); - size_t const mintc = (huf_repeat == HUF_repeat_valid) ? 6 : (size_t)8 << shift; - DEBUGLOG(7, "minLiteralsToCompress = %zu", mintc); - return mintc; - } -} - -size_t ZSTD_compressLiterals ( - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - void* entropyWorkspace, size_t entropyWorkspaceSize, - const ZSTD_hufCTables_t* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_strategy strategy, - int disableLiteralCompression, - int suspectUncompressible, - int bmi2) +size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_strategy strategy, int disableLiteralCompression, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + void* entropyWorkspace, size_t entropyWorkspaceSize, + const int bmi2) { + size_t const minGain = ZSTD_minGain(srcSize, strategy); size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); BYTE* const ostart = (BYTE*)dst; U32 singleStream = srcSize < 256; symbolEncodingType_e hType = set_compressed; size_t cLitSize; - DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i, srcSize=%u, dstCapacity=%zu)", - disableLiteralCompression, (U32)srcSize, dstCapacity); - - DEBUGLOG(6, "Completed literals listing (%zu bytes)", showHexa(src, srcSize)); + DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)", + disableLiteralCompression); /* Prepare nextEntropy assuming reusing the existing table */ - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); if (disableLiteralCompression) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - /* if too small, don't even attempt compression (speed opt) */ - if (srcSize < ZSTD_minLiteralsToCompress(strategy, prevHuf->repeatMode)) - return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + /* small ? don't even attempt compression (speed opt) */ +# define COMPRESS_LITERALS_SIZE_MIN 63 + { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; + if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); { HUF_repeat repeat = prevHuf->repeatMode; - int const flags = 0 - | (bmi2 ? HUF_flags_bmi2 : 0) - | (strategy < ZSTD_lazy && srcSize <= 1024 ? HUF_flags_preferRepeat : 0) - | (strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD ? HUF_flags_optimalDepth : 0) - | (suspectUncompressible ? HUF_flags_suspectUncompressible : 0); - - typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int); - huf_compress_f huf_compress; + int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; - huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; - cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, - src, srcSize, - HUF_SYMBOLVALUE_MAX, LitHufLog, - entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, - &repeat, flags); - DEBUGLOG(5, "%zu literals compressed into %zu bytes (before header)", srcSize, cLitSize); + cLitSize = singleStream ? + HUF_compress1X_repeat( + ostart+lhSize, dstCapacity-lhSize, src, srcSize, + 255, 11, entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) : + HUF_compress4X_repeat( + ostart+lhSize, dstCapacity-lhSize, src, srcSize, + 255, 11, entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); if (repeat != HUF_repeat_none) { /* reused the existing table */ - DEBUGLOG(5, "reusing statistics from previous huffman block"); hType = set_repeat; } } - { size_t const minGain = ZSTD_minGain(srcSize, strategy); - if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - } } + if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } if (cLitSize==1) { - /* A return value of 1 signals that the alphabet consists of a single symbol. - * However, in some rare circumstances, it could be the compressed size (a single byte). - * For that outcome to have a chance to happen, it's necessary that `srcSize < 8`. - * (it's also necessary to not generate statistics). - * Therefore, in such a case, actively check that all bytes are identical. */ - if ((srcSize >= 8) || allBytesIdentical(src, srcSize)) { - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); - } } + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); + } if (hType == set_compressed) { /* using a newly constructed table */ @@ -210,19 +132,16 @@ size_t ZSTD_compressLiterals ( switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - if (!singleStream) assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); - { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); + { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); MEM_writeLE24(ostart, lhc); break; } case 4: /* 2 - 2 - 14 - 14 */ - assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); MEM_writeLE32(ostart, lhc); break; } case 5: /* 2 - 2 - 18 - 18 */ - assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); MEM_writeLE32(ostart, lhc); ostart[4] = (BYTE)(cLitSize >> 10); @@ -231,8 +150,5 @@ size_t ZSTD_compressLiterals ( default: /* not possible : lhSize is {3,4,5} */ assert(0); } - DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)srcSize, (U32)(lhSize+cLitSize)); return lhSize+cLitSize; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_literals.h b/vendor/github.com/DataDog/zstd/zstd_compress_literals.h index 80cb1db2..97273d7c 100644 --- a/vendor/github.com/DataDog/zstd/zstd_compress_literals.h +++ b/vendor/github.com/DataDog/zstd/zstd_compress_literals.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,26 +16,14 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/* ZSTD_compressRleLiteralsBlock() : - * Conditions : - * - All bytes in @src are identical - * - dstCapacity >= 4 */ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/* ZSTD_compressLiterals(): - * @entropyWorkspace: must be aligned on 4-bytes boundaries - * @entropyWorkspaceSize : must be >= HUF_WORKSPACE_SIZE - * @suspectUncompressible: sampling checks, to potentially skip huffman coding - */ -size_t ZSTD_compressLiterals (void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - void* entropyWorkspace, size_t entropyWorkspaceSize, - const ZSTD_hufCTables_t* prevHuf, +size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, ZSTD_hufCTables_t* nextHuf, ZSTD_strategy strategy, int disableLiteralCompression, - int suspectUncompressible, - int bmi2); + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + void* entropyWorkspace, size_t entropyWorkspaceSize, + const int bmi2); #endif /* ZSTD_COMPRESS_LITERALS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_sequences.c b/vendor/github.com/DataDog/zstd/zstd_compress_sequences.c index 465f3781..0ff7a268 100644 --- a/vendor/github.com/DataDog/zstd/zstd_compress_sequences.c +++ b/vendor/github.com/DataDog/zstd/zstd_compress_sequences.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -51,19 +50,6 @@ static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { return maxSymbolValue; } -/** - * Returns true if we should use ncount=-1 else we should - * use ncount=1 for low probability symbols instead. - */ -static unsigned ZSTD_useLowProbCount(size_t const nbSeq) -{ - /* Heuristic: This should cover most blocks <= 16K and - * start to fade out after 16K to about 32K depending on - * compressibility. - */ - return nbSeq >= 2048; -} - /** * Returns the cost in bytes of encoding the normalized count header. * Returns an error if any of the helper functions return an error. @@ -74,7 +60,7 @@ static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, BYTE wksp[FSE_NCOUNTBOUND]; S16 norm[MaxSeq + 1]; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); - FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max, ZSTD_useLowProbCount(nbSeq)), ""); + FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max)); return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); } @@ -86,8 +72,6 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t { unsigned cost = 0; unsigned s; - - assert(total > 0); for (s = 0; s <= max; ++s) { unsigned norm = (unsigned)((256 * count[s]) / total); if (count[s] != 0 && norm == 0) @@ -102,7 +86,7 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t * Returns the cost in bits of encoding the distribution in count using ctable. * Returns an error if ctable cannot represent all the symbols in count. */ -size_t ZSTD_fseBitCost( +static size_t ZSTD_fseBitCost( FSE_CTable const* ctable, unsigned const* count, unsigned const max) @@ -112,22 +96,18 @@ size_t ZSTD_fseBitCost( unsigned s; FSE_CState_t cstate; FSE_initCState(&cstate, ctable); - if (ZSTD_getFSEMaxSymbolValue(ctable) < max) { - DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u", + RETURN_ERROR_IF(ZSTD_getFSEMaxSymbolValue(ctable) < max, GENERIC, + "Repeat FSE_CTable has maxSymbolValue %u < %u", ZSTD_getFSEMaxSymbolValue(ctable), max); - return ERROR(GENERIC); - } for (s = 0; s <= max; ++s) { unsigned const tableLog = cstate.stateLog; unsigned const badCost = (tableLog + 1) << kAccuracyLog; unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog); if (count[s] == 0) continue; - if (bitCost >= badCost) { - DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s); - return ERROR(GENERIC); - } - cost += (size_t)count[s] * bitCost; + RETURN_ERROR_IF(bitCost >= badCost, GENERIC, + "Repeat FSE_CTable has Prob[%u] == 0", s); + cost += count[s] * bitCost; } return cost >> kAccuracyLog; } @@ -137,15 +117,15 @@ size_t ZSTD_fseBitCost( * table described by norm. The max symbol support by norm is assumed >= max. * norm must be valid for every symbol with non-zero probability in count. */ -size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, - unsigned const* count, unsigned const max) +static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, + unsigned const* count, unsigned const max) { unsigned const shift = 8 - accuracyLog; size_t cost = 0; unsigned s; assert(accuracyLog <= 8); for (s = 0; s <= max; ++s) { - unsigned const normAcc = (norm[s] != -1) ? (unsigned)norm[s] : 1; + unsigned const normAcc = norm[s] != -1 ? norm[s] : 1; unsigned const norm256 = normAcc << shift; assert(norm256 > 0); assert(norm256 < 256); @@ -167,7 +147,7 @@ ZSTD_selectEncodingType( if (mostFrequent == nbSeq) { *repeatMode = FSE_repeat_none; if (isDefaultAllowed && nbSeq <= 2) { - /* Prefer set_basic over set_rle when there are 2 or fewer symbols, + /* Prefer set_basic over set_rle when there are 2 or less symbols, * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. * If basic encoding isn't possible, always choose RLE. */ @@ -235,11 +215,6 @@ ZSTD_selectEncodingType( return set_compressed; } -typedef struct { - S16 norm[MaxSeq + 1]; - U32 wksp[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(MaxSeq, MaxFSELog)]; -} ZSTD_BuildCTableWksp; - size_t ZSTD_buildCTable(void* dst, size_t dstCapacity, FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, @@ -255,18 +230,18 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, switch (type) { case set_rle: - FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max), ""); - RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall, "not enough space"); + FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max)); + RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall); *op = codeTable[0]; return 1; case set_repeat: - ZSTD_memcpy(nextCTable, prevCTable, prevCTableSize); + memcpy(nextCTable, prevCTable, prevCTableSize); return 0; case set_basic: - FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */ + FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize)); /* note : could be pre-calculated */ return 0; case set_compressed: { - ZSTD_BuildCTableWksp* wksp = (ZSTD_BuildCTableWksp*)entropyWorkspace; + S16 norm[MaxSeq + 1]; size_t nbSeq_1 = nbSeq; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); if (count[codeTable[nbSeq-1]] > 1) { @@ -274,17 +249,14 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, nbSeq_1--; } assert(nbSeq_1 > 1); - assert(entropyWorkspaceSize >= sizeof(ZSTD_BuildCTableWksp)); - (void)entropyWorkspaceSize; - FORWARD_IF_ERROR(FSE_normalizeCount(wksp->norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "FSE_normalizeCount failed"); - assert(oend >= op); - { size_t const NCountSize = FSE_writeNCount(op, (size_t)(oend - op), wksp->norm, max, tableLog); /* overflow protected */ - FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed"); - FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, wksp->norm, max, tableLog, wksp->wksp, sizeof(wksp->wksp)), "FSE_buildCTable_wksp failed"); + FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max)); + { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ + FORWARD_IF_ERROR(NCountSize); + FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize)); return NCountSize; } } - default: assert(0); RETURN_ERROR(GENERIC, "impossible to reach"); + default: assert(0); RETURN_ERROR(GENERIC); } } @@ -314,19 +286,19 @@ ZSTD_encodeSequences_body( FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[nbSeq-1].mlBase, ML_bits[mlCodeTable[nbSeq-1]]); + BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); if (longOffsets) { U32 const ofBits = ofCodeTable[nbSeq-1]; - unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); + int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, extraBits); + BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); BIT_flushBits(&blockStream); } - BIT_addBits(&blockStream, sequences[nbSeq-1].offBase >> extraBits, + BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, ofBits - extraBits); } else { - BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, ofCodeTable[nbSeq-1]); + BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); } BIT_flushBits(&blockStream); @@ -340,8 +312,8 @@ ZSTD_encodeSequences_body( U32 const mlBits = ML_bits[mlCode]; DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", (unsigned)sequences[n].litLength, - (unsigned)sequences[n].mlBase + MINMATCH, - (unsigned)sequences[n].offBase); + (unsigned)sequences[n].matchLength + MINMATCH, + (unsigned)sequences[n].offset); /* 32b*/ /* 64b*/ /* (7)*/ /* (7)*/ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ @@ -352,18 +324,18 @@ ZSTD_encodeSequences_body( BIT_flushBits(&blockStream); /* (7)*/ BIT_addBits(&blockStream, sequences[n].litLength, llBits); if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[n].mlBase, mlBits); + BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); if (longOffsets) { - unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); + int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[n].offBase, extraBits); + BIT_addBits(&blockStream, sequences[n].offset, extraBits); BIT_flushBits(&blockStream); /* (7)*/ } - BIT_addBits(&blockStream, sequences[n].offBase >> extraBits, + BIT_addBits(&blockStream, sequences[n].offset >> extraBits, ofBits - extraBits); /* 31 */ } else { - BIT_addBits(&blockStream, sequences[n].offBase, ofBits); /* 31 */ + BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ } BIT_flushBits(&blockStream); /* (7)*/ DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr)); @@ -400,7 +372,7 @@ ZSTD_encodeSequences_default( #if DYNAMIC_BMI2 -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t ZSTD_encodeSequences_bmi2( void* dst, size_t dstCapacity, FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, @@ -441,5 +413,3 @@ size_t ZSTD_encodeSequences( CTable_LitLength, llCodeTable, sequences, nbSeq, longOffsets); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_sequences.h b/vendor/github.com/DataDog/zstd/zstd_compress_sequences.h index d3d2a4d7..57e8e367 100644 --- a/vendor/github.com/DataDog/zstd/zstd_compress_sequences.h +++ b/vendor/github.com/DataDog/zstd/zstd_compress_sequences.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -45,13 +44,4 @@ size_t ZSTD_encodeSequences( FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2); -size_t ZSTD_fseBitCost( - FSE_CTable const* ctable, - unsigned const* count, - unsigned const max); - -size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, - unsigned const* count, unsigned const max); #endif /* ZSTD_COMPRESS_SEQUENCES_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_superblock.c b/vendor/github.com/DataDog/zstd/zstd_compress_superblock.c deleted file mode 100644 index 61302a4b..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_compress_superblock.c +++ /dev/null @@ -1,580 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - /*-************************************* - * Dependencies - ***************************************/ -#include "zstd_compress_superblock.h" - -#include "zstd_internal.h" /* ZSTD_getSequenceLength */ -#include "hist.h" /* HIST_countFast_wksp */ -#include "zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */ -#include "zstd_compress_sequences.h" -#include "zstd_compress_literals.h" - -/** ZSTD_compressSubBlock_literal() : - * Compresses literals section for a sub-block. - * When we have to write the Huffman table we will sometimes choose a header - * size larger than necessary. This is because we have to pick the header size - * before we know the table size + compressed size, so we have a bound on the - * table size. If we guessed incorrectly, we fall back to uncompressed literals. - * - * We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded - * in writing the header, otherwise it is set to 0. - * - * hufMetadata->hType has literals block type info. - * If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block. - * If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block. - * If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block - * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block - * and the following sub-blocks' literals sections will be Treeless_Literals_Block. - * @return : compressed size of literals section of a sub-block - * Or 0 if unable to compress. - * Or error code */ -static size_t -ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, - const ZSTD_hufCTablesMetadata_t* hufMetadata, - const BYTE* literals, size_t litSize, - void* dst, size_t dstSize, - const int bmi2, int writeEntropy, int* entropyWritten) -{ - size_t const header = writeEntropy ? 200 : 0; - size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header)); - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ostart + dstSize; - BYTE* op = ostart + lhSize; - U32 const singleStream = lhSize == 3; - symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat; - size_t cLitSize = 0; - - DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy); - - *entropyWritten = 0; - if (litSize == 0 || hufMetadata->hType == set_basic) { - DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal"); - return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); - } else if (hufMetadata->hType == set_rle) { - DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal"); - return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize); - } - - assert(litSize > 0); - assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat); - - if (writeEntropy && hufMetadata->hType == set_compressed) { - ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); - op += hufMetadata->hufDesSize; - cLitSize += hufMetadata->hufDesSize; - DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize); - } - - { int const flags = bmi2 ? HUF_flags_bmi2 : 0; - const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable, flags) - : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable, flags); - op += cSize; - cLitSize += cSize; - if (cSize == 0 || ERR_isError(cSize)) { - DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize)); - return 0; - } - /* If we expand and we aren't writing a header then emit uncompressed */ - if (!writeEntropy && cLitSize >= litSize) { - DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible"); - return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); - } - /* If we are writing headers then allow expansion that doesn't change our header size. */ - if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) { - assert(cLitSize > litSize); - DEBUGLOG(5, "Literals expanded beyond allowed header size"); - return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); - } - DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize); - } - - /* Build header */ - switch(lhSize) - { - case 3: /* 2 - 2 - 10 - 10 */ - { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); - MEM_writeLE24(ostart, lhc); - break; - } - case 4: /* 2 - 2 - 14 - 14 */ - { U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18); - MEM_writeLE32(ostart, lhc); - break; - } - case 5: /* 2 - 2 - 18 - 18 */ - { U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22); - MEM_writeLE32(ostart, lhc); - ostart[4] = (BYTE)(cLitSize >> 10); - break; - } - default: /* not possible : lhSize is {3,4,5} */ - assert(0); - } - *entropyWritten = 1; - DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); - return op-ostart; -} - -static size_t -ZSTD_seqDecompressedSize(seqStore_t const* seqStore, - const seqDef* sequences, size_t nbSeq, - size_t litSize, int lastSequence) -{ - const seqDef* const sstart = sequences; - const seqDef* const send = sequences + nbSeq; - const seqDef* sp = sstart; - size_t matchLengthSum = 0; - size_t litLengthSum = 0; - (void)(litLengthSum); /* suppress unused variable warning on some environments */ - while (send-sp > 0) { - ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); - litLengthSum += seqLen.litLength; - matchLengthSum += seqLen.matchLength; - sp++; - } - assert(litLengthSum <= litSize); - if (!lastSequence) { - assert(litLengthSum == litSize); - } - return matchLengthSum + litSize; -} - -/** ZSTD_compressSubBlock_sequences() : - * Compresses sequences section for a sub-block. - * fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have - * symbol compression modes for the super-block. - * The first successfully compressed block will have these in its header. - * We set entropyWritten=1 when we succeed in compressing the sequences. - * The following sub-blocks will always have repeat mode. - * @return : compressed size of sequences section of a sub-block - * Or 0 if it is unable to compress - * Or error code. */ -static size_t -ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, - const ZSTD_fseCTablesMetadata_t* fseMetadata, - const seqDef* sequences, size_t nbSeq, - const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - const int bmi2, int writeEntropy, int* entropyWritten) -{ - const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ostart + dstCapacity; - BYTE* op = ostart; - BYTE* seqHead; - - DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets); - - *entropyWritten = 0; - /* Sequences Header */ - RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, - dstSize_tooSmall, ""); - if (nbSeq < 0x7F) - *op++ = (BYTE)nbSeq; - else if (nbSeq < LONGNBSEQ) - op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; - else - op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; - if (nbSeq==0) { - return op - ostart; - } - - /* seqHead : flags for FSE encoding type */ - seqHead = op++; - - DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart)); - - if (writeEntropy) { - const U32 LLtype = fseMetadata->llType; - const U32 Offtype = fseMetadata->ofType; - const U32 MLtype = fseMetadata->mlType; - DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize); - *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); - ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); - op += fseMetadata->fseTablesSize; - } else { - const U32 repeat = set_repeat; - *seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2)); - } - - { size_t const bitstreamSize = ZSTD_encodeSequences( - op, oend - op, - fseTables->matchlengthCTable, mlCode, - fseTables->offcodeCTable, ofCode, - fseTables->litlengthCTable, llCode, - sequences, nbSeq, - longOffsets, bmi2); - FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); - op += bitstreamSize; - /* zstd versions <= 1.3.4 mistakenly report corruption when - * FSE_readNCount() receives a buffer < 4 bytes. - * Fixed by https://github.com/facebook/zstd/pull/1146. - * This can happen when the last set_compressed table present is 2 - * bytes and the bitstream is only one byte. - * In this exceedingly rare case, we will simply emit an uncompressed - * block, since it isn't worth optimizing. - */ -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) { - /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ - assert(fseMetadata->lastCountSize + bitstreamSize == 3); - DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " - "emitting an uncompressed block."); - return 0; - } -#endif - DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize); - } - - /* zstd versions <= 1.4.0 mistakenly report error when - * sequences section body size is less than 3 bytes. - * Fixed by https://github.com/facebook/zstd/pull/1664. - * This can happen when the previous sequences section block is compressed - * with rle mode and the current block's sequences section is compressed - * with repeat mode where sequences section body size can be 1 byte. - */ -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (op-seqHead < 4) { - DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting " - "an uncompressed block when sequences are < 4 bytes"); - return 0; - } -#endif - - *entropyWritten = 1; - return op - ostart; -} - -/** ZSTD_compressSubBlock() : - * Compresses a single sub-block. - * @return : compressed size of the sub-block - * Or 0 if it failed to compress. */ -static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, - const ZSTD_entropyCTablesMetadata_t* entropyMetadata, - const seqDef* sequences, size_t nbSeq, - const BYTE* literals, size_t litSize, - const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - const int bmi2, - int writeLitEntropy, int writeSeqEntropy, - int* litEntropyWritten, int* seqEntropyWritten, - U32 lastBlock) -{ - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ostart + dstCapacity; - BYTE* op = ostart + ZSTD_blockHeaderSize; - DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)", - litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); - { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, - &entropyMetadata->hufMetadata, literals, litSize, - op, oend-op, bmi2, writeLitEntropy, litEntropyWritten); - FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed"); - if (cLitSize == 0) return 0; - op += cLitSize; - } - { size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse, - &entropyMetadata->fseMetadata, - sequences, nbSeq, - llCode, mlCode, ofCode, - cctxParams, - op, oend-op, - bmi2, writeSeqEntropy, seqEntropyWritten); - FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); - if (cSeqSize == 0) return 0; - op += cSeqSize; - } - /* Write block header */ - { size_t cSize = (op-ostart)-ZSTD_blockHeaderSize; - U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); - MEM_writeLE24(ostart, cBlockHeader24); - } - return op-ostart; -} - -static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, - const ZSTD_hufCTables_t* huf, - const ZSTD_hufCTablesMetadata_t* hufMetadata, - void* workspace, size_t wkspSize, - int writeEntropy) -{ - unsigned* const countWksp = (unsigned*)workspace; - unsigned maxSymbolValue = 255; - size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ - - if (hufMetadata->hType == set_basic) return litSize; - else if (hufMetadata->hType == set_rle) return 1; - else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { - size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); - if (ZSTD_isError(largest)) return litSize; - { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); - if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; - return cLitSizeEstimate + literalSectionHeaderSize; - } } - assert(0); /* impossible */ - return 0; -} - -static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, - const BYTE* codeTable, unsigned maxCode, - size_t nbSeq, const FSE_CTable* fseCTable, - const U8* additionalBits, - short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, - void* workspace, size_t wkspSize) -{ - unsigned* const countWksp = (unsigned*)workspace; - const BYTE* ctp = codeTable; - const BYTE* const ctStart = ctp; - const BYTE* const ctEnd = ctStart + nbSeq; - size_t cSymbolTypeSizeEstimateInBits = 0; - unsigned max = maxCode; - - HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ - if (type == set_basic) { - /* We selected this encoding type, so it must be valid. */ - assert(max <= defaultMax); - cSymbolTypeSizeEstimateInBits = max <= defaultMax - ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max) - : ERROR(GENERIC); - } else if (type == set_rle) { - cSymbolTypeSizeEstimateInBits = 0; - } else if (type == set_compressed || type == set_repeat) { - cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); - } - if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10; - while (ctp < ctEnd) { - if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; - else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ - ctp++; - } - return cSymbolTypeSizeEstimateInBits / 8; -} - -static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable, - const BYTE* llCodeTable, - const BYTE* mlCodeTable, - size_t nbSeq, - const ZSTD_fseCTables_t* fseTables, - const ZSTD_fseCTablesMetadata_t* fseMetadata, - void* workspace, size_t wkspSize, - int writeEntropy) -{ - size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ - size_t cSeqSizeEstimate = 0; - if (nbSeq == 0) return sequencesSectionHeaderSize; - cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff, - nbSeq, fseTables->offcodeCTable, NULL, - OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, - workspace, wkspSize); - cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL, - nbSeq, fseTables->litlengthCTable, LL_bits, - LL_defaultNorm, LL_defaultNormLog, MaxLL, - workspace, wkspSize); - cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML, - nbSeq, fseTables->matchlengthCTable, ML_bits, - ML_defaultNorm, ML_defaultNormLog, MaxML, - workspace, wkspSize); - if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; - return cSeqSizeEstimate + sequencesSectionHeaderSize; -} - -static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, - const BYTE* ofCodeTable, - const BYTE* llCodeTable, - const BYTE* mlCodeTable, - size_t nbSeq, - const ZSTD_entropyCTables_t* entropy, - const ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize, - int writeLitEntropy, int writeSeqEntropy) { - size_t cSizeEstimate = 0; - cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize, - &entropy->huf, &entropyMetadata->hufMetadata, - workspace, wkspSize, writeLitEntropy); - cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, - nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, - workspace, wkspSize, writeSeqEntropy); - return cSizeEstimate + ZSTD_blockHeaderSize; -} - -static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) -{ - if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle) - return 1; - if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle) - return 1; - if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle) - return 1; - return 0; -} - -/** ZSTD_compressSubBlock_multi() : - * Breaks super-block into multiple sub-blocks and compresses them. - * Entropy will be written to the first block. - * The following blocks will use repeat mode to compress. - * All sub-blocks are compressed blocks (no raw or rle blocks). - * @return : compressed size of the super block (which is multiple ZSTD blocks) - * Or 0 if it failed to compress. */ -static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, - const ZSTD_compressedBlockState_t* prevCBlock, - ZSTD_compressedBlockState_t* nextCBlock, - const ZSTD_entropyCTablesMetadata_t* entropyMetadata, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const int bmi2, U32 lastBlock, - void* workspace, size_t wkspSize) -{ - const seqDef* const sstart = seqStorePtr->sequencesStart; - const seqDef* const send = seqStorePtr->sequences; - const seqDef* sp = sstart; - const BYTE* const lstart = seqStorePtr->litStart; - const BYTE* const lend = seqStorePtr->lit; - const BYTE* lp = lstart; - BYTE const* ip = (BYTE const*)src; - BYTE const* const iend = ip + srcSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ostart + dstCapacity; - BYTE* op = ostart; - const BYTE* llCodePtr = seqStorePtr->llCode; - const BYTE* mlCodePtr = seqStorePtr->mlCode; - const BYTE* ofCodePtr = seqStorePtr->ofCode; - size_t targetCBlockSize = cctxParams->targetCBlockSize; - size_t litSize, seqCount; - int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed; - int writeSeqEntropy = 1; - int lastSequence = 0; - - DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)", - (unsigned)(lend-lp), (unsigned)(send-sstart)); - - litSize = 0; - seqCount = 0; - do { - size_t cBlockSizeEstimate = 0; - if (sstart == send) { - lastSequence = 1; - } else { - const seqDef* const sequence = sp + seqCount; - lastSequence = sequence == send - 1; - litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength; - seqCount++; - } - if (lastSequence) { - assert(lp <= lend); - assert(litSize <= (size_t)(lend - lp)); - litSize = (size_t)(lend - lp); - } - /* I think there is an optimization opportunity here. - * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful - * since it recalculates estimate from scratch. - * For example, it would recount literal distribution and symbol codes every time. - */ - cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount, - &nextCBlock->entropy, entropyMetadata, - workspace, wkspSize, writeLitEntropy, writeSeqEntropy); - if (cBlockSizeEstimate > targetCBlockSize || lastSequence) { - int litEntropyWritten = 0; - int seqEntropyWritten = 0; - const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence); - const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, - sp, seqCount, - lp, litSize, - llCodePtr, mlCodePtr, ofCodePtr, - cctxParams, - op, oend-op, - bmi2, writeLitEntropy, writeSeqEntropy, - &litEntropyWritten, &seqEntropyWritten, - lastBlock && lastSequence); - FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); - if (cSize > 0 && cSize < decompressedSize) { - DEBUGLOG(5, "Committed the sub-block"); - assert(ip + decompressedSize <= iend); - ip += decompressedSize; - sp += seqCount; - lp += litSize; - op += cSize; - llCodePtr += seqCount; - mlCodePtr += seqCount; - ofCodePtr += seqCount; - litSize = 0; - seqCount = 0; - /* Entropy only needs to be written once */ - if (litEntropyWritten) { - writeLitEntropy = 0; - } - if (seqEntropyWritten) { - writeSeqEntropy = 0; - } - } - } - } while (!lastSequence); - if (writeLitEntropy) { - DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten"); - ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); - } - if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { - /* If we haven't written our entropy tables, then we've violated our contract and - * must emit an uncompressed block. - */ - DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten"); - return 0; - } - if (ip < iend) { - size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock); - DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip)); - FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); - assert(cSize != 0); - op += cSize; - /* We have to regenerate the repcodes because we've skipped some sequences */ - if (sp < send) { - seqDef const* seq; - repcodes_t rep; - ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep)); - for (seq = sstart; seq < sp; ++seq) { - ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); - } - ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep)); - } - } - DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed"); - return op-ostart; -} - -size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - void const* src, size_t srcSize, - unsigned lastBlock) { - ZSTD_entropyCTablesMetadata_t entropyMetadata; - - FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore, - &zc->blockState.prevCBlock->entropy, - &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - &entropyMetadata, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); - - return ZSTD_compressSubBlock_multi(&zc->seqStore, - zc->blockState.prevCBlock, - zc->blockState.nextCBlock, - &entropyMetadata, - &zc->appliedParams, - dst, dstCapacity, - src, srcSize, - zc->bmi2, lastBlock, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */); -} - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_compress_superblock.h b/vendor/github.com/DataDog/zstd/zstd_compress_superblock.h deleted file mode 100644 index fdc4b165..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_compress_superblock.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_COMPRESS_ADVANCED_H -#define ZSTD_COMPRESS_ADVANCED_H - -/*-************************************* -* Dependencies -***************************************/ - -#include "zstd.h" /* ZSTD_CCtx */ - -/*-************************************* -* Target Compressed Block Size -***************************************/ - -/* ZSTD_compressSuperBlock() : - * Used to compress a super block when targetCBlockSize is being used. - * The given block will be compressed into multiple sub blocks that are around targetCBlockSize. */ -size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - void const* src, size_t srcSize, - unsigned lastBlock); - -#endif /* ZSTD_COMPRESS_ADVANCED_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_ctx.go b/vendor/github.com/DataDog/zstd/zstd_ctx.go deleted file mode 100644 index 46c19767..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_ctx.go +++ /dev/null @@ -1,131 +0,0 @@ -package zstd - -/* -#include "zstd.h" -*/ -import "C" -import ( - "bytes" - "io/ioutil" - "runtime" - "unsafe" -) - -type Ctx interface { - // Compress src into dst. If you have a buffer to use, you can pass it to - // prevent allocation. If it is too small, or if nil is passed, a new buffer - // will be allocated and returned. - Compress(dst, src []byte) ([]byte, error) - - // CompressLevel is the same as Compress but you can pass a compression level - CompressLevel(dst, src []byte, level int) ([]byte, error) - - // Decompress src into dst. If you have a buffer to use, you can pass it to - // prevent allocation. If it is too small, or if nil is passed, a new buffer - // will be allocated and returned. - Decompress(dst, src []byte) ([]byte, error) -} - -type ctx struct { - cctx *C.ZSTD_CCtx - dctx *C.ZSTD_DCtx -} - -// Create a new ZStd Context. -// When compressing/decompressing many times, it is recommended to allocate a -// context just once, and re-use it for each successive compression operation. -// This will make workload friendlier for system's memory. -// Note : re-using context is just a speed / resource optimization. -// It doesn't change the compression ratio, which remains identical. -// Note 2 : In multi-threaded environments, -// use one different context per thread for parallel execution. -// -func NewCtx() Ctx { - c := &ctx{ - cctx: C.ZSTD_createCCtx(), - dctx: C.ZSTD_createDCtx(), - } - - runtime.SetFinalizer(c, finalizeCtx) - return c -} - -func (c *ctx) Compress(dst, src []byte) ([]byte, error) { - return c.CompressLevel(dst, src, DefaultCompression) -} - -func (c *ctx) CompressLevel(dst, src []byte, level int) ([]byte, error) { - bound := CompressBound(len(src)) - if cap(dst) >= bound { - dst = dst[0:bound] // Reuse dst buffer - } else { - dst = make([]byte, bound) - } - - // We need unsafe.Pointer(&src[0]) in the Cgo call to avoid "Go pointer to Go pointer" panics. - // This means we need to special case empty input. See: - // https://github.com/golang/go/issues/14210#issuecomment-346402945 - var cWritten C.size_t - if len(src) == 0 { - cWritten = C.ZSTD_compressCCtx( - c.cctx, - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(nil), - C.size_t(0), - C.int(level)) - } else { - cWritten = C.ZSTD_compressCCtx( - c.cctx, - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(&src[0]), - C.size_t(len(src)), - C.int(level)) - } - - written := int(cWritten) - // Check if the return is an Error code - if err := getError(written); err != nil { - return nil, err - } - return dst[:written], nil -} - -func (c *ctx) Decompress(dst, src []byte) ([]byte, error) { - if len(src) == 0 { - return []byte{}, ErrEmptySlice - } - - bound := decompressSizeHint(src) - if cap(dst) >= bound { - dst = dst[0:cap(dst)] - } else { - dst = make([]byte, bound) - } - - written := int(C.ZSTD_decompressDCtx( - c.dctx, - unsafe.Pointer(&dst[0]), - C.size_t(len(dst)), - unsafe.Pointer(&src[0]), - C.size_t(len(src)))) - - err := getError(written) - if err == nil { - return dst[:written], nil - } - if !IsDstSizeTooSmallError(err) { - return nil, err - } - - // We failed getting a dst buffer of correct size, use stream API - r := NewReader(bytes.NewReader(src)) - defer r.Close() - return ioutil.ReadAll(r) -} - -func finalizeCtx(c *ctx) { - C.ZSTD_freeCCtx(c.cctx) - C.ZSTD_freeDCtx(c.dctx) -} diff --git a/vendor/github.com/DataDog/zstd/zstd_cwksp.h b/vendor/github.com/DataDog/zstd/zstd_cwksp.h index a2746c53..fc9765bd 100644 --- a/vendor/github.com/DataDog/zstd/zstd_cwksp.h +++ b/vendor/github.com/DataDog/zstd/zstd_cwksp.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,9 +14,7 @@ /*-************************************* * Dependencies ***************************************/ -#include "allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ #include "zstd_internal.h" -#include "portability_macros.h" #if defined (__cplusplus) extern "C" { @@ -27,6 +24,16 @@ extern "C" { * Constants ***************************************/ +/* define "workspace is too large" as this number of times larger than needed */ +#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 + +/* when workspace is continuously too large + * during at least this number of times, + * context's memory usage is considered wasteful, + * because it's sized to handle a worst case scenario which rarely happens. + * In which case, resize it down to free some memory */ +#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 + /* Since the workspace is effectively its own little malloc implementation / * arena, when we run under ASAN, we should similarly insert redzones between * each internal element of the workspace, so ASAN will catch overruns that @@ -38,30 +45,15 @@ extern "C" { #define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128 #endif - -/* Set our tables and aligneds to align by 64 bytes */ -#define ZSTD_CWKSP_ALIGNMENT_BYTES 64 - /*-************************************* * Structures ***************************************/ typedef enum { ZSTD_cwksp_alloc_objects, - ZSTD_cwksp_alloc_aligned_init_once, - ZSTD_cwksp_alloc_aligned, - ZSTD_cwksp_alloc_buffers + ZSTD_cwksp_alloc_buffers, + ZSTD_cwksp_alloc_aligned } ZSTD_cwksp_alloc_phase_e; -/** - * Used to describe whether the workspace is statically allocated (and will not - * necessarily ever be freed), or if it's dynamically allocated and we can - * expect a well-formed caller to free this. - */ -typedef enum { - ZSTD_cwksp_dynamic_alloc, - ZSTD_cwksp_static_alloc -} ZSTD_cwksp_static_alloc_e; - /** * Zstd fits all its internal datastructures into a single continuous buffer, * so that it only needs to perform a single OS allocation (or so that a buffer @@ -102,15 +94,15 @@ typedef enum { * * Workspace Layout: * - * [ ... workspace ... ] - * [objects][tables ->] free space [<- buffers][<- aligned][<- init once] + * [ ... workspace ... ] + * [objects][tables ... ->] free space [<- ... aligned][<- ... buffers] * * The various objects that live in the workspace are divided into the * following categories, and are allocated separately: * * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict, * so that literally everything fits in a single buffer. Note: if present, - * this must be the first object in the workspace, since ZSTD_customFree{CCtx, + * this must be the first object in the workspace, since ZSTD_free{CCtx, * CDict}() rely on a pointer comparison to see whether one or two frees are * required. * @@ -125,20 +117,10 @@ typedef enum { * - Tables: these are any of several different datastructures (hash tables, * chain tables, binary trees) that all respect a common format: they are * uint32_t arrays, all of whose values are between 0 and (nextSrc - base). - * Their sizes depend on the cparams. These tables are 64-byte aligned. - * - * - Init once: these buffers require to be initialized at least once before - * use. They should be used when we want to skip memory initialization - * while not triggering memory checkers (like Valgrind) when reading from - * from this memory without writing to it first. - * These buffers should be used carefully as they might contain data - * from previous compressions. - * Buffers are aligned to 64 bytes. + * Their sizes depend on the cparams. * - * - Aligned: these buffers don't require any initialization before they're - * used. The user of the buffer should make sure they write into a buffer - * location before reading from it. - * Buffers are aligned to 64 bytes. + * - Aligned: these buffers are used for various purposes that require 4 byte + * alignment, but don't require any initialization before they're used. * * - Buffers: these buffers are used for various purposes that don't require * any alignment or initialization before they're used. This means they can @@ -150,9 +132,9 @@ typedef enum { * correctly packed into the workspace buffer. That order is: * * 1. Objects - * 2. Init once / Tables - * 3. Aligned / Tables - * 4. Buffers / Tables + * 2. Buffers + * 3. Aligned + * 4. Tables * * Attempts to reserve objects of different types out of order will fail. */ @@ -164,12 +146,10 @@ typedef struct { void* tableEnd; void* tableValidEnd; void* allocStart; - void* initOnceStart; - BYTE allocFailed; + int allocFailed; int workspaceOversizedDuration; ZSTD_cwksp_alloc_phase_e phase; - ZSTD_cwksp_static_alloc_e isStatic; } ZSTD_cwksp; /*-************************************* @@ -177,7 +157,6 @@ typedef struct { ***************************************/ MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws); -MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws); MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) { (void)ws; @@ -187,20 +166,6 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) { assert(ws->tableEnd <= ws->allocStart); assert(ws->tableValidEnd <= ws->allocStart); assert(ws->allocStart <= ws->workspaceEnd); - assert(ws->initOnceStart <= ZSTD_cwksp_initialAllocStart(ws)); - assert(ws->workspace <= ws->initOnceStart); -#if ZSTD_MEMORY_SANITIZER - { - intptr_t const offset = __msan_test_shadow(ws->initOnceStart, - (U8*)ZSTD_cwksp_initialAllocStart(ws) - (U8*)ws->initOnceStart); -#if defined(ZSTD_MSAN_PRINT) - if(offset!=-1) { - __msan_print_shadow((U8*)ws->initOnceStart + offset - 8, 32); - } -#endif - assert(offset==-1); - }; -#endif } /** @@ -221,72 +186,63 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) { * Since tables aren't currently redzoned, you don't need to call through this * to figure out how much space you need for the matchState tables. Everything * else is though. - * - * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size(). */ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) { - if (size == 0) - return 0; -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; #else return size; #endif } -/** - * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes. - * Used to determine the number of bytes required for a given "aligned". - */ -MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) { - return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES)); +MEM_STATIC void ZSTD_cwksp_internal_advance_phase( + ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) { + assert(phase >= ws->phase); + if (phase > ws->phase) { + if (ws->phase < ZSTD_cwksp_alloc_buffers && + phase >= ZSTD_cwksp_alloc_buffers) { + ws->tableValidEnd = ws->objectEnd; + } + if (ws->phase < ZSTD_cwksp_alloc_aligned && + phase >= ZSTD_cwksp_alloc_aligned) { + /* If unaligned allocations down from a too-large top have left us + * unaligned, we need to realign our alloc ptr. Technically, this + * can consume space that is unaccounted for in the neededSpace + * calculation. However, I believe this can only happen when the + * workspace is too large, and specifically when it is too large + * by a larger margin than the space that will be consumed. */ + /* TODO: cleaner, compiler warning friendly way to do this??? */ + ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1)); + if (ws->allocStart < ws->tableValidEnd) { + ws->tableValidEnd = ws->allocStart; + } + } + ws->phase = phase; + } } /** - * Returns the amount of additional space the cwksp must allocate - * for internal purposes (currently only alignment). + * Returns whether this object/buffer/etc was allocated in this workspace. */ -MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) { - /* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES - * bytes to align the beginning of tables section and end of buffers; - */ - size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2; - return slackSpace; +MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) { + return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd); } - /** - * Return the number of additional bytes required to align a pointer to the given number of bytes. - * alignBytes must be a power of two. + * Internal function. Do not use directly. */ -MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) { - size_t const alignBytesMask = alignBytes - 1; - size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask; - assert((alignBytes & alignBytesMask) == 0); - assert(bytes < alignBytes); - return bytes; -} +MEM_STATIC void* ZSTD_cwksp_reserve_internal( + ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) { + void* alloc; + void* bottom = ws->tableEnd; + ZSTD_cwksp_internal_advance_phase(ws, phase); + alloc = (BYTE *)ws->allocStart - bytes; -/** - * Returns the initial value for allocStart which is used to determine the position from - * which we can allocate from the end of the workspace. - */ -MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws) { - return (void*)((size_t)ws->workspaceEnd & ~(ZSTD_CWKSP_ALIGNMENT_BYTES-1)); -} +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* over-reserve space */ + alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; +#endif -/** - * Internal function. Do not use directly. - * Reserves the given number of bytes within the aligned/buffer segment of the wksp, - * which counts from the end of the wksp (as opposed to the object/table segment). - * - * Returns a pointer to the beginning of that space. - */ -MEM_STATIC void* -ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) -{ - void* const alloc = (BYTE*)ws->allocStart - bytes; - void* const bottom = ws->tableEnd; DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); ZSTD_cwksp_assert_internal_consistency(ws); @@ -296,88 +252,16 @@ ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) ws->allocFailed = 1; return NULL; } - /* the area is reserved from the end of wksp. - * If it overlaps with tableValidEnd, it voids guarantees on values' range */ if (alloc < ws->tableValidEnd) { ws->tableValidEnd = alloc; } ws->allocStart = alloc; - return alloc; -} -/** - * Moves the cwksp to the next phase, and does any necessary allocations. - * cwksp initialization must necessarily go through each phase in order. - * Returns a 0 on success, or zstd error - */ -MEM_STATIC size_t -ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) -{ - assert(phase >= ws->phase); - if (phase > ws->phase) { - /* Going from allocating objects to allocating initOnce / tables */ - if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once && - phase >= ZSTD_cwksp_alloc_aligned_init_once) { - ws->tableValidEnd = ws->objectEnd; - ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws); - - { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */ - void *const alloc = ws->objectEnd; - size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES); - void *const objectEnd = (BYTE *) alloc + bytesToAlign; - DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign); - RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation, - "table phase - alignment initial allocation failed!"); - ws->objectEnd = objectEnd; - ws->tableEnd = objectEnd; /* table area starts being empty */ - if (ws->tableValidEnd < ws->tableEnd) { - ws->tableValidEnd = ws->tableEnd; - } - } - } - ws->phase = phase; - ZSTD_cwksp_assert_internal_consistency(ws); - } - return 0; -} - -/** - * Returns whether this object/buffer/etc was allocated in this workspace. - */ -MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) -{ - return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd); -} - -/** - * Internal function. Do not use directly. - */ -MEM_STATIC void* -ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) -{ - void* alloc; - if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) { - return NULL; - } - -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* over-reserve space */ - bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; -#endif - - alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes); - -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on * either size. */ - if (alloc) { - alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; - if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { - /* We need to keep the redzone poisoned while unpoisoning the bytes that - * are actually allocated. */ - __asan_unpoison_memory_region(alloc, bytes - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE); - } - } + alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; + __asan_unpoison_memory_region(alloc, bytes); #endif return alloc; @@ -386,78 +270,33 @@ ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase /** * Reserves and returns unaligned memory. */ -MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) -{ +MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) { return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers); } /** - * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). - * This memory has been initialized at least once in the past. - * This doesn't mean it has been initialized this time, and it might contain data from previous - * operations. - * The main usage is for algorithms that might need read access into uninitialized memory. - * The algorithm must maintain safety under these conditions and must make sure it doesn't - * leak any of the past data (directly or in side channels). + * Reserves and returns memory sized on and aligned on sizeof(unsigned). */ -MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes) -{ - size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES); - void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once); - assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); - if(ptr && ptr < ws->initOnceStart) { - /* We assume the memory following the current allocation is either: - * 1. Not usable as initOnce memory (end of workspace) - * 2. Another initOnce buffer that has been allocated before (and so was previously memset) - * 3. An ASAN redzone, in which case we don't want to write on it - * For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart. - * Note that we assume here that MSAN and ASAN cannot run in the same time. */ - ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes)); - ws->initOnceStart = ptr; - } -#if ZSTD_MEMORY_SANITIZER - assert(__msan_test_shadow(ptr, bytes) == -1); -#endif - return ptr; -} - -/** - * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). - */ -MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) -{ - void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES), - ZSTD_cwksp_alloc_aligned); - assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); - return ptr; +MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) { + assert((bytes & (sizeof(U32)-1)) == 0); + return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned); } /** - * Aligned on 64 bytes. These buffers have the special property that + * Aligned on sizeof(unsigned). These buffers have the special property that * their values remain constrained, allowing us to re-use them without * memset()-ing them. */ -MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) -{ - const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once; - void* alloc; - void* end; - void* top; - - /* We can only start allocating tables after we are done reserving space for objects at the - * start of the workspace */ - if(ws->phase < phase) { - if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) { - return NULL; - } - } - alloc = ws->tableEnd; - end = (BYTE *)alloc + bytes; - top = ws->allocStart; +MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) { + const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned; + void* alloc = ws->tableEnd; + void* end = (BYTE *)alloc + bytes; + void* top = ws->allocStart; DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); assert((bytes & (sizeof(U32)-1)) == 0); + ZSTD_cwksp_internal_advance_phase(ws, phase); ZSTD_cwksp_assert_internal_consistency(ws); assert(end <= top); if (end > top) { @@ -467,41 +306,35 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) } ws->tableEnd = end; -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { - __asan_unpoison_memory_region(alloc, bytes); - } +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + __asan_unpoison_memory_region(alloc, bytes); #endif - assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0); - assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); return alloc; } /** * Aligned on sizeof(void*). - * Note : should happen only once, at workspace first initialization */ -MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) -{ - size_t const roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); +MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) { + size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); void* alloc = ws->objectEnd; void* end = (BYTE*)alloc + roundedBytes; -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* over-reserve space */ end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; #endif - DEBUGLOG(4, + DEBUGLOG(5, "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining", alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes); - assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0); - assert(bytes % ZSTD_ALIGNOF(void*) == 0); + assert(((size_t)alloc & (sizeof(void*)-1)) == 0); + assert((bytes & (sizeof(void*)-1)) == 0); ZSTD_cwksp_assert_internal_consistency(ws); /* we must be in the first phase, no advance is possible */ if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) { - DEBUGLOG(3, "cwksp: object alloc failed!"); + DEBUGLOG(4, "cwksp: object alloc failed!"); ws->allocFailed = 1; return NULL; } @@ -509,38 +342,27 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) ws->tableEnd = end; ws->tableValidEnd = end; -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on * either size. */ - alloc = (BYTE*)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; - if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { - __asan_unpoison_memory_region(alloc, bytes); - } + alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; + __asan_unpoison_memory_region(alloc, bytes); #endif return alloc; } -MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) -{ +MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty"); -#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) +#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) /* To validate that the table re-use logic is sound, and that we don't * access table space that we haven't cleaned, we re-"poison" the table - * space every time we mark it dirty. - * Since tableValidEnd space and initOnce space may overlap we don't poison - * the initOnce portion as it break its promise. This means that this poisoning - * check isn't always applied fully. */ + * space every time we mark it dirty. */ { size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; assert(__msan_test_shadow(ws->objectEnd, size) == -1); - if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) { - __msan_poison(ws->objectEnd, size); - } else { - assert(ws->initOnceStart >= ws->objectEnd); - __msan_poison(ws->objectEnd, (BYTE*)ws->initOnceStart - (BYTE*)ws->objectEnd); - } + __msan_poison(ws->objectEnd, size); } #endif @@ -568,7 +390,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { assert(ws->tableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); if (ws->tableValidEnd < ws->tableEnd) { - ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd)); + memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd); } ZSTD_cwksp_mark_tables_clean(ws); } @@ -580,12 +402,8 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing tables!"); -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* We don't do this when the workspace is statically allocated, because - * when that is the case, we have no capability to hook into the end of the - * workspace's lifecycle to unpoison the memory. - */ - if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + { size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; __asan_poison_memory_region(ws->objectEnd, size); } @@ -602,36 +420,29 @@ MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing!"); -#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) +#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) /* To validate that the context re-use logic is sound, and that we don't * access stuff that this compression hasn't initialized, we re-"poison" - * the workspace except for the areas in which we expect memory re-use - * without initialization (objects, valid tables area and init once - * memory). */ + * the workspace (or at least the non-static, non-table parts of it) + * every time we start a new compression. */ { - if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) { - size_t size = (BYTE*)ws->initOnceStart - (BYTE*)ws->tableValidEnd; - __msan_poison(ws->tableValidEnd, size); - } + size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd; + __msan_poison(ws->tableValidEnd, size); } #endif -#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* We don't do this when the workspace is statically allocated, because - * when that is the case, we have no capability to hook into the end of the - * workspace's lifecycle to unpoison the memory. - */ - if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + { size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd; __asan_poison_memory_region(ws->objectEnd, size); } #endif ws->tableEnd = ws->objectEnd; - ws->allocStart = ZSTD_cwksp_initialAllocStart(ws); + ws->allocStart = ws->workspaceEnd; ws->allocFailed = 0; - if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) { - ws->phase = ZSTD_cwksp_alloc_aligned_init_once; + if (ws->phase > ZSTD_cwksp_alloc_buffers) { + ws->phase = ZSTD_cwksp_alloc_buffers; } ZSTD_cwksp_assert_internal_consistency(ws); } @@ -641,54 +452,47 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { * Any existing values in the workspace are ignored (the previously managed * buffer, if present, must be separately freed). */ -MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_cwksp_static_alloc_e isStatic) { +MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) { DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size); assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ ws->workspace = start; ws->workspaceEnd = (BYTE*)start + size; ws->objectEnd = ws->workspace; ws->tableValidEnd = ws->objectEnd; - ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws); ws->phase = ZSTD_cwksp_alloc_objects; - ws->isStatic = isStatic; ZSTD_cwksp_clear(ws); ws->workspaceOversizedDuration = 0; ZSTD_cwksp_assert_internal_consistency(ws); } MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) { - void* workspace = ZSTD_customMalloc(size, customMem); + void* workspace = ZSTD_malloc(size, customMem); DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size); - RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!"); - ZSTD_cwksp_init(ws, workspace, size, ZSTD_cwksp_dynamic_alloc); + RETURN_ERROR_IF(workspace == NULL, memory_allocation); + ZSTD_cwksp_init(ws, workspace, size); return 0; } MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) { void *ptr = ws->workspace; DEBUGLOG(4, "cwksp: freeing workspace"); - ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp)); - ZSTD_customFree(ptr, customMem); + memset(ws, 0, sizeof(ZSTD_cwksp)); + ZSTD_free(ptr, customMem); } /** * Moves the management of a workspace from one cwksp to another. The src cwksp - * is left in an invalid state (src must be re-init()'ed before it's used again). + * is left in an invalid state (src must be re-init()'ed before its used again). */ MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) { *dst = *src; - ZSTD_memset(src, 0, sizeof(ZSTD_cwksp)); + memset(src, 0, sizeof(ZSTD_cwksp)); } MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) { return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace); } -MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) { - return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace) - + (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart); -} - MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { return ws->allocFailed; } @@ -697,18 +501,6 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { * Functions Checking Free Space ***************************************/ -/* ZSTD_alignmentSpaceWithinBounds() : - * Returns if the estimated space needed for a wksp is within an acceptable limit of the - * actual amount of space used. - */ -MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) { - /* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice - * the alignment bytes difference between estimation and actual usage */ - return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) && - ZSTD_cwksp_used(ws) <= estimatedSpace; -} - - MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) { return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd); } @@ -741,5 +533,3 @@ MEM_STATIC void ZSTD_cwksp_bump_oversized_duration( #endif #endif /* ZSTD_CWKSP_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_ddict.c b/vendor/github.com/DataDog/zstd/zstd_ddict.c index c77a9df8..0af3d23b 100644 --- a/vendor/github.com/DataDog/zstd/zstd_ddict.c +++ b/vendor/github.com/DataDog/zstd/zstd_ddict.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,18 +14,18 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ -#include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include /* memcpy, memmove, memset */ #include "cpu.h" /* bmi2 */ #include "mem.h" /* low level memory routines */ #define FSE_STATIC_LINKING_ONLY #include "fse.h" +#define HUF_STATIC_LINKING_ONLY #include "huf.h" #include "zstd_decompress_internal.h" #include "zstd_ddict.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -#include "zstd_legacy.h" +# include "zstd_legacy.h" #endif @@ -66,10 +65,6 @@ void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) dctx->virtualStart = ddict->dictContent; dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize; dctx->previousDstEnd = dctx->dictEnd; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - dctx->dictContentBeginForFuzzing = dctx->prefixStart; - dctx->dictContentEndForFuzzing = dctx->previousDstEnd; -#endif if (ddict->entropyPresent) { dctx->litEntropy = 1; dctx->fseEntropy = 1; @@ -112,7 +107,7 @@ ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict, /* load entropy tables */ RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy( &ddict->entropy, ddict->dictContent, ddict->dictSize)), - dictionary_corrupted, ""); + dictionary_corrupted); ddict->entropyPresent = 1; return 0; } @@ -128,17 +123,17 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, ddict->dictContent = dict; if (!dict) dictSize = 0; } else { - void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); + void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem); ddict->dictBuffer = internalBuffer; ddict->dictContent = internalBuffer; if (!internalBuffer) return ERROR(memory_allocation); - ZSTD_memcpy(internalBuffer, dict, dictSize); + memcpy(internalBuffer, dict, dictSize); } ddict->dictSize = dictSize; - ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ + ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ /* parse dictionary content */ - FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); + FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) ); return 0; } @@ -148,9 +143,9 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem) { - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem); if (ddict == NULL) return NULL; ddict->cMem = customMem; { size_t const initResult = ZSTD_initDDict_internal(ddict, @@ -199,7 +194,7 @@ const ZSTD_DDict* ZSTD_initStaticDDict( if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ if (sBufferSize < neededSpace) return NULL; if (dictLoadMethod == ZSTD_dlm_byCopy) { - ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ + memcpy(ddict+1, dict, dictSize); /* local copy */ dict = ddict+1; } if (ZSTD_isError( ZSTD_initDDict_internal(ddict, @@ -214,8 +209,8 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) { if (ddict==NULL) return 0; /* support free on NULL */ { ZSTD_customMem const cMem = ddict->cMem; - ZSTD_customFree(ddict->dictBuffer, cMem); - ZSTD_customFree(ddict, cMem); + ZSTD_free(ddict->dictBuffer, cMem); + ZSTD_free(ddict, cMem); return 0; } } @@ -241,7 +236,5 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) { if (ddict==NULL) return 0; - return ddict->dictID; + return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_ddict.h b/vendor/github.com/DataDog/zstd/zstd_ddict.h index 97e432ef..0479d11b 100644 --- a/vendor/github.com/DataDog/zstd/zstd_ddict.h +++ b/vendor/github.com/DataDog/zstd/zstd_ddict.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,7 +15,7 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd_deps.h" /* size_t */ +#include /* size_t */ #include "zstd.h" /* ZSTD_DDict, and several public functions */ @@ -43,5 +42,3 @@ void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); #endif /* ZSTD_DDICT_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_decompress.c b/vendor/github.com/DataDog/zstd/zstd_decompress.c index d48e87be..dd4591b7 100644 --- a/vendor/github.com/DataDog/zstd/zstd_decompress.c +++ b/vendor/github.com/DataDog/zstd/zstd_decompress.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -56,165 +55,23 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include /* memcpy, memmove, memset */ +#include "cpu.h" /* bmi2 */ #include "mem.h" /* low level memory routines */ #define FSE_STATIC_LINKING_ONLY #include "fse.h" +#define HUF_STATIC_LINKING_ONLY #include "huf.h" -#include "xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ #include "zstd_internal.h" /* blockProperties_t */ #include "zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ -#include "bits.h" /* ZSTD_highbit32 */ #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -#include "zstd_legacy.h" +# include "zstd_legacy.h" #endif - -/************************************* - * Multiple DDicts Hashset internals * - *************************************/ - -#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 -#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. - * Currently, that means a 0.75 load factor. - * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded - * the load factor of the ddict hash set. - */ - -#define DDICT_HASHSET_TABLE_BASE_SIZE 64 -#define DDICT_HASHSET_RESIZE_FACTOR 2 - -/* Hash function to determine starting position of dict insertion within the table - * Returns an index between [0, hashSet->ddictPtrTableSize] - */ -static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { - const U64 hash = XXH64(&dictID, sizeof(U32), 0); - /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ - return hash & (hashSet->ddictPtrTableSize - 1); -} - -/* Adds DDict to a hashset without resizing it. - * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. - * Returns 0 if successful, or a zstd error code if something went wrong. - */ -static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { - const U32 dictID = ZSTD_getDictID_fromDDict(ddict); - size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); - const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; - RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); - DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); - while (hashSet->ddictPtrTable[idx] != NULL) { - /* Replace existing ddict if inserting ddict with same dictID */ - if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { - DEBUGLOG(4, "DictID already exists, replacing rather than adding"); - hashSet->ddictPtrTable[idx] = ddict; - return 0; - } - idx &= idxRangeMask; - idx++; - } - DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); - hashSet->ddictPtrTable[idx] = ddict; - hashSet->ddictPtrCount++; - return 0; -} - -/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and - * rehashes all values, allocates new table, frees old table. - * Returns 0 on success, otherwise a zstd error code. - */ -static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { - size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; - const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); - const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; - size_t oldTableSize = hashSet->ddictPtrTableSize; - size_t i; - - DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); - RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); - hashSet->ddictPtrTable = newTable; - hashSet->ddictPtrTableSize = newTableSize; - hashSet->ddictPtrCount = 0; - for (i = 0; i < oldTableSize; ++i) { - if (oldTable[i] != NULL) { - FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); - } - } - ZSTD_customFree((void*)oldTable, customMem); - DEBUGLOG(4, "Finished re-hash"); - return 0; -} - -/* Fetches a DDict with the given dictID - * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. - */ -static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { - size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); - const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; - DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); - for (;;) { - size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); - if (currDictID == dictID || currDictID == 0) { - /* currDictID == 0 implies a NULL ddict entry */ - break; - } else { - idx &= idxRangeMask; /* Goes to start of table when we reach the end */ - idx++; - } - } - DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); - return hashSet->ddictPtrTable[idx]; -} - -/* Allocates space for and returns a ddict hash set - * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. - * Returns NULL if allocation failed. - */ -static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { - ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); - DEBUGLOG(4, "Allocating new hash set"); - if (!ret) - return NULL; - ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); - if (!ret->ddictPtrTable) { - ZSTD_customFree(ret, customMem); - return NULL; - } - ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; - ret->ddictPtrCount = 0; - return ret; -} - -/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. - * Note: The ZSTD_DDict* within the table are NOT freed. - */ -static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { - DEBUGLOG(4, "Freeing ddict hash set"); - if (hashSet && hashSet->ddictPtrTable) { - ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); - } - if (hashSet) { - ZSTD_customFree(hashSet, customMem); - } -} - -/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. - * Returns 0 on success, or a ZSTD error. - */ -static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { - DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); - if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { - FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); - } - FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); - return 0; -} - /*-************************************************************* * Context management ***************************************************************/ @@ -237,20 +94,11 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) return startingInputLength; } -static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) -{ - assert(dctx->streamStage == zdss_init); - dctx->format = ZSTD_f_zstd1; - dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; - dctx->outBufferMode = ZSTD_bm_buffered; - dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; - dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; - dctx->disableHufAsm = 0; -} - static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { + dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */ dctx->staticSize = 0; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; dctx->ddict = NULL; dctx->ddictLocal = NULL; dctx->dictEnd = NULL; @@ -260,20 +108,10 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->inBuffSize = 0; dctx->outBuffSize = 0; dctx->streamStage = zdss_init; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) dctx->legacyContext = NULL; dctx->previousLegacyVersion = 0; -#endif dctx->noForwardProgress = 0; - dctx->oversizedDuration = 0; -#if DYNAMIC_BMI2 - dctx->bmi2 = ZSTD_cpuSupportsBmi2(); -#endif - dctx->ddictSet = NULL; - ZSTD_DCtx_resetParameters(dctx); -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - dctx->dictContentEndForFuzzing = NULL; -#endif + dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); } ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) @@ -289,10 +127,11 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) return dctx; } -static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem); if (!dctx) return NULL; dctx->customMem = customMem; ZSTD_initDCtx_internal(dctx); @@ -300,15 +139,10 @@ static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { } } -ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) -{ - return ZSTD_createDCtx_internal(customMem); -} - ZSTD_DCtx* ZSTD_createDCtx(void) { DEBUGLOG(3, "ZSTD_createDCtx"); - return ZSTD_createDCtx_internal(ZSTD_defaultCMem); + return ZSTD_createDCtx_advanced(ZSTD_defaultCMem); } static void ZSTD_clearDict(ZSTD_DCtx* dctx) @@ -325,17 +159,13 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); { ZSTD_customMem const cMem = dctx->customMem; ZSTD_clearDict(dctx); - ZSTD_customFree(dctx->inBuff, cMem); + ZSTD_free(dctx->inBuff, cMem); dctx->inBuff = NULL; #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (dctx->legacyContext) ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); #endif - if (dctx->ddictSet) { - ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); - dctx->ddictSet = NULL; - } - ZSTD_customFree(dctx, cMem); + ZSTD_free(dctx, cMem); return 0; } } @@ -344,30 +174,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); - ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ -} - -/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on - * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then - * accordingly sets the ddict to be used to decompress the frame. - * - * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. - * - * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. - */ -static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { - assert(dctx->refMultipleDDicts && dctx->ddictSet); - DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); - if (dctx->ddict) { - const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); - if (frameDDict) { - DEBUGLOG(4, "DDict found!"); - ZSTD_clearDict(dctx); - dctx->dictID = dctx->fParams.dictID; - dctx->ddict = frameDDict; - dctx->dictUses = ZSTD_use_indefinitely; - } - } + memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ } @@ -393,19 +200,6 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) return 0; } -/*! ZSTD_isSkippableFrame() : - * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. - * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. - */ -unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) -{ - if (size < ZSTD_FRAMEIDSIZE) return 0; - { U32 const magic = MEM_readLE32(buffer); - if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; - } - return 0; -} - /** ZSTD_frameHeaderSize_internal() : * srcSize must be large enough to reach header size fields. * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. @@ -414,7 +208,7 @@ unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format) { size_t const minInputSize = ZSTD_startingInputLength(format); - RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong); { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; U32 const dictID= fhd & 3; @@ -441,52 +235,28 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless * @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, value is wanted `srcSize` amount, -** or an error code, which can be tested using ZSTD_isError() */ + * or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) { const BYTE* ip = (const BYTE*)src; size_t const minInputSize = ZSTD_startingInputLength(format); - DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize); - - if (srcSize > 0) { - /* note : technically could be considered an assert(), since it's an invalid entry */ - RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0"); - } - if (srcSize < minInputSize) { - if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) { - /* when receiving less than @minInputSize bytes, - * control these bytes at least correspond to a supported magic number - * in order to error out early if they don't. - **/ - size_t const toCopy = MIN(4, srcSize); - unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER); - assert(src != NULL); - ZSTD_memcpy(hbuf, src, toCopy); - if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) { - /* not a zstd frame : let's check if it's a skippable frame */ - MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START); - ZSTD_memcpy(hbuf, src, toCopy); - if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) { - RETURN_ERROR(prefix_unknown, - "first bytes don't correspond to any supported magic number"); - } } } - return minInputSize; - } + memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */ + if (srcSize < minInputSize) return minInputSize; + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter"); - ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */ if ( (format != ZSTD_f_zstd1_magicless) && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ - ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); + memset(zfhPtr, 0, sizeof(*zfhPtr)); zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); zfhPtr->frameType = ZSTD_skippableFrame; return 0; } - RETURN_ERROR(prefix_unknown, ""); + RETURN_ERROR(prefix_unknown); } /* ensure there is enough `srcSize` to fully read/decode frame header */ @@ -510,15 +280,13 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s if (!singleSegment) { BYTE const wlByte = ip[pos++]; U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; - RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, ""); + RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge); windowSize = (1ULL << windowLog); windowSize += (windowSize >> 3) * (wlByte&7); } switch(dictIDSizeCode) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : break; case 1 : dictID = ip[pos]; pos++; break; case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; @@ -526,9 +294,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s } switch(fcsID) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : if (singleSegment) frameContentSize = ip[pos]; break; case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; case 2 : frameContentSize = MEM_readLE32(ip+pos); break; @@ -557,6 +323,7 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); } + /** ZSTD_getFrameContentSize() : * compatible with legacy mode * @return : decompressed size of the single frame pointed to be `src` if known, otherwise @@ -585,57 +352,23 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize) size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE; U32 sizeU32; - RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong); sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, - frameParameter_unsupported, ""); - { size_t const skippableSize = skippableHeaderSize + sizeU32; - RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); + frameParameter_unsupported); + { + size_t const skippableSize = skippableHeaderSize + sizeU32; + RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong); return skippableSize; } } -/*! ZSTD_readSkippableFrame() : - * Retrieves content of a skippable frame, and writes it to dst buffer. - * - * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, - * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested - * in the magicVariant. - * - * Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame. - * - * @return : number of bytes written or a ZSTD error. - */ -size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, - unsigned* magicVariant, /* optional, can be NULL */ - const void* src, size_t srcSize) -{ - RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); - - { U32 const magicNumber = MEM_readLE32(src); - size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); - size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; - - /* check input validity */ - RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); - RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); - RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); - - /* deliver payload */ - if (skippableContentSize > 0 && dst != NULL) - ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); - if (magicVariant != NULL) - *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; - return skippableContentSize; - } -} - /** ZSTD_findDecompressedSize() : + * compatible with legacy mode * `srcSize` must be the exact length of some number of ZSTD compressed and/or * skippable frames - * note: compatible with legacy mode - * @return : decompressed size of the frames contained */ + * @return : decompressed size of the frames contained */ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) { unsigned long long totalDstSize = 0; @@ -645,7 +378,9 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { size_t const skippableSize = readSkippableFrameSize(src, srcSize); - if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR; + if (ZSTD_isError(skippableSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; @@ -653,17 +388,17 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) continue; } - { unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize); - if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs; + { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; - if (totalDstSize + fcs < totalDstSize) - return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */ - totalDstSize += fcs; + /* check for overflow */ + if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; + totalDstSize += ret; } - /* skip to next frame */ { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); - if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR; - assert(frameSrcSize <= srcSize); + if (ZSTD_isError(frameSrcSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } src = (const BYTE *)src + frameSrcSize; srcSize -= frameSrcSize; @@ -693,29 +428,20 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) /** ZSTD_decodeFrameHeader() : * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). - * If multiple DDict references are enabled, also will choose the correct DDict to use. * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) { size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); if (ZSTD_isError(result)) return result; /* invalid header */ RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); - - /* Reference DDict requested by frame if dctx references multiple ddicts */ - if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { - ZSTD_DCtx_selectFrameDDict(dctx); - } - #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Skip the dictID check in fuzzing mode, because it makes the search * harder. */ RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), - dictionary_wrong, ""); + dictionary_wrong); #endif - dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; - if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); - dctx->processedCSize += headerSize; + if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0); return 0; } @@ -730,7 +456,7 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) { ZSTD_frameSizeInfo frameSizeInfo; - ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (ZSTD_isLegacy(src, srcSize)) @@ -785,11 +511,10 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize ip += 4; } - frameSizeInfo.nbBlocks = nbBlocks; - frameSizeInfo.compressedSize = (size_t)(ip - ipstart); + frameSizeInfo.compressedSize = ip - ipstart; frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) ? zfh.frameContentSize - : (unsigned long long)nbBlocks * zfh.blockSizeMax; + : nbBlocks * zfh.blockSizeMax; return frameSizeInfo; } } @@ -829,59 +554,28 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) return bound; } -size_t ZSTD_decompressionMargin(void const* src, size_t srcSize) -{ - size_t margin = 0; - unsigned maxBlockSize = 0; - /* Iterate over each frame */ - while (srcSize > 0) { - ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); - size_t const compressedSize = frameSizeInfo.compressedSize; - unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; - ZSTD_frameHeader zfh; +/*-************************************************************* + * Frame decoding + ***************************************************************/ - FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), ""); - if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) - return ERROR(corruption_detected); - - if (zfh.frameType == ZSTD_frame) { - /* Add the frame header to our margin */ - margin += zfh.headerSize; - /* Add the checksum to our margin */ - margin += zfh.checksumFlag ? 4 : 0; - /* Add 3 bytes per block */ - margin += 3 * frameSizeInfo.nbBlocks; - - /* Compute the max block size */ - maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax); - } else { - assert(zfh.frameType == ZSTD_skippableFrame); - /* Add the entire skippable frame size to our margin. */ - margin += compressedSize; - } - assert(srcSize >= compressedSize); - src = (const BYTE*)src + compressedSize; - srcSize -= compressedSize; +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst) +{ + if (dst != dctx->previousDstEnd) { /* not contiguous */ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dst; + dctx->previousDstEnd = dst; } - - /* Add the max block size back to the margin. */ - margin += maxBlockSize; - - return margin; } -/*-************************************************************* - * Frame decoding - ***************************************************************/ - /** ZSTD_insertBlock() : * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */ size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) { DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); - ZSTD_checkContinuity(dctx, blockStart, blockSize); + ZSTD_checkContinuity(dctx, blockStart); dctx->previousDstEnd = (const char*)blockStart + blockSize; return blockSize; } @@ -891,12 +585,12 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_copyRawBlock"); - RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (srcSize == 0) return 0; - RETURN_ERROR(dstBuffer_null, ""); + RETURN_ERROR(dstBuffer_null); } - ZSTD_memmove(dst, src, srcSize); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall); + memcpy(dst, src, srcSize); return srcSize; } @@ -904,41 +598,15 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, BYTE b, size_t regenSize) { - RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (regenSize == 0) return 0; - RETURN_ERROR(dstBuffer_null, ""); + RETURN_ERROR(dstBuffer_null); } - ZSTD_memset(dst, b, regenSize); + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall); + memset(dst, b, regenSize); return regenSize; } -static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) -{ -#if ZSTD_TRACE - if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { - ZSTD_Trace trace; - ZSTD_memset(&trace, 0, sizeof(trace)); - trace.version = ZSTD_VERSION_NUMBER; - trace.streaming = streaming; - if (dctx->ddict) { - trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); - trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); - trace.dictionaryIsCold = dctx->ddictIsCold; - } - trace.uncompressedSize = (size_t)uncompressedSize; - trace.compressedSize = (size_t)compressedSize; - trace.dctx = dctx; - ZSTD_trace_decompress_end(dctx->traceCtx, &trace); - } -#else - (void)dctx; - (void)uncompressedSize; - (void)compressedSize; - (void)streaming; -#endif -} - /*! ZSTD_decompressFrame() : * @dctx must be properly initialized @@ -948,10 +616,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void** srcPtr, size_t *srcSizePtr) { - const BYTE* const istart = (const BYTE*)(*srcPtr); - const BYTE* ip = istart; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; + const BYTE* ip = (const BYTE*)(*srcPtr); + BYTE* const ostart = (BYTE* const)dst; + BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; size_t remainingSrcSize = *srcSizePtr; @@ -960,21 +627,20 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* check */ RETURN_ERROR_IF( remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, - srcSize_wrong, ""); + srcSize_wrong); /* Frame Header */ { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, - srcSize_wrong, ""); - FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); + srcSize_wrong); + FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) ); ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; } /* Loop on each block */ while (1) { - BYTE* oBlockEnd = oend; size_t decodedSize; blockProperties_t blockProperties; size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties); @@ -982,48 +648,28 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, ip += ZSTD_blockHeaderSize; remainingSrcSize -= ZSTD_blockHeaderSize; - RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); - - if (ip >= op && ip < oBlockEnd) { - /* We are decompressing in-place. Limit the output pointer so that we - * don't overwrite the block that we are currently reading. This will - * fail decompression if the input & output pointers aren't spaced - * far enough apart. - * - * This is important to set, even when the pointers are far enough - * apart, because ZSTD_decompressBlock_internal() can decide to store - * literals in the output buffer, after the block it is decompressing. - * Since we don't want anything to overwrite our input, we have to tell - * ZSTD_decompressBlock_internal to never write past ip. - * - * See ZSTD_allocateLiteralsBuffer() for reference. - */ - oBlockEnd = op + (ip - op); - } + RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong); switch(blockProperties.blockType) { case bt_compressed: - decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, /* frame */ 1, not_streaming); + decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1); break; case bt_raw : - /* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */ - decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); + decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize); break; case bt_rle : - decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize); + decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize); break; case bt_reserved : default: - RETURN_ERROR(corruption_detected, "invalid block type"); + RETURN_ERROR(corruption_detected); } if (ZSTD_isError(decodedSize)) return decodedSize; - if (dctx->validateChecksum) + if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, op, decodedSize); - if (decodedSize != 0) - op += decodedSize; - assert(ip != NULL); + op += decodedSize; ip += cBlockSize; remainingSrcSize -= cBlockSize; if (blockProperties.lastBlock) break; @@ -1031,25 +677,22 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, - corruption_detected, ""); + corruption_detected); } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ - RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); - if (!dctx->forceIgnoreChecksum) { - U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); - U32 checkRead; - checkRead = MEM_readLE32(ip); - RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); - } + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong); + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong); ip += 4; remainingSrcSize -= 4; } - ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); + /* Allow caller to get size read */ - DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %zi, consuming %zi bytes of input", op-ostart, ip - (const BYTE*)*srcPtr); *srcPtr = ip; *srcSizePtr = remainingSrcSize; - return (size_t)(op-ostart); + return op-ostart; } static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, @@ -1082,7 +725,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); if (ZSTD_isError(decodedSize)) return decodedSize; - assert(decodedSize <= dstCapacity); + assert(decodedSize <=- dstCapacity); dst = (BYTE*)dst + decodedSize; dstCapacity -= decodedSize; @@ -1093,29 +736,28 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, } #endif - if (srcSize >= 4) { - U32 const magicNumber = MEM_readLE32(src); - DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber); + { U32 const magicNumber = MEM_readLE32(src); + DEBUGLOG(4, "reading magic number %08X (expecting %08X)", + (unsigned)magicNumber, ZSTD_MAGICNUMBER); if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { - /* skippable frame detected : skip it */ size_t const skippableSize = readSkippableFrameSize(src, srcSize); - FORWARD_IF_ERROR(skippableSize, "invalid skippable frame"); + FORWARD_IF_ERROR(skippableSize); assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; srcSize -= skippableSize; - continue; /* check next frame */ + continue; } } if (ddict) { /* we were called from ZSTD_decompress_usingDDict */ - FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), ""); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict)); } else { /* this will initialize correctly with no dict if dict == NULL, so * use this in all cases but ddict */ - FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize)); } - ZSTD_checkContinuity(dctx, dst, dstCapacity); + ZSTD_checkContinuity(dctx, dst); { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize); @@ -1123,17 +765,18 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) && (moreThan1Frame==1), srcSize_wrong, - "At least one frame successfully completed, " - "but following bytes are garbage: " - "it's more likely to be a srcSize error, " - "specifying more input bytes than size of frame(s). " - "Note: one could be unlucky, it might be a corruption error instead, " - "happening right at the place where we expect zstd magic bytes. " - "But this is _much_ less likely than a srcSize field error."); + "at least one frame successfully completed, but following " + "bytes are garbage: it's more likely to be a srcSize error, " + "specifying more bytes than compressed size of frame(s). This " + "error message replaces ERROR(prefix_unknown), which would be " + "confusing, as the first header is actually correct. Note that " + "one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic " + "bytes. But this is _much_ less likely than a srcSize field " + "error."); if (ZSTD_isError(res)) return res; assert(res <= dstCapacity); - if (res != 0) - dst = (BYTE*)dst + res; + dst = (BYTE*)dst + res; dstCapacity -= res; } moreThan1Frame = 1; @@ -1141,7 +784,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); - return (size_t)((BYTE*)dst - (BYTE*)dststart); + return (BYTE*)dst - (BYTE*)dststart; } size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, @@ -1158,7 +801,7 @@ static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) switch (dctx->dictUses) { default: assert(0 /* Impossible */); - ZSTD_FALLTHROUGH; + /* fall-through */ case ZSTD_dont_use: ZSTD_clearDict(dctx); return NULL; @@ -1180,8 +823,8 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr { #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) size_t regenSize; - ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); - RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); + ZSTD_DCtx* const dctx = ZSTD_createDCtx(); + RETURN_ERROR_IF(dctx==NULL, memory_allocation); regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); ZSTD_freeDCtx(dctx); return regenSize; @@ -1199,32 +842,12 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr ****************************************/ size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } -/** - * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we - * allow taking a partial block as the input. Currently only raw uncompressed blocks can - * be streamed. - * - * For blocks that can be streamed, this allows us to reduce the latency until we produce - * output, and avoid copying the input. - * - * @param inputSize - The total amount of input that the caller currently has. - */ -static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) { - if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock)) - return dctx->expected; - if (dctx->bType != bt_raw) - return dctx->expected; - return BOUNDED(1, inputSize, dctx->expected); -} - ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { switch(dctx->stage) { default: /* should not happen */ assert(0); - ZSTD_FALLTHROUGH; case ZSTDds_getFrameHeaderSize: - ZSTD_FALLTHROUGH; case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader; case ZSTDds_decodeBlockHeader: @@ -1236,7 +859,6 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { case ZSTDds_checkChecksum: return ZSTDnit_checksum; case ZSTDds_decodeSkippableHeader: - ZSTD_FALLTHROUGH; case ZSTDds_skipFrame: return ZSTDnit_skippableFrame; } @@ -1252,10 +874,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); /* Sanity check */ - RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); - ZSTD_checkContinuity(dctx, dst, dstCapacity); - - dctx->processedCSize += srcSize; + RETURN_ERROR_IF(srcSize != dctx->expected, srcSize_wrong, "not allowed"); + if (dstCapacity) ZSTD_checkContinuity(dctx, dst); switch (dctx->stage) { @@ -1264,22 +884,22 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c if (dctx->format == ZSTD_f_zstd1) { /* allows header */ assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ - ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ dctx->stage = ZSTDds_decodeSkippableHeader; return 0; } } dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; - ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = dctx->headerSize - srcSize; dctx->stage = ZSTDds_decodeFrameHeader; return 0; case ZSTDds_decodeFrameHeader: assert(src != NULL); - ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); - FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); + memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize)); dctx->expected = ZSTD_blockHeaderSize; dctx->stage = ZSTDds_decodeBlockHeader; return 0; @@ -1320,67 +940,51 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { case bt_compressed: DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); - rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming); - dctx->expected = 0; /* Streaming not supported */ + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1); break; case bt_raw : - assert(srcSize <= dctx->expected); rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); - FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed"); - assert(rSize == srcSize); - dctx->expected -= rSize; break; case bt_rle : rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize); - dctx->expected = 0; /* Streaming not supported */ break; case bt_reserved : /* should never happen */ default: - RETURN_ERROR(corruption_detected, "invalid block type"); + RETURN_ERROR(corruption_detected); } - FORWARD_IF_ERROR(rSize, ""); + if (ZSTD_isError(rSize)) return rSize; RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); dctx->decodedSize += rSize; - if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); - dctx->previousDstEnd = (char*)dst + rSize; - - /* Stay on the same stage until we are finished streaming the block. */ - if (dctx->expected > 0) { - return rSize; - } + if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize); RETURN_ERROR_IF( dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && dctx->decodedSize != dctx->fParams.frameContentSize, - corruption_detected, ""); + corruption_detected); if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; } else { - ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); dctx->expected = 0; /* ends here */ dctx->stage = ZSTDds_getFrameHeaderSize; } } else { dctx->stage = ZSTDds_decodeBlockHeader; dctx->expected = ZSTD_blockHeaderSize; + dctx->previousDstEnd = (char*)dst + rSize; } return rSize; } case ZSTDds_checkChecksum: assert(srcSize == 4); /* guaranteed by dctx->expected */ - { - if (dctx->validateChecksum) { - U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); - U32 const check32 = MEM_readLE32(src); - DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); - RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); - } - ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong); dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; @@ -1389,7 +993,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_decodeSkippableHeader: assert(src != NULL); assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); - ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ dctx->stage = ZSTDds_skipFrame; return 0; @@ -1401,7 +1005,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ + RETURN_ERROR(GENERIC); /* some compiler require default to do something */ } } @@ -1412,10 +1016,6 @@ static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dict dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); dctx->prefixStart = dict; dctx->previousDstEnd = (const char*)dict + dictSize; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - dctx->dictContentBeginForFuzzing = dctx->prefixStart; - dctx->dictContentEndForFuzzing = dctx->previousDstEnd; -#endif return 0; } @@ -1429,7 +1029,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, const BYTE* dictPtr = (const BYTE*)dict; const BYTE* const dictEnd = dictPtr + dictSize; - RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small"); + RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted); assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */ dictPtr += 8; /* skip header = magic + dictID */ @@ -1442,72 +1042,66 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, /* in minimal huffman, we always use X1 variants */ size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable, dictPtr, dictEnd - dictPtr, - workspace, workspaceSize, /* flags */ 0); + workspace, workspaceSize); #else size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, - dictPtr, (size_t)(dictEnd - dictPtr), - workspace, workspaceSize, /* flags */ 0); + dictPtr, dictEnd - dictPtr, + workspace, workspaceSize); #endif - RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted); dictPtr += hSize; } { short offcodeNCount[MaxOff+1]; unsigned offcodeMaxValue = MaxOff, offcodeLog; - size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); - RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); - RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); ZSTD_buildFSETable( entropy->OFTable, offcodeNCount, offcodeMaxValue, OF_base, OF_bits, - offcodeLog, - entropy->workspace, sizeof(entropy->workspace), - /* bmi2 */0); + offcodeLog); dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; - size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); - RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); - RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); ZSTD_buildFSETable( entropy->MLTable, matchlengthNCount, matchlengthMaxValue, ML_base, ML_bits, - matchlengthLog, - entropy->workspace, sizeof(entropy->workspace), - /* bmi2 */ 0); + matchlengthLog); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; - size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); - RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); - RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); + RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); ZSTD_buildFSETable( entropy->LLTable, litlengthNCount, litlengthMaxValue, LL_base, LL_bits, - litlengthLog, - entropy->workspace, sizeof(entropy->workspace), - /* bmi2 */ 0); + litlengthLog); dictPtr += litlengthHeaderSize; } - RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); { int i; size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12)); for (i=0; i<3; i++) { U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4; RETURN_ERROR_IF(rep==0 || rep > dictContentSize, - dictionary_corrupted, ""); + dictionary_corrupted); entropy->rep[i] = rep; } } - return (size_t)(dictPtr - (const BYTE*)dict); + return dictPtr - (const BYTE*)dict; } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) @@ -1521,7 +1115,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict /* load entropy tables */ { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize); - RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted); dict = (const char*)dict + eSize; dictSize -= eSize; } @@ -1534,23 +1128,18 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { assert(dctx != NULL); -#if ZSTD_TRACE - dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; -#endif dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ dctx->stage = ZSTDds_getFrameHeaderSize; - dctx->processedCSize = 0; dctx->decodedSize = 0; dctx->previousDstEnd = NULL; dctx->prefixStart = NULL; dctx->virtualStart = NULL; dctx->dictEnd = NULL; - dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ + dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; - dctx->bType = bt_reserved; ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); - ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ dctx->LLTptr = dctx->entropy.LLTable; dctx->MLTptr = dctx->entropy.MLTable; dctx->OFTptr = dctx->entropy.OFTable; @@ -1560,11 +1149,11 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { - FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) ); if (dict && dictSize) RETURN_ERROR_IF( ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)), - dictionary_corrupted, ""); + dictionary_corrupted); return 0; } @@ -1583,7 +1172,7 @@ size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) DEBUGLOG(4, "DDict is %s", dctx->ddictIsCold ? "~cold~" : "hot!"); } - FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) ); if (ddict) { /* NULL ddict is equivalent to no dictionary */ ZSTD_copyDDictParameters(dctx, ddict); } @@ -1607,7 +1196,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * This could for one of the following reasons : * - The frame does not require a dictionary (most common case). * - The frame was built with dictID intentionally removed. - * Needed dictionary is a hidden piece of information. + * Needed dictionary is a hidden information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, frame header could not be decoded. * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. @@ -1616,7 +1205,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * ZSTD_getFrameHeader(), which will provide a more precise error code. */ unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) { - ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 }; + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 }; size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); if (ZSTD_isError(hError)) return 0; return zfp.dictID; @@ -1645,7 +1234,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, ZSTD_DStream* ZSTD_createDStream(void) { DEBUGLOG(3, "ZSTD_createDStream"); - return ZSTD_createDCtx_internal(ZSTD_defaultCMem); + return ZSTD_createDStream_advanced(ZSTD_defaultCMem); } ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) @@ -1655,7 +1244,7 @@ ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) { - return ZSTD_createDCtx_internal(customMem); + return ZSTD_createDCtx_advanced(customMem); } size_t ZSTD_freeDStream(ZSTD_DStream* zds) @@ -1674,11 +1263,11 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); ZSTD_clearDict(dctx); if (dict && dictSize != 0) { dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem); - RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!"); + RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation); dctx->ddict = dctx->ddictLocal; dctx->dictUses = ZSTD_use_indefinitely; } @@ -1697,7 +1286,7 @@ size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSi size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) { - FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), ""); + FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType)); dctx->dictUses = ZSTD_use_once; return 0; } @@ -1714,8 +1303,8 @@ size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSiz size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize) { DEBUGLOG(4, "ZSTD_initDStream_usingDict"); - FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) ); return ZSTD_startingInputLength(zds->format); } @@ -1723,9 +1312,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di size_t ZSTD_initDStream(ZSTD_DStream* zds) { DEBUGLOG(4, "ZSTD_initDStream"); - FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), ""); - FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), ""); - return ZSTD_startingInputLength(zds->format); + return ZSTD_initDStream_usingDDict(zds, NULL); } /* ZSTD_initDStream_usingDDict() : @@ -1733,9 +1320,8 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds) * this function cannot fail */ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) { - DEBUGLOG(4, "ZSTD_initDStream_usingDDict"); - FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); - FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) ); + FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) ); return ZSTD_startingInputLength(dctx->format); } @@ -1744,29 +1330,18 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) * this function cannot fail */ size_t ZSTD_resetDStream(ZSTD_DStream* dctx) { - DEBUGLOG(4, "ZSTD_resetDStream"); - FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only)); return ZSTD_startingInputLength(dctx->format); } size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); ZSTD_clearDict(dctx); if (ddict) { dctx->ddict = ddict; dctx->dictUses = ZSTD_use_indefinitely; - if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { - if (dctx->ddictSet == NULL) { - dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); - if (!dctx->ddictSet) { - RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); - } - } - assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ - FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); - } } return 0; } @@ -1779,16 +1354,16 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax); size_t const min = (size_t)1 << bounds.lowerBound; size_t const max = (size_t)1 << bounds.upperBound; - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); - RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, ""); - RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, ""); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); + RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound); + RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound); dctx->maxWindowSize = maxWindowSize; return 0; } size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) @@ -1804,23 +1379,6 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) bounds.upperBound = (int)ZSTD_f_zstd1_magicless; ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); return bounds; - case ZSTD_d_stableOutBuffer: - bounds.lowerBound = (int)ZSTD_bm_buffered; - bounds.upperBound = (int)ZSTD_bm_stable; - return bounds; - case ZSTD_d_forceIgnoreChecksum: - bounds.lowerBound = (int)ZSTD_d_validateChecksum; - bounds.upperBound = (int)ZSTD_d_ignoreChecksum; - return bounds; - case ZSTD_d_refMultipleDDicts: - bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; - bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; - return bounds; - case ZSTD_d_disableHuffmanAssembly: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - default:; } bounds.error = ERROR(parameter_unsupported); @@ -1840,38 +1398,12 @@ static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) } #define CHECK_DBOUNDS(p,v) { \ - RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ -} - -size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) -{ - switch (param) { - case ZSTD_d_windowLogMax: - *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); - return 0; - case ZSTD_d_format: - *value = (int)dctx->format; - return 0; - case ZSTD_d_stableOutBuffer: - *value = (int)dctx->outBufferMode; - return 0; - case ZSTD_d_forceIgnoreChecksum: - *value = (int)dctx->forceIgnoreChecksum; - return 0; - case ZSTD_d_refMultipleDDicts: - *value = (int)dctx->refMultipleDDicts; - return 0; - case ZSTD_d_disableHuffmanAssembly: - *value = (int)dctx->disableHufAsm; - return 0; - default:; - } - RETURN_ERROR(parameter_unsupported, ""); + RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound); \ } size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); switch(dParam) { case ZSTD_d_windowLogMax: if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT; @@ -1882,28 +1414,9 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value CHECK_DBOUNDS(ZSTD_d_format, value); dctx->format = (ZSTD_format_e)value; return 0; - case ZSTD_d_stableOutBuffer: - CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); - dctx->outBufferMode = (ZSTD_bufferMode_e)value; - return 0; - case ZSTD_d_forceIgnoreChecksum: - CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); - dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; - return 0; - case ZSTD_d_refMultipleDDicts: - CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); - if (dctx->staticSize != 0) { - RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); - } - dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; - return 0; - case ZSTD_d_disableHuffmanAssembly: - CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value); - dctx->disableHufAsm = value != 0; - return 0; default:; } - RETURN_ERROR(parameter_unsupported, ""); + RETURN_ERROR(parameter_unsupported); } size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) @@ -1915,9 +1428,10 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) } if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); ZSTD_clearDict(dctx); - ZSTD_DCtx_resetParameters(dctx); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; } return 0; } @@ -1931,12 +1445,11 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) { size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); - /* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/ - unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2); + unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); size_t const minRBSize = (size_t) neededSize; RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, - frameParameter_windowTooLarge, ""); + frameParameter_windowTooLarge); return minRBSize; } @@ -1954,94 +1467,30 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) ZSTD_frameHeader zfh; size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize); if (ZSTD_isError(err)) return err; - RETURN_ERROR_IF(err>0, srcSize_wrong, ""); + RETURN_ERROR_IF(err>0, srcSize_wrong); RETURN_ERROR_IF(zfh.windowSize > windowSizeMax, - frameParameter_windowTooLarge, ""); + frameParameter_windowTooLarge); return ZSTD_estimateDStreamSize((size_t)zfh.windowSize); } /* ***** Decompression ***** */ -static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR; + size_t const length = MIN(dstCapacity, srcSize); + memcpy(dst, src, length); + return length; } -static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) -{ - if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) - zds->oversizedDuration++; - else - zds->oversizedDuration = 0; -} - -static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds) -{ - return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION; -} - -/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */ -static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output) -{ - ZSTD_outBuffer const expect = zds->expectedOutBuffer; - /* No requirement when ZSTD_obm_stable is not enabled. */ - if (zds->outBufferMode != ZSTD_bm_stable) - return 0; - /* Any buffer is allowed in zdss_init, this must be the same for every other call until - * the context is reset. - */ - if (zds->streamStage == zdss_init) - return 0; - /* The buffer must match our expectation exactly. */ - if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) - return 0; - RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); -} - -/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() - * and updates the stage and the output buffer state. This call is extracted so it can be - * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode. - * NOTE: You must break after calling this function since the streamStage is modified. - */ -static size_t ZSTD_decompressContinueStream( - ZSTD_DStream* zds, char** op, char* oend, - void const* src, size_t srcSize) { - int const isSkipFrame = ZSTD_isSkipFrame(zds); - if (zds->outBufferMode == ZSTD_bm_buffered) { - size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; - size_t const decodedSize = ZSTD_decompressContinue(zds, - zds->outBuff + zds->outStart, dstSize, src, srcSize); - FORWARD_IF_ERROR(decodedSize, ""); - if (!decodedSize && !isSkipFrame) { - zds->streamStage = zdss_read; - } else { - zds->outEnd = zds->outStart + decodedSize; - zds->streamStage = zdss_flush; - } - } else { - /* Write directly into the output buffer */ - size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); - size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); - FORWARD_IF_ERROR(decodedSize, ""); - *op += decodedSize; - /* Flushing is not needed. */ - zds->streamStage = zdss_read; - assert(*op <= oend); - assert(zds->outBufferMode == ZSTD_bm_stable); - } - return 0; -} size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input) { - const char* const src = (const char*)input->src; - const char* const istart = input->pos != 0 ? src + input->pos : src; - const char* const iend = input->size != 0 ? src + input->size : src; + const char* const istart = (const char*)(input->src) + input->pos; + const char* const iend = (const char*)(input->src) + input->size; const char* ip = istart; - char* const dst = (char*)output->dst; - char* const ostart = output->pos != 0 ? dst + output->pos : dst; - char* const oend = output->size != 0 ? dst + output->size : dst; + char* const ostart = (char*)(output->dst) + output->pos; + char* const oend = (char*)(output->dst) + output->size; char* op = ostart; U32 someMoreWork = 1; @@ -2057,7 +1506,6 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB "forbidden. out: pos: %u vs size: %u", (U32)output->pos, (U32)output->size); DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); - FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), ""); while (someMoreWork) { switch(zds->streamStage) @@ -2066,12 +1514,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB DEBUGLOG(5, "stage zdss_init => transparent reset "); zds->streamStage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) zds->legacyVersion = 0; -#endif zds->hostageByte = 0; - zds->expectedOutBuffer = *output; - ZSTD_FALLTHROUGH; + /* fall-through */ case zdss_loadHeader : DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); @@ -2085,9 +1530,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } #endif { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); - if (zds->refMultipleDDicts && zds->ddictSet) { - ZSTD_DCtx_selectFrameDDict(zds); - } + DEBUGLOG(5, "header size : %u", (U32)hSize); if (ZSTD_isError(hSize)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); @@ -2100,7 +1543,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB "legacy support is incompatible with static dctx"); FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion, - dict, dictSize), ""); + dict, dictSize)); zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input); if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */ @@ -2115,58 +1558,43 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB assert(iend >= ip); if (toLoad > remainingInput) { /* not enough input to load full header */ if (remainingInput > 0) { - ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); zds->lhSize += remainingInput; } input->pos = input->size; - /* check first few bytes */ - FORWARD_IF_ERROR( - ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format), - "First few bytes detected incorrect" ); - /* return hint input size */ return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } assert(ip != NULL); - ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; } } /* check for single-pass mode opportunity */ - if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN - && zds->fParams.frameType != ZSTD_skippableFrame + if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */ && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { - size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart)); + size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart); if (cSize <= (size_t)(iend-istart)) { /* shortcut : using single-pass mode */ - size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds)); if (ZSTD_isError(decompressedSize)) return decompressedSize; DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") - assert(istart != NULL); ip = istart + cSize; - op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */ + op += decompressedSize; zds->expected = 0; zds->streamStage = zdss_init; someMoreWork = 0; break; } } - /* Check output buffer is large enough for ZSTD_odm_stable. */ - if (zds->outBufferMode == ZSTD_bm_stable - && zds->fParams.frameType != ZSTD_skippableFrame - && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN - && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { - RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small"); - } - /* Consume header (see ZSTDds_decodeFrameHeader) */ DEBUGLOG(4, "Consume header"); - FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds))); if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); zds->stage = ZSTDds_skipFrame; } else { - FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize)); zds->expected = ZSTD_blockHeaderSize; zds->stage = ZSTDds_decodeBlockHeader; } @@ -2177,48 +1605,40 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB (U32)(zds->maxWindowSize >> 10) ); zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, - frameParameter_windowTooLarge, ""); + frameParameter_windowTooLarge); /* Adapt buffer sizes to frame header instructions */ { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); - size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered - ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) - : 0; - - ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); - - { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); - int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); - - if (tooSmall || tooLarge) { - size_t const bufferSize = neededInBuffSize + neededOutBuffSize; - DEBUGLOG(4, "inBuff : from %u to %u", - (U32)zds->inBuffSize, (U32)neededInBuffSize); - DEBUGLOG(4, "outBuff : from %u to %u", - (U32)zds->outBuffSize, (U32)neededOutBuffSize); - if (zds->staticSize) { /* static DCtx */ - DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); - assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ - RETURN_ERROR_IF( - bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), - memory_allocation, ""); - } else { - ZSTD_customFree(zds->inBuff, zds->customMem); - zds->inBuffSize = 0; - zds->outBuffSize = 0; - zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); - RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); - } - zds->inBuffSize = neededInBuffSize; - zds->outBuff = zds->inBuff + zds->inBuffSize; - zds->outBuffSize = neededOutBuffSize; - } } } + size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize); + if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) { + size_t const bufferSize = neededInBuffSize + neededOutBuffSize; + DEBUGLOG(4, "inBuff : from %u to %u", + (U32)zds->inBuffSize, (U32)neededInBuffSize); + DEBUGLOG(4, "outBuff : from %u to %u", + (U32)zds->outBuffSize, (U32)neededOutBuffSize); + if (zds->staticSize) { /* static DCtx */ + DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); + assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ + RETURN_ERROR_IF( + bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), + memory_allocation); + } else { + ZSTD_free(zds->inBuff, zds->customMem); + zds->inBuffSize = 0; + zds->outBuffSize = 0; + zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem); + RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation); + } + zds->inBuffSize = neededInBuffSize; + zds->outBuff = zds->inBuff + zds->inBuffSize; + zds->outBuffSize = neededOutBuffSize; + } } zds->streamStage = zdss_read; - ZSTD_FALLTHROUGH; + /* fall-through */ case zdss_read: DEBUGLOG(5, "stage zdss_read"); - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); if (neededInSize==0) { /* end of frame */ zds->streamStage = zdss_init; @@ -2226,56 +1646,59 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB break; } if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ - FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); - assert(ip != NULL); + int const isSkipFrame = ZSTD_isSkipFrame(zds); + size_t const decodedSize = ZSTD_decompressContinue(zds, + zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), + ip, neededInSize); + if (ZSTD_isError(decodedSize)) return decodedSize; ip += neededInSize; - /* Function modifies the stage so we must break */ + if (!decodedSize && !isSkipFrame) break; /* this was just a header */ + zds->outEnd = zds->outStart + decodedSize; + zds->streamStage = zdss_flush; break; } } if (ip==iend) { someMoreWork = 0; break; } /* no more input */ zds->streamStage = zdss_load; - ZSTD_FALLTHROUGH; + /* fall-through */ case zdss_load: { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); size_t const toLoad = neededInSize - zds->inPos; int const isSkipFrame = ZSTD_isSkipFrame(zds); size_t loadedSize; - /* At this point we shouldn't be decompressing a block that we can stream. */ - assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip))); if (isSkipFrame) { loadedSize = MIN(toLoad, (size_t)(iend-ip)); } else { RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, corruption_detected, "should never happen"); - loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); - } - if (loadedSize != 0) { - /* ip may be NULL */ - ip += loadedSize; - zds->inPos += loadedSize; + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip); } + ip += loadedSize; + zds->inPos += loadedSize; if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ - zds->inPos = 0; /* input is consumed */ - FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), ""); - /* Function modifies the stage so we must break */ - break; - } - case zdss_flush: - { - size_t const toFlushSize = zds->outEnd - zds->outStart; - size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); - - op = op ? op + flushedSize : op; + { size_t const decodedSize = ZSTD_decompressContinue(zds, + zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart, + zds->inBuff, neededInSize); + if (ZSTD_isError(decodedSize)) return decodedSize; + zds->inPos = 0; /* input is consumed */ + if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; } /* this was just a header */ + zds->outEnd = zds->outStart + decodedSize; + } } + zds->streamStage = zdss_flush; + /* fall-through */ + case zdss_flush: + { size_t const toFlushSize = zds->outEnd - zds->outStart; + size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize); + op += flushedSize; zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ zds->streamStage = zdss_read; if ( (zds->outBuffSize < zds->fParams.frameContentSize) - && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", (int)(zds->outBuffSize - zds->outStart), (U32)zds->fParams.blockSizeMax); @@ -2289,21 +1712,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ + RETURN_ERROR(GENERIC); /* some compiler require default to do something */ } } /* result */ input->pos = (size_t)(ip - (const char*)(input->src)); output->pos = (size_t)(op - (char*)(output->dst)); - - /* Update the expected output buffer for ZSTD_obm_stable. */ - zds->expectedOutBuffer = *output; - if ((ip==istart) && (op==ostart)) { /* no forward progress */ zds->noForwardProgress ++; if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { - RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, ""); - RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, ""); + RETURN_ERROR_IF(op==oend, dstSize_tooSmall); + RETURN_ERROR_IF(ip==iend, srcSize_wrong); assert(0); } } else { @@ -2340,19 +1759,11 @@ size_t ZSTD_decompressStream_simpleArgs ( void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos) { - ZSTD_outBuffer output; - ZSTD_inBuffer input; - output.dst = dst; - output.size = dstCapacity; - output.pos = *dstPos; - input.src = src; - input.size = srcSize; - input.pos = *srcPos; - { size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); - *dstPos = output.pos; - *srcPos = input.pos; - return cErr; - } + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; + /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ + size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_decompress_block.c b/vendor/github.com/DataDog/zstd/zstd_decompress_block.c index 98767b14..767e5f9a 100644 --- a/vendor/github.com/DataDog/zstd/zstd_decompress_block.c +++ b/vendor/github.com/DataDog/zstd/zstd_decompress_block.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,18 +14,18 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include /* memcpy, memmove, memset */ #include "compiler.h" /* prefetch */ #include "cpu.h" /* bmi2 */ #include "mem.h" /* low level memory routines */ #define FSE_STATIC_LINKING_ONLY #include "fse.h" +#define HUF_STATIC_LINKING_ONLY #include "huf.h" #include "zstd_internal.h" #include "zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd_decompress_block.h" -#include "bits.h" /* ZSTD_highbit32 */ /*_******************************************************* * Macros @@ -45,7 +44,7 @@ /*_******************************************************* * Memory operations **********************************************************/ -static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } +static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } /*-************************************************************* @@ -57,7 +56,7 @@ static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong); { U32 const cBlockHeader = MEM_readLE24(src); U32 const cSize = cBlockHeader >> 3; @@ -65,64 +64,23 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3); bpPtr->origSize = cSize; /* only useful for RLE */ if (bpPtr->blockType == bt_rle) return 1; - RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, ""); + RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected); return cSize; } } -/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ -static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, - const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) -{ - if (streaming == not_streaming && dstCapacity > ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) - { - /* room for litbuffer to fit without read faulting */ - dctx->litBuffer = (BYTE*)dst + ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH; - dctx->litBufferEnd = dctx->litBuffer + litSize; - dctx->litBufferLocation = ZSTD_in_dst; - } - else if (litSize > ZSTD_LITBUFFEREXTRASIZE) - { - /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ - if (splitImmediately) { - /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ - dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; - dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; - } - else { - /* initially this will be stored entirely in dst during huffman decoding, it will partially be shifted to litExtraBuffer after */ - dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; - dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; - } - dctx->litBufferLocation = ZSTD_split; - } - else - { - /* fits entirely within litExtraBuffer, so no split is necessary */ - dctx->litBuffer = dctx->litExtraBuffer; - dctx->litBufferEnd = dctx->litBuffer + litSize; - dctx->litBufferLocation = ZSTD_not_in_dst; - } -} /* Hidden declaration for fullbench */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize, - void* dst, size_t dstCapacity, const streaming_operation streaming); + const void* src, size_t srcSize); /*! ZSTD_decodeLiteralsBlock() : - * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored - * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current - * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being - * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. - * * @return : nb of bytes read from src (< srcSize ) * note : symbol not declared but exposed for fullbench */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ - void* dst, size_t dstCapacity, const streaming_operation streaming) + const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ { DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); - RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); + RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected); { const BYTE* const istart = (const BYTE*) src; symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); @@ -131,20 +89,16 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, { case set_repeat: DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); - RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); - ZSTD_FALLTHROUGH; + RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted); + /* fall-through */ case set_compressed: - RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need up to 5 for case 3"); + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); { size_t lhSize, litSize, litCSize; U32 singleStream=0; U32 const lhlCode = (istart[0] >> 2) & 3; U32 const lhc = MEM_readLE32(istart); size_t hufSuccess; - size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); - int const flags = 0 - | (ZSTD_DCtx_get_bmi2(dctx) ? HUF_flags_bmi2 : 0) - | (dctx->disableHufAsm ? HUF_flags_disableAsm : 0); switch(lhlCode) { case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -167,15 +121,8 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); break; } - RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); - if (!singleStream) - RETURN_ERROR_IF(litSize < MIN_LITERALS_FOR_4_STREAMS, literals_headerWrong, - "Not enough literals (%zu) for the 4-streams mode (min %u)", - litSize, MIN_LITERALS_FOR_4_STREAMS); - RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); - RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); - ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected); + RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected); /* prefetch huffman table if cold */ if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { @@ -184,14 +131,13 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (litEncType==set_repeat) { if (singleStream) { - hufSuccess = HUF_decompress1X_usingDTable( + hufSuccess = HUF_decompress1X_usingDTable_bmi2( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, flags); + dctx->HUFptr, dctx->bmi2); } else { - assert(litSize >= MIN_LITERALS_FOR_4_STREAMS); - hufSuccess = HUF_decompress4X_usingDTable( + hufSuccess = HUF_decompress4X_usingDTable_bmi2( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, flags); + dctx->HUFptr, dctx->bmi2); } } else { if (singleStream) { @@ -199,41 +145,34 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, hufSuccess = HUF_decompress1X_DCtx_wksp( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), flags); + sizeof(dctx->workspace)); #else - hufSuccess = HUF_decompress1X1_DCtx_wksp( + hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), flags); + sizeof(dctx->workspace), dctx->bmi2); #endif } else { - hufSuccess = HUF_decompress4X_hufOnly_wksp( + hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), flags); + sizeof(dctx->workspace), dctx->bmi2); } } - if (dctx->litBufferLocation == ZSTD_split) - { - ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); - dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; - dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; - } - RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); + RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; dctx->litEntropy = 1; if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; + memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return litCSize + lhSize; } case set_basic: { size_t litSize, lhSize; U32 const lhlCode = ((istart[0]) >> 2) & 3; - size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -246,41 +185,27 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 3: lhSize = 3; - RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize = 3"); litSize = MEM_readLE24(istart) >> 4; break; } - RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); - ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ - RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); - if (dctx->litBufferLocation == ZSTD_split) - { - ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); - } - else - { - ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); - } + RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected); + memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; + memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return lhSize+litSize; } /* direct reference into compressed stream */ dctx->litPtr = istart+lhSize; dctx->litSize = litSize; - dctx->litBufferEnd = dctx->litPtr + litSize; - dctx->litBufferLocation = ZSTD_not_in_dst; return lhSize+litSize; } case set_rle: { U32 const lhlCode = ((istart[0]) >> 2) & 3; size_t litSize, lhSize; - size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -289,28 +214,16 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 1: lhSize = 2; - RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 3"); litSize = MEM_readLE16(istart) >> 4; break; case 3: lhSize = 3; - RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 4"); litSize = MEM_readLE24(istart) >> 4; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4"); break; } - RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); - RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); - ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); - if (dctx->litBufferLocation == ZSTD_split) - { - ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); - } - else - { - ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); - } + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected); + memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; return lhSize+1; @@ -323,7 +236,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, /* Default FSE distribution tables. * These are pre-calculated FSE decoding tables using default distributions as defined in specification : - * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions + * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions * They were generated programmatically with following method : * - start from default distributions, present in /lib/common/zstd_internal.h * - generate tables normally, using ZSTD_buildFSETable() @@ -430,7 +343,7 @@ static const ZSTD_seqSymbol ML_defaultDTable[(1<nbBits = 0; cell->nextState = 0; assert(nbAddBits < 255); - cell->nbAdditionalBits = nbAddBits; + cell->nbAdditionalBits = (BYTE)nbAddBits; cell->baseValue = baseValue; } @@ -451,26 +364,23 @@ static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U8 nbAddBi * generate FSE decoding table for one symbol (ll, ml or off) * cannot fail if input is valid => * all inputs are presumed validated at this stage */ -FORCE_INLINE_TEMPLATE -void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, +void +ZSTD_buildFSETable(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U8* nbAdditionalBits, - unsigned tableLog, void* wksp, size_t wkspSize) + const U32* baseValue, const U32* nbAdditionalBits, + unsigned tableLog) { ZSTD_seqSymbol* const tableDecode = dt+1; + U16 symbolNext[MaxSeq+1]; + U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; - - U16* symbolNext = (U16*)wksp; - BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); - U32 highThreshold = tableSize - 1; - + U32 highThreshold = tableSize-1; /* Sanity Checks */ assert(maxSymbolValue <= MaxSeq); assert(tableLog <= MaxFSELog); - assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); - (void)wkspSize; + /* Init, lay down lowprob symbols */ { ZSTD_seqSymbol_header DTableH; DTableH.tableLog = tableLog; @@ -486,128 +396,34 @@ void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, assert(normalizedCounter[s]>=0); symbolNext[s] = (U16)normalizedCounter[s]; } } } - ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - assert(tableSize <= 512); - /* Specialized symbol spreading for the case when there are - * no low probability (-1 count) symbols. When compressing - * small blocks we avoid low probability symbols to hit this - * case, since header decoding speed matters more. - */ - if (highThreshold == tableSize - 1) { - size_t const tableMask = tableSize-1; - size_t const step = FSE_TABLESTEP(tableSize); - /* First lay down the symbols in order. - * We use a uint64_t to lay down 8 bytes at a time. This reduces branch - * misses since small blocks generally have small table logs, so nearly - * all symbols have counts <= 8. We ensure we have 8 bytes at the end of - * our buffer to handle the over-write. - */ - { - U64 const add = 0x0101010101010101ull; - size_t pos = 0; - U64 sv = 0; - U32 s; - for (s=0; s=0); - pos += (size_t)n; - } - } - /* Now we spread those positions across the table. - * The benefit of doing it in two stages is that we avoid the - * variable size inner loop, which caused lots of branch misses. - * Now we can run through all the positions without any branch misses. - * We unroll the loop twice, since that is what empirically worked best. - */ - { - size_t position = 0; - size_t s; - size_t const unroll = 2; - assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ - for (s = 0; s < (size_t)tableSize; s += unroll) { - size_t u; - for (u = 0; u < unroll; ++u) { - size_t const uPosition = (position + (u * step)) & tableMask; - tableDecode[uPosition].baseValue = spread[s + u]; - } - position = (position + (unroll * step)) & tableMask; - } - assert(position == 0); - } - } else { - U32 const tableMask = tableSize-1; + { U32 const tableMask = tableSize-1; U32 const step = FSE_TABLESTEP(tableSize); U32 s, position = 0; for (s=0; s highThreshold)) position = (position + step) & tableMask; /* lowprob area */ + while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */ } } assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ } /* Build Decoding table */ - { - U32 u; + { U32 u; for (u=0; u max, corruption_detected, ""); + RETURN_ERROR_IF(!srcSize, srcSize_wrong); + RETURN_ERROR_IF((*(const BYTE*)src) > max, corruption_detected); { U32 const symbol = *(const BYTE*)src; U32 const baseline = baseValue[symbol]; - U8 const nbBits = nbAdditionalBits[symbol]; + U32 const nbBits = nbAdditionalBits[symbol]; ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); } *DTablePtr = DTableSpace; @@ -638,7 +453,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb *DTablePtr = defaultTable; return 0; case set_repeat: - RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, ""); + RETURN_ERROR_IF(!flagRepeatTable, corruption_detected); /* prefetch FSE table if used */ if (ddictIsCold && (nbSeq > 24 /* heuristic */)) { const void* const pStart = *DTablePtr; @@ -650,9 +465,9 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb { unsigned tableLog; S16 norm[MaxSeq+1]; size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); - RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); - RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); - ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); + RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected); + RETURN_ERROR_IF(tableLog > maxLog, corruption_detected); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog); *DTablePtr = DTableSpace; return headerSize; } @@ -665,36 +480,35 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE*)src; + const BYTE* const istart = (const BYTE* const)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; int nbSeq; DEBUGLOG(5, "ZSTD_decodeSeqHeaders"); /* check */ - RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong); /* SeqHead */ nbSeq = *ip++; if (!nbSeq) { *nbSeqPtr=0; - RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize != 1, srcSize_wrong); return 1; } if (nbSeq > 0x7F) { if (nbSeq == 0xFF) { - RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); - nbSeq = MEM_readLE16(ip) + LONGNBSEQ; - ip+=2; + RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong); + nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; } else { - RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); + RETURN_ERROR_IF(ip >= iend, srcSize_wrong); nbSeq = ((nbSeq-0x80)<<8) + *ip++; } } *nbSeqPtr = nbSeq; /* FSE table descriptors */ - RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ + RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong); /* minimum possible size: 1 byte for symbol encoding types */ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); @@ -706,10 +520,8 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip, iend-ip, LL_base, LL_bits, LL_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq, - dctx->workspace, sizeof(dctx->workspace), - ZSTD_DCtx_get_bmi2(dctx)); - RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + dctx->ddictIsCold, nbSeq); + RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected); ip += llhSize; } @@ -718,10 +530,8 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip, iend-ip, OF_base, OF_bits, OF_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq, - dctx->workspace, sizeof(dctx->workspace), - ZSTD_DCtx_get_bmi2(dctx)); - RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + dctx->ddictIsCold, nbSeq); + RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected); ip += ofhSize; } @@ -730,10 +540,8 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip, iend-ip, ML_base, ML_bits, ML_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq, - dctx->workspace, sizeof(dctx->workspace), - ZSTD_DCtx_get_bmi2(dctx)); - RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + dctx->ddictIsCold, nbSeq); + RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected); ip += mlhSize; } } @@ -746,6 +554,7 @@ typedef struct { size_t litLength; size_t matchLength; size_t offset; + const BYTE* match; } seq_t; typedef struct { @@ -759,6 +568,9 @@ typedef struct { ZSTD_fseState stateOffb; ZSTD_fseState stateML; size_t prevOffset[ZSTD_REP_NUM]; + const BYTE* prefixStart; + const BYTE* dictEnd; + size_t pos; } seqState_t; /*! ZSTD_overlapCopy8() : @@ -768,7 +580,7 @@ typedef struct { * Precondition: *ip <= *op * Postcondition: *op - *op >= 8 */ -HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { +static void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { assert(*ip <= *op); if (offset < 8) { /* close range match, overlap */ @@ -801,7 +613,7 @@ HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. * The src buffer must be before the dst buffer. */ -static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { +static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { ptrdiff_t const diff = op - ip; BYTE* const oend = op + length; @@ -817,7 +629,6 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ assert(length >= 8); ZSTD_overlapCopy8(&op, &ip, diff); - length -= 8; assert(op - ip >= 8); assert(op <= oend); } @@ -832,35 +643,12 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt assert(oend > oend_w); ZSTD_wildcopy(op, ip, oend_w - op, ovtype); ip += oend_w - op; - op += oend_w - op; + op = oend_w; } /* Handle the leftovers. */ while (op < oend) *op++ = *ip++; } -/* ZSTD_safecopyDstBeforeSrc(): - * This version allows overlap with dst before src, or handles the non-overlap case with dst after src - * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ -static void ZSTD_safecopyDstBeforeSrc(BYTE* op, BYTE const* ip, ptrdiff_t length) { - ptrdiff_t const diff = op - ip; - BYTE* const oend = op + length; - - if (length < 8 || diff > -8) { - /* Handle short lengths, close overlaps, and dst not before src. */ - while (op < oend) *op++ = *ip++; - return; - } - - if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { - ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); - ip += oend - WILDCOPY_OVERLENGTH - op; - op += oend - WILDCOPY_OVERLENGTH - op; - } - - /* Handle the leftovers. */ - while (op < oend) *op++ = *ip++; -} - /* ZSTD_execSequenceEnd(): * This version handles cases that are near the end of the output buffer. It requires * more careful checks to make sure there is no overflow. By separating out these hard @@ -871,21 +659,21 @@ static void ZSTD_safecopyDstBeforeSrc(BYTE* op, BYTE const* ip, ptrdiff_t length */ FORCE_NOINLINE size_t ZSTD_execSequenceEnd(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ const BYTE* const iLitEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; - /* bounds checks : careful of address space overflow in 32-bit mode */ - RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); - RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); - assert(op < op + sequenceLength); - assert(oLitEnd < op + sequenceLength); + /* bounds checks */ + assert(oLitEnd < oMatchEnd); + RETURN_ERROR_IF(oMatchEnd > oend, dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(iLitEnd > litLimit, corruption_detected, "try to read beyond literal buffer"); /* copy literals */ ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap); @@ -895,199 +683,42 @@ size_t ZSTD_execSequenceEnd(BYTE* op, /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { /* offset beyond prefix */ - RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); - match = dictEnd - (prefixStart - match); - if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); - return sequenceLength; - } - /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } - } - ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); - return sequenceLength; -} - -/* ZSTD_execSequenceEndSplitLitBuffer(): - * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. - */ -FORCE_NOINLINE -size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, - BYTE* const oend, const BYTE* const oend_w, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) -{ - BYTE* const oLitEnd = op + sequence.litLength; - size_t const sequenceLength = sequence.litLength + sequence.matchLength; - const BYTE* const iLitEnd = *litPtr + sequence.litLength; - const BYTE* match = oLitEnd - sequence.offset; - - - /* bounds checks : careful of address space overflow in 32-bit mode */ - RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); - RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); - assert(op < op + sequenceLength); - assert(oLitEnd < op + sequenceLength); - - /* copy literals */ - RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); - ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); - op = oLitEnd; - *litPtr = iLitEnd; - - /* copy Match */ - if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { - /* offset beyond prefix */ - RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); - match = dictEnd - (prefixStart - match); + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected); + match = dictEnd - (prefixStart-match); if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); + memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } - } + memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } } ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); return sequenceLength; } HINT_INLINE size_t ZSTD_execSequence(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ - BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */ + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; const BYTE* const iLitEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; - assert(op != NULL /* Precondition */); - assert(oend_w < oend /* No underflow */); - -#if defined(__aarch64__) - /* prefetch sequence starting from match that will be used for copy later */ - PREFETCH_L1(match); -#endif - /* Handle edge cases in a slow path: - * - Read beyond end of literals - * - Match end is within WILDCOPY_OVERLIMIT of oend - * - 32-bit mode and the match length overflows - */ - if (UNLIKELY( - iLitEnd > litLimit || - oMatchEnd > oend_w || - (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + /* Errors and uncommon cases handled here. */ + assert(oLitEnd < oMatchEnd); + if (iLitEnd > litLimit || oMatchEnd > oend_w) return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ - assert(op <= oLitEnd /* No overflow */); - assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); - assert(oMatchEnd <= oend /* No underflow */); - assert(iLitEnd <= litLimit /* Literal length is in bounds */); - assert(oLitEnd <= oend_w /* Can wildcopy literals */); - assert(oMatchEnd <= oend_w /* Can wildcopy matches */); - - /* Copy Literals: - * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. - * We likely don't need the full 32-byte wildcopy. - */ - assert(WILDCOPY_OVERLENGTH >= 16); - ZSTD_copy16(op, (*litPtr)); - if (UNLIKELY(sequence.litLength > 16)) { - ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); - } - op = oLitEnd; - *litPtr = iLitEnd; /* update for next sequence */ - - /* Copy Match */ - if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { - /* offset beyond prefix -> go into extDict */ - RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); - match = dictEnd + (match - prefixStart); - if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); - return sequenceLength; - } - /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } - } - /* Match within prefix of 1 or more bytes */ - assert(op <= oMatchEnd); - assert(oMatchEnd <= oend_w); - assert(match >= prefixStart); - assert(sequence.matchLength >= 1); - - /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy - * without overlap checking. - */ - if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { - /* We bet on a full wildcopy for matches, since we expect matches to be - * longer than literals (in general). In silesia, ~10% of matches are longer - * than 16 bytes. - */ - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); - return sequenceLength; - } - assert(sequence.offset < WILDCOPY_VECLEN); - - /* Copy 8 bytes and spread the offset to be >= 8. */ - ZSTD_overlapCopy8(&op, &match, sequence.offset); - - /* If the match length is > 8 bytes, then continue with the wildcopy. */ - if (sequence.matchLength > 8) { - assert(op < oMatchEnd); - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); - } - return sequenceLength; -} - -HINT_INLINE -size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, - BYTE* const oend, const BYTE* const oend_w, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) -{ - BYTE* const oLitEnd = op + sequence.litLength; - size_t const sequenceLength = sequence.litLength + sequence.matchLength; - BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ - const BYTE* const iLitEnd = *litPtr + sequence.litLength; - const BYTE* match = oLitEnd - sequence.offset; - - assert(op != NULL /* Precondition */); - assert(oend_w < oend /* No underflow */); - /* Handle edge cases in a slow path: - * - Read beyond end of literals - * - Match end is within WILDCOPY_OVERLIMIT of oend - * - 32-bit mode and the match length overflows - */ - if (UNLIKELY( - iLitEnd > litLimit || - oMatchEnd > oend_w || - (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) - return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); - - /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ - assert(op <= oLitEnd /* No overflow */); - assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); - assert(oMatchEnd <= oend /* No underflow */); assert(iLitEnd <= litLimit /* Literal length is in bounds */); assert(oLitEnd <= oend_w /* Can wildcopy literals */); assert(oMatchEnd <= oend_w /* Can wildcopy matches */); @@ -1098,7 +729,7 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, */ assert(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(op, (*litPtr)); - if (UNLIKELY(sequence.litLength > 16)) { + if (sequence.litLength > 16) { ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap); } op = oLitEnd; @@ -1107,15 +738,15 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, /* Copy Match */ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { /* offset beyond prefix -> go into extDict */ - RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected); match = dictEnd + (match - prefixStart); if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); + memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); + memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = prefixStart; @@ -1129,7 +760,7 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy * without overlap checking. */ - if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + if (sequence.offset >= WILDCOPY_VECLEN) { /* We bet on a full wildcopy for matches, since we expect matches to be * longer than literals (in general). In silesia, ~10% of matches are longer * than 16 bytes. @@ -1150,7 +781,6 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, return sequenceLength; } - static void ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) { @@ -1164,14 +794,16 @@ ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqS } FORCE_INLINE_TEMPLATE void -ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) +ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD) { + ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = nextState + lowBits; + DStatePtr->state = DInfo.nextState + lowBits; } /* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum - * offset bits. But we can only read at most STREAM_ACCUMULATOR_MIN_32 + * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1) * bits before reloading. This value is the maximum number of bytes we read * after reloading when we are decoding long offsets. */ @@ -1182,191 +814,102 @@ ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG FORCE_INLINE_TEMPLATE seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) { seq_t seq; - /* - * ZSTD_seqSymbol is a structure with a total of 64 bits wide. So it can be - * loaded in one operation and extracted its fields by simply shifting or - * bit-extracting on aarch64. - * GCC doesn't recognize this and generates more unnecessary ldr/ldrb/ldrh - * operations that cause performance drop. This can be avoided by using this - * ZSTD_memcpy hack. - */ -#if defined(__aarch64__) && (defined(__GNUC__) && !defined(__clang__)) - ZSTD_seqSymbol llDInfoS, mlDInfoS, ofDInfoS; - ZSTD_seqSymbol* const llDInfo = &llDInfoS; - ZSTD_seqSymbol* const mlDInfo = &mlDInfoS; - ZSTD_seqSymbol* const ofDInfo = &ofDInfoS; - ZSTD_memcpy(llDInfo, seqState->stateLL.table + seqState->stateLL.state, sizeof(ZSTD_seqSymbol)); - ZSTD_memcpy(mlDInfo, seqState->stateML.table + seqState->stateML.state, sizeof(ZSTD_seqSymbol)); - ZSTD_memcpy(ofDInfo, seqState->stateOffb.table + seqState->stateOffb.state, sizeof(ZSTD_seqSymbol)); -#else - const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; - const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; - const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; -#endif - seq.matchLength = mlDInfo->baseValue; - seq.litLength = llDInfo->baseValue; - { U32 const ofBase = ofDInfo->baseValue; - BYTE const llBits = llDInfo->nbAdditionalBits; - BYTE const mlBits = mlDInfo->nbAdditionalBits; - BYTE const ofBits = ofDInfo->nbAdditionalBits; - BYTE const totalBits = llBits+mlBits+ofBits; - - U16 const llNext = llDInfo->nextState; - U16 const mlNext = mlDInfo->nextState; - U16 const ofNext = ofDInfo->nextState; - U32 const llnbBits = llDInfo->nbBits; - U32 const mlnbBits = mlDInfo->nbBits; - U32 const ofnbBits = ofDInfo->nbBits; - - assert(llBits <= MaxLLBits); - assert(mlBits <= MaxMLBits); - assert(ofBits <= MaxOff); - /* - * As gcc has better branch and block analyzers, sometimes it is only - * valuable to mark likeliness for clang, it gives around 3-4% of - * performance. - */ - - /* sequence */ - { size_t offset; - if (ofBits > 1) { - ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); - ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32); - ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits); - if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { - /* Always read extra bits, this keeps the logic simple, - * avoids branches, and avoids accidentally reading 0 bits. - */ - U32 const extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32; - offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); - BIT_reloadDStream(&seqState->DStream); - offset += BIT_readBitsFast(&seqState->DStream, extraBits); - } else { - offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); - } - seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; + U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits; + U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits; + U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits; + U32 const totalBits = llBits+mlBits+ofBits; + U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue; + U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue; + U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue; + + /* sequence */ + { size_t offset; + if (!ofBits) + offset = 0; + else { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + assert(ofBits <= MaxOff); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ } else { - U32 const ll0 = (llDInfo->baseValue == 0); - if (LIKELY((ofBits == 0))) { - offset = seqState->prevOffset[ll0]; - seqState->prevOffset[1] = seqState->prevOffset[!ll0]; - seqState->prevOffset[0] = offset; - } else { - offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); - { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; - temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ - if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset = temp; - } } } - seq.offset = offset; + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } } - if (mlBits > 0) - seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); - - if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) - BIT_reloadDStream(&seqState->DStream); - if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) - BIT_reloadDStream(&seqState->DStream); - /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ - ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); - - if (llBits > 0) - seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); - - if (MEM_32bits()) - BIT_reloadDStream(&seqState->DStream); - - DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - - ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ - ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ - ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + if (ofBits <= 1) { + offset += (llBase==0); + if (offset) { + size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } else { /* offset == 0 */ + offset = seqState->prevOffset[0]; + } + } else { + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; + } + seq.offset = offset; } - return seq; -} - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) -{ - size_t const windowSize = dctx->fParams.windowSize; - /* No dictionary used. */ - if (dctx->dictContentEndForFuzzing == NULL) return 0; - /* Dictionary is our prefix. */ - if (prefixStart == dctx->dictContentBeginForFuzzing) return 1; - /* Dictionary is not our ext-dict. */ - if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0; - /* Dictionary is not within our window size. */ - if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0; - /* Dictionary is active. */ - return 1; -} + seq.matchLength = mlBase + + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/) : 0); /* <= 16 bits */ + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + seq.litLength = llBase + + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits/*>0*/) : 0); /* <= 16 bits */ + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + + /* ANS state update */ + ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ + ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ -MEM_STATIC void ZSTD_assertValidSequence( - ZSTD_DCtx const* dctx, - BYTE const* op, BYTE const* oend, - seq_t const seq, - BYTE const* prefixStart, BYTE const* virtualStart) -{ -#if DEBUGLEVEL >= 1 - size_t const windowSize = dctx->fParams.windowSize; - size_t const sequenceSize = seq.litLength + seq.matchLength; - BYTE const* const oLitEnd = op + seq.litLength; - DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - assert(op <= oend); - assert((size_t)(oend - op) >= sequenceSize); - assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); - if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { - size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); - /* Offset must be within the dictionary. */ - assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); - assert(seq.offset <= windowSize + dictSize); - } else { - /* Offset must be within our window. */ - assert(seq.offset <= windowSize); - } -#else - (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; -#endif + return seq; } -#endif - -#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG - FORCE_INLINE_TEMPLATE size_t DONT_VECTORIZE -ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, +ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const litEnd = litPtr + dctx->litSize; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer"); - (void)frame; + DEBUGLOG(5, "ZSTD_decompressSequences_body"); /* Regen sequences */ if (nbSeq) { @@ -1375,279 +918,38 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, { U32 i; for (i=0; ientropy.rep[i]; } RETURN_ERROR_IF( ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), - corruption_detected, ""); + corruption_detected); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); - assert(dst != NULL); ZSTD_STATIC_ASSERT( BIT_DStream_unfinished < BIT_DStream_completed && BIT_DStream_endOfBuffer < BIT_DStream_completed && BIT_DStream_completed < BIT_DStream_overflow); - /* decompress without overrunning litPtr begins */ - { - seq_t sequence = ZSTD_decodeSequence(&seqState, isLongOffset); - /* Align the decompression loop to 32 + 16 bytes. - * - * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression - * speed swings based on the alignment of the decompression loop. This - * performance swing is caused by parts of the decompression loop falling - * out of the DSB. The entire decompression loop should fit in the DSB, - * when it can't we get much worse performance. You can measure if you've - * hit the good case or the bad case with this perf command for some - * compressed file test.zst: - * - * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ - * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst - * - * If you see most cycles served out of the MITE you've hit the bad case. - * If you see most cycles served out of the DSB you've hit the good case. - * If it is pretty even then you may be in an okay case. - * - * This issue has been reproduced on the following CPUs: - * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 - * Use Instruments->Counters to get DSB/MITE cycles. - * I never got performance swings, but I was able to - * go from the good case of mostly DSB to half of the - * cycles served from MITE. - * - Coffeelake: Intel i9-9900k - * - Coffeelake: Intel i7-9700k - * - * I haven't been able to reproduce the instability or DSB misses on any - * of the following CPUS: - * - Haswell - * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH - * - Skylake - * - * Alignment is done for each of the three major decompression loops: - * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer - * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer - * - ZSTD_decompressSequences_body - * Alignment choices are made to minimize large swings on bad cases and influence on performance - * from changes external to this code, rather than to overoptimize on the current commit. - * - * If you are seeing performance stability this script can help test. - * It tests on 4 commits in zstd where I saw performance change. - * - * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 - */ -#if defined(__GNUC__) && defined(__x86_64__) - __asm__(".p2align 6"); -# if __GNUC__ >= 7 - /* good for gcc-7, gcc-9, and gcc-11 */ - __asm__("nop"); - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 4"); -# if __GNUC__ == 8 || __GNUC__ == 10 - /* good for gcc-8 and gcc-10 */ - __asm__("nop"); - __asm__(".p2align 3"); -# endif -# endif -#endif - - /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ - for (; litPtr + sequence.litLength <= dctx->litBufferEnd; ) { - size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; - if (UNLIKELY(!--nbSeq)) - break; - BIT_reloadDStream(&(seqState.DStream)); - sequence = ZSTD_decodeSequence(&seqState, isLongOffset); - } - - /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ - if (nbSeq > 0) { - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - if (leftoverLit) - { - RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); - ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); - sequence.litLength -= leftoverLit; - op += leftoverLit; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - { - size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; - if (--nbSeq) - BIT_reloadDStream(&(seqState.DStream)); - } - } - } - - if (nbSeq > 0) /* there is remaining lit from extra buffer */ - { - -#if defined(__GNUC__) && defined(__x86_64__) - __asm__(".p2align 6"); - __asm__("nop"); -# if __GNUC__ != 7 - /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ - __asm__(".p2align 4"); - __asm__("nop"); - __asm__(".p2align 3"); -# elif __GNUC__ >= 11 - __asm__(".p2align 3"); -# else - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 3"); -# endif -#endif - - for (; ; ) { - seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); - size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; + for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) { + nbSeq--; + { seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; - if (UNLIKELY(!--nbSeq)) - break; - BIT_reloadDStream(&(seqState.DStream)); - } - } - - /* check if reached exact end */ - DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); - RETURN_ERROR_IF(nbSeq, corruption_detected, ""); - RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); - /* save reps for next block */ - { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } - } - - /* last literal segment */ - if (dctx->litBufferLocation == ZSTD_split) /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ - { - size_t const lastLLSize = litBufferEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - } - { size_t const lastLLSize = litBufferEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } - } - - return op-ostart; -} - -FORCE_INLINE_TEMPLATE size_t -DONT_VECTORIZE -ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) -{ - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ostart + maxDstSize : dctx->litBuffer; - BYTE* op = ostart; - const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; - const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); - const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); - const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); - DEBUGLOG(5, "ZSTD_decompressSequences_body: nbSeq = %d", nbSeq); - (void)frame; - - /* Regen sequences */ - if (nbSeq) { - seqState_t seqState; - dctx->fseEntropy = 1; - { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } - RETURN_ERROR_IF( - ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), - corruption_detected, ""); - ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); - ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); - ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); - assert(dst != NULL); - - ZSTD_STATIC_ASSERT( - BIT_DStream_unfinished < BIT_DStream_completed && - BIT_DStream_endOfBuffer < BIT_DStream_completed && - BIT_DStream_completed < BIT_DStream_overflow); - -#if defined(__GNUC__) && defined(__x86_64__) - __asm__(".p2align 6"); - __asm__("nop"); -# if __GNUC__ >= 7 - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 3"); -# else - __asm__(".p2align 4"); - __asm__("nop"); - __asm__(".p2align 3"); -# endif -#endif - - for ( ; ; ) { - seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); - size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; - if (UNLIKELY(!--nbSeq)) - break; - BIT_reloadDStream(&(seqState.DStream)); - } + } } /* check if reached exact end */ DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); - RETURN_ERROR_IF(nbSeq, corruption_detected, ""); - RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + RETURN_ERROR_IF(nbSeq, corruption_detected); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected); /* save reps for next block */ { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } } /* last literal segment */ { size_t const lastLLSize = litEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall); + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; } return op-ostart; @@ -1657,180 +959,157 @@ static size_t ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); -} - -static size_t -ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) -{ - return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ -#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -FORCE_INLINE_TEMPLATE size_t -ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, - const BYTE* const prefixStart, const BYTE* const dictEnd) + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +FORCE_INLINE_TEMPLATE seq_t +ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets) { - prefetchPos += sequence.litLength; - { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; - const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. - * No consequence though : memory address is only used for prefetching, not for dereferencing */ - PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ + seq_t seq; + U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits; + U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits; + U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits; + U32 const totalBits = llBits+mlBits+ofBits; + U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue; + U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue; + U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue; + + /* sequence */ + { size_t offset; + if (!ofBits) + offset = 0; + else { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + assert(ofBits <= MaxOff); + if (MEM_32bits() && longOffsets) { + U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1); + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + } + + if (ofBits <= 1) { + offset += (llBase==0); + if (offset) { + size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } else { + offset = seqState->prevOffset[0]; + } + } else { + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; + } + seq.offset = offset; + } + + seq.matchLength = mlBase + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */ + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + seq.litLength = llBase + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */ + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + { size_t const pos = seqState->pos + seq.litLength; + const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart; + seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */ + seqState->pos = pos + seq.matchLength; } - return prefetchPos + sequence.matchLength; + + /* ANS state update */ + ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ + ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ + + return seq; } -/* This decoding function employs prefetching - * to reduce latency impact of cache misses. - * It's generally employed when block contains a significant portion of long-distance matches - * or when coupled with a "cold" dictionary */ FORCE_INLINE_TEMPLATE size_t ZSTD_decompressSequencesLong_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ostart + maxDstSize; + BYTE* const ostart = (BYTE* const)dst; + BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const litEnd = litPtr + dctx->litSize; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - (void)frame; /* Regen sequences */ if (nbSeq) { -#define STORED_SEQS 8 +#define STORED_SEQS 4 #define STORED_SEQS_MASK (STORED_SEQS-1) -#define ADVANCED_SEQS STORED_SEQS +#define ADVANCED_SEQS 4 seq_t sequences[STORED_SEQS]; int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); seqState_t seqState; int seqNb; - size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ - dctx->fseEntropy = 1; { int i; for (i=0; ientropy.rep[i]; } - assert(dst != NULL); + seqState.prefixStart = prefixStart; + seqState.pos = (size_t)(op-prefixStart); + seqState.dictEnd = dictEnd; assert(iend >= ip); RETURN_ERROR_IF( ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), - corruption_detected, ""); + corruption_detected); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); /* prepare in advance */ for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) - { - /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - if (leftoverLit) - { - RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); - ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); - sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; - op += leftoverLit; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); -#endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - - prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); - sequences[seqNb & STORED_SEQS_MASK] = sequence; - op += oneSeqSize; - } - else - { - /* lit buffer is either wholly contained in first or second split, or not split at all*/ - oneSeqSize = dctx->litBufferLocation == ZSTD_split ? - ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : - ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); -#endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - - prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); - sequences[seqNb & STORED_SEQS_MASK] = sequence; - op += oneSeqSize; - } + RETURN_ERROR_IF(seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) - { - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - if (leftoverLit) - { - RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); - ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); - sequence->litLength -= leftoverLit; - op += leftoverLit; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - { - size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); -#endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; - } - } - else - { - size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? - ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : - ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); -#endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; - } + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd); + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; } /* save reps for next block */ @@ -1838,23 +1117,10 @@ ZSTD_decompressSequencesLong_body( } /* last literal segment */ - if (dctx->litBufferLocation == ZSTD_split) /* first deplete literal buffer in dst, then copy litExtraBuffer */ - { - size_t const lastLLSize = litBufferEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - } - { size_t const lastLLSize = litBufferEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } + { size_t const lastLLSize = litEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall); + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; } return op-ostart; @@ -1864,10 +1130,9 @@ static size_t ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1876,37 +1141,25 @@ ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, #if DYNAMIC_BMI2 #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t DONT_VECTORIZE ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); -} -static BMI2_TARGET_ATTRIBUTE size_t -DONT_VECTORIZE -ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) -{ - return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1916,37 +1169,21 @@ typedef size_t (*ZSTD_decompressSequences_t)( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame); + const ZSTD_longOffset_e isLongOffset); #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG static size_t ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { DEBUGLOG(5, "ZSTD_decompressSequences"); #if DYNAMIC_BMI2 - if (ZSTD_DCtx_get_bmi2(dctx)) { - return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); - } -#endif - return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); -} -static size_t -ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) -{ - DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); -#if DYNAMIC_BMI2 - if (ZSTD_DCtx_get_bmi2(dctx)) { - return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + if (dctx->bmi2) { + return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif - return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ @@ -1961,115 +1198,69 @@ static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { DEBUGLOG(5, "ZSTD_decompressSequencesLong"); #if DYNAMIC_BMI2 - if (ZSTD_DCtx_get_bmi2(dctx)) { - return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + if (dctx->bmi2) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif - return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ -/** - * @returns The total size of the history referenceable by zstd, including - * both the prefix and the extDict. At @p op any offset larger than this - * is invalid. - */ -static size_t ZSTD_totalHistorySize(BYTE* op, BYTE const* virtualStart) -{ - return (size_t)(op - virtualStart); -} - -typedef struct { - unsigned longOffsetShare; - unsigned maxNbAdditionalBits; -} ZSTD_OffsetInfo; -/* ZSTD_getOffsetInfo() : +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +/* ZSTD_getLongOffsetsShare() : * condition : offTable must be valid * @return : "share" of long offsets (arbitrarily defined as > (1<<23)) - * compared to maximum possible of (1< 22) info.longOffsetShare += 1; - } - - assert(tableLog <= OffFSELog); - info.longOffsetShare <<= (OffFSELog - tableLog); /* scale to OffFSELog */ + const void* ptr = offTable; + U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog; + const ZSTD_seqSymbol* table = offTable + 1; + U32 const max = 1 << tableLog; + U32 u, total = 0; + DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog); + + assert(max <= (1 << OffFSELog)); /* max not too large */ + for (u=0; u 22) total += 1; } - return info; -} + assert(tableLog <= OffFSELog); + total <<= (OffFSELog - tableLog); /* scale to OffFSELog */ -/** - * @returns The maximum offset we can decode in one read of our bitstream, without - * reloading more bits in the middle of the offset bits read. Any offsets larger - * than this must use the long offset decoder. - */ -static size_t ZSTD_maxShortOffset(void) -{ - if (MEM_64bits()) { - /* We can decode any offset without reloading bits. - * This might change if the max window size grows. - */ - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); - return (size_t)-1; - } else { - /* The maximum offBase is (1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1. - * This offBase would require STREAM_ACCUMULATOR_MIN extra bits. - * Then we have to subtract ZSTD_REP_NUM to get the maximum possible offset. - */ - size_t const maxOffbase = ((size_t)1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1; - size_t const maxOffset = maxOffbase - ZSTD_REP_NUM; - assert(ZSTD_highbit32((U32)maxOffbase) == STREAM_ACCUMULATOR_MIN); - return maxOffset; - } + return total; } +#endif + size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const int frame, const streaming_operation streaming) + const void* src, size_t srcSize, const int frame) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN. + * We don't expect that to be the case in 64-bit mode. + * In block mode, window size is not known, so we have to be conservative. + * (note: but it could be evaluated from current-lowLimit) + */ + ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)))); DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); - /* Note : the wording of the specification - * allows compressed block to be sized exactly ZSTD_BLOCKSIZE_MAX. - * This generally does not happen, as it makes little sense, - * since an uncompressed block would feature same size and have no decompression cost. - * Also, note that decoder from reference libzstd before < v1.5.4 - * would consider this edge case as an error. - * As a consequence, avoid generating compressed blocks of size ZSTD_BLOCKSIZE_MAX - * for broader compatibility with the deployed ecosystem of zstd decoders */ - RETURN_ERROR_IF(srcSize > ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong); /* Decode literals section */ - { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); - DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : cSize=%u, nbLiterals=%zu", (U32)litCSize, dctx->litSize); + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; @@ -2077,23 +1268,6 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, /* Build Decoding Tables */ { - /* Compute the maximum block size, which must also work when !frame and fParams are unset. - * Additionally, take the min with dstCapacity to ensure that the totalHistorySize fits in a size_t. - */ - size_t const blockSizeMax = MIN(dstCapacity, (frame ? dctx->fParams.blockSizeMax : ZSTD_BLOCKSIZE_MAX)); - size_t const totalHistorySize = ZSTD_totalHistorySize((BYTE*)dst + blockSizeMax, (BYTE const*)dctx->virtualStart); - /* isLongOffset must be true if there are long offsets. - * Offsets are long if they are larger than ZSTD_maxShortOffset(). - * We don't expect that to be the case in 64-bit mode. - * - * We check here to see if our history is large enough to allow long offsets. - * If it isn't, then we can't possible have (valid) long offsets. If the offset - * is invalid, then it is okay to read it incorrectly. - * - * If isLongOffsets is true, then we will later check our decoding table to see - * if it is even possible to generate long offsets. - */ - ZSTD_longOffset_e isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (totalHistorySize > ZSTD_maxShortOffset())); /* These macros control at build-time which decompressor implementation * we use. If neither is defined, we do some inspection and dispatch at * runtime. @@ -2101,11 +1275,6 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) int usePrefetchDecoder = dctx->ddictIsCold; -#else - /* Set to 1 to avoid computing offset info if we don't need to. - * Otherwise this value is ignored. - */ - int usePrefetchDecoder = 1; #endif int nbSeq; size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize); @@ -2113,83 +1282,42 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ip += seqHSize; srcSize -= seqHSize; - RETURN_ERROR_IF((dst == NULL || dstCapacity == 0) && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(MEM_64bits() && sizeof(size_t) == sizeof(void*) && (size_t)(-1) - (size_t)dst < (size_t)(1 << 20), dstSize_tooSmall, - "invalid dst"); - - /* If we could potentially have long offsets, or we might want to use the prefetch decoder, - * compute information about the share of long offsets, and the maximum nbAdditionalBits. - * NOTE: could probably use a larger nbSeq limit - */ - if (isLongOffset || (!usePrefetchDecoder && (totalHistorySize > (1u << 24)) && (nbSeq > 8))) { - ZSTD_OffsetInfo const info = ZSTD_getOffsetInfo(dctx->OFTptr, nbSeq); - if (isLongOffset && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN) { - /* If isLongOffset, but the maximum number of additional bits that we see in our table is small - * enough, then we know it is impossible to have too long an offset in this block, so we can - * use the regular offset decoder. - */ - isLongOffset = ZSTD_lo_isRegularOffset; - } - if (!usePrefetchDecoder) { - U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ - usePrefetchDecoder = (info.longOffsetShare >= minShare); - } +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if ( !usePrefetchDecoder + && (!frame || (dctx->fParams.windowSize > (1<<24))) + && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */ + U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr); + U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ + usePrefetchDecoder = (shareLongOffsets >= minShare); } +#endif dctx->ddictIsCold = 0; #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) - if (usePrefetchDecoder) { -#else - (void)usePrefetchDecoder; - { + if (usePrefetchDecoder) #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT - return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); #endif - } #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG /* else */ - if (dctx->litBufferLocation == ZSTD_split) - return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); - else - return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); #endif } } -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) -{ - if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ - dctx->dictEnd = dctx->previousDstEnd; - dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); - dctx->prefixStart = dst; - dctx->previousDstEnd = dst; - } -} - - -size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - size_t dSize; - ZSTD_checkContinuity(dctx, dst, dstCapacity); - dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0, not_streaming); - dctx->previousDstEnd = (char*)dst + dSize; - return dSize; -} - - -/* NOTE: Must just wrap ZSTD_decompressBlock_deprecated() */ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - return ZSTD_decompressBlock_deprecated(dctx, dst, dstCapacity, src, srcSize); + size_t dSize; + ZSTD_checkContinuity(dctx, dst); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0); + dctx->previousDstEnd = (char*)dst + dSize; + return dSize; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_decompress_block.h b/vendor/github.com/DataDog/zstd/zstd_decompress_block.h index a6df799e..7e929604 100644 --- a/vendor/github.com/DataDog/zstd/zstd_decompress_block.h +++ b/vendor/github.com/DataDog/zstd/zstd_decompress_block.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,7 +15,7 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd_deps.h" /* size_t */ +#include /* size_t */ #include "zstd.h" /* DCtx, and some public functions */ #include "zstd_internal.h" /* blockProperties_t, and some public functions */ #include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ @@ -34,12 +33,6 @@ */ - /* Streaming state is used to inform allocation of the literal buffer */ -typedef enum { - not_streaming = 0, - is_streaming = 1 -} streaming_operation; - /* ZSTD_decompressBlock_internal() : * decompress block, starting at `src`, * into destination buffer `dst`. @@ -48,29 +41,19 @@ typedef enum { */ size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const int frame, const streaming_operation streaming); + const void* src, size_t srcSize, const int frame); /* ZSTD_buildFSETable() : * generate FSE decoding table for one symbol (ll, ml or off) * this function must be called with valid parameters only * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) * in which case it cannot fail. - * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is - * defined in zstd_decompress_internal.h. * Internal use only. */ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U8* nbAdditionalBits, - unsigned tableLog, void* wksp, size_t wkspSize, - int bmi2); - -/* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */ -size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); + const U32* baseValue, const U32* nbAdditionalBits, + unsigned tableLog); #endif /* ZSTD_DEC_BLOCK_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_decompress_internal.h b/vendor/github.com/DataDog/zstd/zstd_decompress_internal.h index 7ce46329..ccbdfa09 100644 --- a/vendor/github.com/DataDog/zstd/zstd_decompress_internal.h +++ b/vendor/github.com/DataDog/zstd/zstd_decompress_internal.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -21,33 +20,33 @@ * Dependencies *********************************************************/ #include "mem.h" /* BYTE, U16, U32 */ -#include "zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ +#include "zstd_internal.h" /* ZSTD_seqSymbol */ /*-******************************************************* * Constants *********************************************************/ -static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { +static const U32 LL_base[MaxLL+1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000 }; -static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { +static const U32 OF_base[MaxOff+1] = { 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; -static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { +static const U32 OF_bits[MaxOff+1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; -static UNUSED_ATTR const U32 ML_base[MaxML+1] = { +static const U32 ML_base[MaxML+1] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, @@ -74,17 +73,12 @@ static UNUSED_ATTR const U32 ML_base[MaxML+1] = { #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) -#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) -#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) -#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 - typedef struct { ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ - HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ U32 rep[ZSTD_REP_NUM]; - U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; } ZSTD_entropyDTables_t; typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, @@ -101,29 +95,6 @@ typedef enum { ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ } ZSTD_dictUses_e; -/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ -typedef struct { - const ZSTD_DDict** ddictPtrTable; - size_t ddictPtrTableSize; - size_t ddictPtrCount; -} ZSTD_DDictHashSet; - -#ifndef ZSTD_DECODER_INTERNAL_BUFFER -# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) -#endif - -#define ZSTD_LBMIN 64 -#define ZSTD_LBMAX (128 << 10) - -/* extra buffer, compensates when dst is not large enough to store litBuffer */ -#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) - -typedef enum { - ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ - ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ - ZSTD_split = 2 /* Split between litExtraBuffer and dst */ -} ZSTD_litLocation_e; - struct ZSTD_DCtx_s { const ZSTD_seqSymbol* LLTptr; @@ -138,7 +109,6 @@ struct ZSTD_DCtx_s const void* dictEnd; /* end of previous segment */ size_t expected; ZSTD_frameHeader fParams; - U64 processedCSize; U64 decodedSize; blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ ZSTD_dStage stage; @@ -147,16 +117,12 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; - ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ - U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; size_t rleSize; size_t staticSize; -#if DYNAMIC_BMI2 != 0 int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ -#endif /* dictionary */ ZSTD_DDict* ddictLocal; @@ -164,9 +130,6 @@ struct ZSTD_DCtx_s U32 dictID; int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ ZSTD_dictUses_e dictUses; - ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ - ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ - int disableHufAsm; /* streaming */ ZSTD_dStreamStage streamStage; @@ -179,44 +142,17 @@ struct ZSTD_DCtx_s size_t outStart; size_t outEnd; size_t lhSize; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) void* legacyContext; U32 previousLegacyVersion; U32 legacyVersion; -#endif U32 hostageByte; int noForwardProgress; - ZSTD_bufferMode_e outBufferMode; - ZSTD_outBuffer expectedOutBuffer; /* workspace */ - BYTE* litBuffer; - const BYTE* litBufferEnd; - ZSTD_litLocation_e litBufferLocation; - BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ + BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; - - size_t oversizedDuration; - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - void const* dictContentBeginForFuzzing; - void const* dictContentEndForFuzzing; -#endif - - /* Tracing */ -#if ZSTD_TRACE - ZSTD_TraceCtx traceCtx; -#endif }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ -MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { -#if DYNAMIC_BMI2 != 0 - return dctx->bmi2; -#else - (void)dctx; - return 0; -#endif -} /*-******************************************************* * Shared internal functions @@ -224,7 +160,7 @@ MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { /*! ZSTD_loadDEntropy() : * dict : must point at beginning of a valid zstd dictionary. - * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */ + * @return : size of entropy tables read */ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, const void* const dict, size_t const dictSize); @@ -233,9 +169,7 @@ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, * If yes, do nothing (continue on current segment). * If not, classify previous segment as "external dictionary", and start a new segment. * This function cannot fail. */ -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst); #endif /* ZSTD_DECOMPRESS_INTERNAL_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_deps.h b/vendor/github.com/DataDog/zstd/zstd_deps.h deleted file mode 100644 index 949e0231..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_deps.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/* This file provides common libc dependencies that zstd requires. - * The purpose is to allow replacing this file with a custom implementation - * to compile zstd without libc support. - */ - -/* Need: - * NULL - * INT_MAX - * UINT_MAX - * ZSTD_memcpy() - * ZSTD_memset() - * ZSTD_memmove() - */ -#ifndef ZSTD_DEPS_COMMON -#define ZSTD_DEPS_COMMON - -#include -#include -#include - -#if defined(__GNUC__) && __GNUC__ >= 4 -# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) -# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) -# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) -#else -# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) -# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) -# define ZSTD_memset(p,v,l) memset((p),(v),(l)) -#endif - -#endif /* ZSTD_DEPS_COMMON */ - -/* Need: - * ZSTD_malloc() - * ZSTD_free() - * ZSTD_calloc() - */ -#ifdef ZSTD_DEPS_NEED_MALLOC -#ifndef ZSTD_DEPS_MALLOC -#define ZSTD_DEPS_MALLOC - -#include - -#define ZSTD_malloc(s) malloc(s) -#define ZSTD_calloc(n,s) calloc((n), (s)) -#define ZSTD_free(p) free((p)) - -#endif /* ZSTD_DEPS_MALLOC */ -#endif /* ZSTD_DEPS_NEED_MALLOC */ - -/* - * Provides 64-bit math support. - * Need: - * U64 ZSTD_div64(U64 dividend, U32 divisor) - */ -#ifdef ZSTD_DEPS_NEED_MATH64 -#ifndef ZSTD_DEPS_MATH64 -#define ZSTD_DEPS_MATH64 - -#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) - -#endif /* ZSTD_DEPS_MATH64 */ -#endif /* ZSTD_DEPS_NEED_MATH64 */ - -/* Need: - * assert() - */ -#ifdef ZSTD_DEPS_NEED_ASSERT -#ifndef ZSTD_DEPS_ASSERT -#define ZSTD_DEPS_ASSERT - -#include - -#endif /* ZSTD_DEPS_ASSERT */ -#endif /* ZSTD_DEPS_NEED_ASSERT */ - -/* Need: - * ZSTD_DEBUG_PRINT() - */ -#ifdef ZSTD_DEPS_NEED_IO -#ifndef ZSTD_DEPS_IO -#define ZSTD_DEPS_IO - -#include -#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) - -#endif /* ZSTD_DEPS_IO */ -#endif /* ZSTD_DEPS_NEED_IO */ - -/* Only requested when is known to be present. - * Need: - * intptr_t - */ -#ifdef ZSTD_DEPS_NEED_STDINT -#ifndef ZSTD_DEPS_STDINT -#define ZSTD_DEPS_STDINT - -#include - -#endif /* ZSTD_DEPS_STDINT */ -#endif /* ZSTD_DEPS_NEED_STDINT */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_double_fast.c b/vendor/github.com/DataDog/zstd/zstd_double_fast.c index 458533f7..a661a485 100644 --- a/vendor/github.com/DataDog/zstd/zstd_double_fast.c +++ b/vendor/github.com/DataDog/zstd/zstd_double_fast.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -12,43 +11,8 @@ #include "zstd_compress_internal.h" #include "zstd_double_fast.h" -static void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm) -{ - const ZSTD_compressionParameters* const cParams = &ms->cParams; - U32* const hashLarge = ms->hashTable; - U32 const hBitsL = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; - U32 const mls = cParams->minMatch; - U32* const hashSmall = ms->chainTable; - U32 const hBitsS = cParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; - const BYTE* const base = ms->window.base; - const BYTE* ip = base + ms->nextToUpdate; - const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; - const U32 fastHashFillStep = 3; - - /* Always insert every fastHashFillStep position into the hash tables. - * Insert the other positions into the large hash table if their entry - * is empty. - */ - for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); - U32 i; - for (i = 0; i < fastHashFillStep; ++i) { - size_t const smHashAndTag = ZSTD_hashPtr(ip + i, hBitsS, mls); - size_t const lgHashAndTag = ZSTD_hashPtr(ip + i, hBitsL, 8); - if (i == 0) { - ZSTD_writeTaggedIndex(hashSmall, smHashAndTag, curr + i); - } - if (i == 0 || hashLarge[lgHashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { - ZSTD_writeTaggedIndex(hashLarge, lgHashAndTag, curr + i); - } - /* Only load extra positions for ZSTD_dtlm_full */ - if (dtlm == ZSTD_dtlm_fast) - break; - } } -} -static void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms, +void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, void const* end, ZSTD_dictTableLoadMethod_e dtlm) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -67,249 +31,27 @@ static void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms, * is empty. */ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); + U32 const current = (U32)(ip - base); U32 i; for (i = 0; i < fastHashFillStep; ++i) { size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls); size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8); if (i == 0) - hashSmall[smHash] = curr + i; + hashSmall[smHash] = current + i; if (i == 0 || hashLarge[lgHash] == 0) - hashLarge[lgHash] = curr + i; + hashLarge[lgHash] = current + i; /* Only load extra positions for ZSTD_dtlm_full */ if (dtlm == ZSTD_dtlm_fast) break; - } } -} - -void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, - const void* const end, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp) -{ - if (tfp == ZSTD_tfp_forCDict) { - ZSTD_fillDoubleHashTableForCDict(ms, end, dtlm); - } else { - ZSTD_fillDoubleHashTableForCCtx(ms, end, dtlm); - } -} - - -FORCE_INLINE_TEMPLATE -size_t ZSTD_compressBlock_doubleFast_noDict_generic( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls /* template */) -{ - ZSTD_compressionParameters const* cParams = &ms->cParams; - U32* const hashLong = ms->hashTable; - const U32 hBitsL = cParams->hashLog; - U32* const hashSmall = ms->chainTable; - const U32 hBitsS = cParams->chainLog; - const BYTE* const base = ms->window.base; - const BYTE* const istart = (const BYTE*)src; - const BYTE* anchor = istart; - const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - /* presumes that, if there is a dictionary, it must be using Attach mode */ - const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); - const BYTE* const prefixLowest = base + prefixLowestIndex; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - HASH_READ_SIZE; - U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; - - size_t mLength; - U32 offset; - U32 curr; - - /* how many positions to search before increasing step size */ - const size_t kStepIncr = 1 << kSearchStrength; - /* the position at which to increment the step size if no match is found */ - const BYTE* nextStep; - size_t step; /* the current step size */ - - size_t hl0; /* the long hash at ip */ - size_t hl1; /* the long hash at ip1 */ - - U32 idxl0; /* the long match index for ip */ - U32 idxl1; /* the long match index for ip1 */ - - const BYTE* matchl0; /* the long match for ip */ - const BYTE* matchs0; /* the short match for ip */ - const BYTE* matchl1; /* the long match for ip1 */ - - const BYTE* ip = istart; /* the current position */ - const BYTE* ip1; /* the next position */ - - DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic"); - - /* init */ - ip += ((ip - prefixLowest) == 0); - { - U32 const current = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); - U32 const maxRep = current - windowLow; - if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; - } - - /* Outer Loop: one iteration per match found and stored */ - while (1) { - step = 1; - nextStep = ip + kStepIncr; - ip1 = ip + step; - - if (ip1 > ilimit) { - goto _cleanup; - } - - hl0 = ZSTD_hashPtr(ip, hBitsL, 8); - idxl0 = hashLong[hl0]; - matchl0 = base + idxl0; - - /* Inner Loop: one iteration per search / position */ - do { - const size_t hs0 = ZSTD_hashPtr(ip, hBitsS, mls); - const U32 idxs0 = hashSmall[hs0]; - curr = (U32)(ip-base); - matchs0 = base + idxs0; - - hashLong[hl0] = hashSmall[hs0] = curr; /* update hash tables */ - - /* check noDict repcode */ - if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { - mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); - goto _match_stored; - } - - hl1 = ZSTD_hashPtr(ip1, hBitsL, 8); - - if (idxl0 > prefixLowestIndex) { - /* check prefix long match */ - if (MEM_read64(matchl0) == MEM_read64(ip)) { - mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8; - offset = (U32)(ip-matchl0); - while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */ - goto _match_found; - } - } - - idxl1 = hashLong[hl1]; - matchl1 = base + idxl1; - - if (idxs0 > prefixLowestIndex) { - /* check prefix short match */ - if (MEM_read32(matchs0) == MEM_read32(ip)) { - goto _search_next_long; - } - } - - if (ip1 >= nextStep) { - PREFETCH_L1(ip1 + 64); - PREFETCH_L1(ip1 + 128); - step++; - nextStep += kStepIncr; - } - ip = ip1; - ip1 += step; - - hl0 = hl1; - idxl0 = idxl1; - matchl0 = matchl1; - #if defined(__aarch64__) - PREFETCH_L1(ip+256); - #endif - } while (ip1 <= ilimit); - -_cleanup: - /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), - * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ - offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; - - /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved1; - rep[1] = offset_2 ? offset_2 : offsetSaved2; - - /* Return the last literals size */ - return (size_t)(iend - anchor); - -_search_next_long: - - /* check prefix long +1 match */ - if (idxl1 > prefixLowestIndex) { - if (MEM_read64(matchl1) == MEM_read64(ip1)) { - ip = ip1; - mLength = ZSTD_count(ip+8, matchl1+8, iend) + 8; - offset = (U32)(ip-matchl1); - while (((ip>anchor) & (matchl1>prefixLowest)) && (ip[-1] == matchl1[-1])) { ip--; matchl1--; mLength++; } /* catch up */ - goto _match_found; - } - } - - /* if no long +1 match, explore the short match we found */ - mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4; - offset = (U32)(ip - matchs0); - while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* catch up */ - - /* fall-through */ - -_match_found: /* requires ip, offset, mLength */ - offset_2 = offset_1; - offset_1 = offset; - - if (step < 4) { - /* It is unsafe to write this value back to the hashtable when ip1 is - * greater than or equal to the new ip we will have after we're done - * processing this match. Rather than perform that test directly - * (ip1 >= ip + mLength), which costs speed in practice, we do a simpler - * more predictable test. The minmatch even if we take a short match is - * 4 bytes, so as long as step, the distance between ip and ip1 - * (initially) is less than 4, we know ip1 < new ip. */ - hashLong[hl1] = (U32)(ip1 - base); - } - - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); - -_match_stored: - /* match found */ - ip += mLength; - anchor = ip; - - if (ip <= ilimit) { - /* Complementary insertion */ - /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = curr+2; - hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; - hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); - hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; - hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base); - } - - /* check immediate repcode */ - while ( (ip <= ilimit) - && ( (offset_2>0) - & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { - /* store sequence */ - size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, rLength); - ip += rLength; - anchor = ip; - continue; /* faster when present ... (?) */ - } - } - } + } } } FORCE_INLINE_TEMPLATE -size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( +size_t ZSTD_compressBlock_doubleFast_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls /* template */) + U32 const mls /* template */, ZSTD_dictMode_e const dictMode) { ZSTD_compressionParameters const* cParams = &ms->cParams; U32* const hashLong = ms->hashTable; @@ -321,45 +63,63 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 lowestValid = ms->window.dictLimit; + const U32 maxDistance = 1U << cParams->windowLog; /* presumes that, if there is a dictionary, it must be using Attach mode */ - const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid; const BYTE* const prefixLowest = base + prefixLowestIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dictCParams = &dms->cParams; - const U32* const dictHashLong = dms->hashTable; - const U32* const dictHashSmall = dms->chainTable; - const U32 dictStartIndex = dms->window.dictLimit; - const BYTE* const dictBase = dms->window.base; - const BYTE* const dictStart = dictBase + dictStartIndex; - const BYTE* const dictEnd = dms->window.nextSrc; - const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase); - const U32 dictHBitsL = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; - const U32 dictHBitsS = dictCParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; - const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart)); - - DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic"); + const ZSTD_compressionParameters* const dictCParams = + dictMode == ZSTD_dictMatchState ? + &dms->cParams : NULL; + const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ? + dms->hashTable : NULL; + const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ? + dms->chainTable : NULL; + const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ? + dms->window.dictLimit : 0; + const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? + dms->window.base : NULL; + const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ? + dictBase + dictStartIndex : NULL; + const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? + dms->window.nextSrc : NULL; + const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? + prefixLowestIndex - (U32)(dictEnd - dictBase) : + 0; + const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ? + dictCParams->hashLog : hBitsL; + const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ? + dictCParams->chainLog : hBitsS; + const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart); + + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic"); + + assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); /* if a dictionary is attached, it must be within window range */ - assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); - - if (ms->prefetchCDictTables) { - size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); - size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32); - PREFETCH_AREA(dictHashLong, hashTableBytes) - PREFETCH_AREA(dictHashSmall, chainTableBytes) + if (dictMode == ZSTD_dictMatchState) { + assert(lowestValid + maxDistance >= endIndex); } /* init */ ip += (dictAndPrefixLength == 0); - - /* dictMatchState repCode checks don't currently handle repCode == 0 - * disabling. */ - assert(offset_1 <= dictAndPrefixLength); - assert(offset_2 <= dictAndPrefixLength); + if (dictMode == ZSTD_noDict) { + U32 const maxRep = (U32)(ip - prefixLowest); + if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; + } + if (dictMode == ZSTD_dictMatchState) { + /* dictMatchState repCode checks don't currently handle repCode == 0 + * disabling. */ + assert(offset_1 <= dictAndPrefixLength); + assert(offset_2 <= dictAndPrefixLength); + } /* Main Search Loop */ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ @@ -367,30 +127,37 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( U32 offset; size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8); size_t const h = ZSTD_hashPtr(ip, hBitsS, mls); - size_t const dictHashAndTagL = ZSTD_hashPtr(ip, dictHBitsL, 8); - size_t const dictHashAndTagS = ZSTD_hashPtr(ip, dictHBitsS, mls); - U32 const dictMatchIndexAndTagL = dictHashLong[dictHashAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS]; - U32 const dictMatchIndexAndTagS = dictHashSmall[dictHashAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS]; - int const dictTagsMatchL = ZSTD_comparePackedTags(dictMatchIndexAndTagL, dictHashAndTagL); - int const dictTagsMatchS = ZSTD_comparePackedTags(dictMatchIndexAndTagS, dictHashAndTagS); - U32 const curr = (U32)(ip-base); + size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8); + size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls); + U32 const current = (U32)(ip-base); U32 const matchIndexL = hashLong[h2]; U32 matchIndexS = hashSmall[h]; const BYTE* matchLong = base + matchIndexL; const BYTE* match = base + matchIndexS; - const U32 repIndex = curr + 1 - offset_1; - const BYTE* repMatch = (repIndex < prefixLowestIndex) ? + const U32 repIndex = current + 1 - offset_1; + const BYTE* repMatch = (dictMode == ZSTD_dictMatchState + && repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; - hashLong[h2] = hashSmall[h] = curr; /* update hash tables */ + hashLong[h2] = hashSmall[h] = current; /* update hash tables */ - /* check repcode */ - if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) + /* check dictMatchState repcode */ + if (dictMode == ZSTD_dictMatchState + && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + goto _match_stored; + } + + /* check noDict repcode */ + if ( dictMode == ZSTD_noDict + && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { + mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); goto _match_stored; } @@ -402,15 +169,15 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictTagsMatchL) { + } else if (dictMode == ZSTD_dictMatchState) { /* check dictMatchState long match */ - U32 const dictMatchIndexL = dictMatchIndexAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const dictMatchIndexL = dictHashLong[dictHL]; const BYTE* dictMatchL = dictBase + dictMatchIndexL; assert(dictMatchL < dictEnd); if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) { mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8; - offset = (U32)(curr - dictMatchIndexL - dictIndexDelta); + offset = (U32)(current - dictMatchIndexL - dictIndexDelta); while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */ goto _match_found; } } @@ -420,9 +187,9 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( if (MEM_read32(match) == MEM_read32(ip)) { goto _search_next_long; } - } else if (dictTagsMatchS) { + } else if (dictMode == ZSTD_dictMatchState) { /* check dictMatchState short match */ - U32 const dictMatchIndexS = dictMatchIndexAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const dictMatchIndexS = dictHashSmall[dictHS]; match = dictBase + dictMatchIndexS; matchIndexS = dictMatchIndexS + dictIndexDelta; @@ -431,19 +198,15 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( } } ip += ((ip-anchor) >> kSearchStrength) + 1; -#if defined(__aarch64__) - PREFETCH_L1(ip+256); -#endif continue; _search_next_long: + { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); - size_t const dictHashAndTagL3 = ZSTD_hashPtr(ip+1, dictHBitsL, 8); + size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8); U32 const matchIndexL3 = hashLong[hl3]; - U32 const dictMatchIndexAndTagL3 = dictHashLong[dictHashAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS]; - int const dictTagsMatchL3 = ZSTD_comparePackedTags(dictMatchIndexAndTagL3, dictHashAndTagL3); const BYTE* matchL3 = base + matchIndexL3; - hashLong[hl3] = curr + 1; + hashLong[hl3] = current + 1; /* check prefix long +1 match */ if (matchIndexL3 > prefixLowestIndex) { @@ -454,23 +217,23 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictTagsMatchL3) { + } else if (dictMode == ZSTD_dictMatchState) { /* check dict long +1 match */ - U32 const dictMatchIndexL3 = dictMatchIndexAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const dictMatchIndexL3 = dictHashLong[dictHLNext]; const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3; assert(dictMatchL3 < dictEnd); if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) { mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8; ip++; - offset = (U32)(curr + 1 - dictMatchIndexL3 - dictIndexDelta); + offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta); while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */ goto _match_found; } } } /* if no long +1 match, explore the short match we found */ - if (matchIndexS < prefixLowestIndex) { + if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) { mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4; - offset = (U32)(curr - matchIndexS); + offset = (U32)(current - matchIndexS); while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } else { mLength = ZSTD_count(ip+4, match+4, iend) + 4; @@ -478,11 +241,13 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } + /* fall-through */ + _match_found: offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); _match_stored: /* match found */ @@ -492,7 +257,7 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = curr+2; + { U32 const indexToInsert = current+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -500,55 +265,53 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( } /* check immediate repcode */ - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - offset_2; - const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ? - dictBase + repIndex2 - dictIndexDelta : - base + repIndex2; - if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; - U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; - ip += repLength2; + if (dictMode == ZSTD_dictMatchState) { + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; + const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState + && repIndex2 < prefixLowestIndex ? + dictBase - dictIndexDelta + repIndex2 : + base + repIndex2; + if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; + U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; + ip += repLength2; + anchor = ip; + continue; + } + break; + } } + + if (dictMode == ZSTD_noDict) { + while ( (ip <= ilimit) + && ( (offset_2>0) + & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { + /* store sequence */ + size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; + U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, rLength-MINMATCH); + ip += rLength; anchor = ip; - continue; - } - break; - } - } + continue; /* faster when present ... (?) */ + } } } } /* while (ip < ilimit) */ /* save reps for next block */ - rep[0] = offset_1; - rep[1] = offset_2; + rep[0] = offset_1 ? offset_1 : offsetSaved; + rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ return (size_t)(iend - anchor); } -#define ZSTD_GEN_DFAST_FN(dictMode, mls) \ - static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \ - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ - void const* src, size_t srcSize) \ - { \ - return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \ - } - -ZSTD_GEN_DFAST_FN(noDict, 4) -ZSTD_GEN_DFAST_FN(noDict, 5) -ZSTD_GEN_DFAST_FN(noDict, 6) -ZSTD_GEN_DFAST_FN(noDict, 7) - -ZSTD_GEN_DFAST_FN(dictMatchState, 4) -ZSTD_GEN_DFAST_FN(dictMatchState, 5) -ZSTD_GEN_DFAST_FN(dictMatchState, 6) -ZSTD_GEN_DFAST_FN(dictMatchState, 7) - size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -559,13 +322,13 @@ size_t ZSTD_compressBlock_doubleFast( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_noDict_4(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict); case 5 : - return ZSTD_compressBlock_doubleFast_noDict_5(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict); case 6 : - return ZSTD_compressBlock_doubleFast_noDict_6(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict); case 7 : - return ZSTD_compressBlock_doubleFast_noDict_7(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict); } } @@ -579,13 +342,13 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_dictMatchState_4(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState); case 5 : - return ZSTD_compressBlock_doubleFast_dictMatchState_5(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState); case 6 : - return ZSTD_compressBlock_doubleFast_dictMatchState_6(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState); case 7 : - return ZSTD_compressBlock_doubleFast_dictMatchState_7(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState); } } @@ -621,7 +384,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( /* if extDict is invalidated due to maxDistance, switch to "regular" variant */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_doubleFast(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict); /* Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ @@ -635,31 +398,31 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base; const BYTE* matchLong = matchLongBase + matchLongIndex; - const U32 curr = (U32)(ip-base); - const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */ + const U32 current = (U32)(ip-base); + const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; size_t mLength; - hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */ + hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */ - & (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */ + & (repIndex > dictStartIndex)) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); } else { if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart; U32 offset; mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8; - offset = curr - matchLongIndex; + offset = current - matchLongIndex; while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) { size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); @@ -667,24 +430,24 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base; const BYTE* match3 = match3Base + matchIndex3; U32 offset; - hashLong[h3] = curr + 1; + hashLong[h3] = current + 1; if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) { const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8; ip++; - offset = curr+1 - matchIndex3; + offset = current+1 - matchIndex3; while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */ } else { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; - offset = curr - matchIndex; + offset = current - matchIndex; while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } else { ip += ((ip-anchor) >> kSearchStrength) + 1; @@ -698,7 +461,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = curr+2; + { U32 const indexToInsert = current+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -711,12 +474,12 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */ - & (offset_2 <= current2 - dictStartIndex)) + & (repIndex2 > dictStartIndex)) && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; ip += repLength2; @@ -734,10 +497,6 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( return (size_t)(iend - anchor); } -ZSTD_GEN_DFAST_FN(extDict, 4) -ZSTD_GEN_DFAST_FN(extDict, 5) -ZSTD_GEN_DFAST_FN(extDict, 6) -ZSTD_GEN_DFAST_FN(extDict, 7) size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -748,14 +507,12 @@ size_t ZSTD_compressBlock_doubleFast_extDict( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_extDict_4(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_doubleFast_extDict_5(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_doubleFast_extDict_6(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); } } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_double_fast.h b/vendor/github.com/DataDog/zstd/zstd_double_fast.h index bdafd495..4fa31acf 100644 --- a/vendor/github.com/DataDog/zstd/zstd_double_fast.h +++ b/vendor/github.com/DataDog/zstd/zstd_double_fast.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,8 +19,7 @@ extern "C" { #include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp); + void const* end, ZSTD_dictTableLoadMethod_e dtlm); size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -38,5 +36,3 @@ size_t ZSTD_compressBlock_doubleFast_extDict( #endif #endif /* ZSTD_DOUBLE_FAST_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_errors.h b/vendor/github.com/DataDog/zstd/zstd_errors.h index 4064ecb1..92a34338 100644 --- a/vendor/github.com/DataDog/zstd/zstd_errors.h +++ b/vendor/github.com/DataDog/zstd/zstd_errors.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -21,31 +20,19 @@ extern "C" { /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDERRORLIB_VISIBLE - /* Backwards compatibility with old macro name */ -# ifdef ZSTDERRORLIB_VISIBILITY -# define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY -# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default"))) +#ifndef ZSTDERRORLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) # else -# define ZSTDERRORLIB_VISIBLE +# define ZSTDERRORLIB_VISIBILITY # endif #endif - -#ifndef ZSTDERRORLIB_HIDDEN -# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden"))) -# else -# define ZSTDERRORLIB_HIDDEN -# endif -#endif - #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY #endif /*-********************************************* @@ -71,17 +58,14 @@ typedef enum { ZSTD_error_frameParameter_windowTooLarge = 16, ZSTD_error_corruption_detected = 20, ZSTD_error_checksum_wrong = 22, - ZSTD_error_literals_headerWrong = 24, ZSTD_error_dictionary_corrupted = 30, ZSTD_error_dictionary_wrong = 32, ZSTD_error_dictionaryCreation_failed = 34, ZSTD_error_parameter_unsupported = 40, - ZSTD_error_parameter_combination_unsupported = 41, ZSTD_error_parameter_outOfBound = 42, ZSTD_error_tableLog_tooLarge = 44, ZSTD_error_maxSymbolValue_tooLarge = 46, ZSTD_error_maxSymbolValue_tooSmall = 48, - ZSTD_error_stabilityCondition_notRespected = 50, ZSTD_error_stage_wrong = 60, ZSTD_error_init_missing = 62, ZSTD_error_memory_allocation = 64, @@ -89,15 +73,9 @@ typedef enum { ZSTD_error_dstSize_tooSmall = 70, ZSTD_error_srcSize_wrong = 72, ZSTD_error_dstBuffer_null = 74, - ZSTD_error_noForwardProgress_destFull = 80, - ZSTD_error_noForwardProgress_inputEmpty = 82, /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ ZSTD_error_frameIndex_tooLarge = 100, ZSTD_error_seekableIO = 102, - ZSTD_error_dstBuffer_wrong = 104, - ZSTD_error_srcBuffer_wrong = 105, - ZSTD_error_sequenceProducer_failed = 106, - ZSTD_error_externalSequences_invalid = 107, ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ } ZSTD_ErrorCode; @@ -113,5 +91,3 @@ ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Sa #endif #endif /* ZSTD_ERRORS_H_398273423 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_fast.c b/vendor/github.com/DataDog/zstd/zstd_fast.c index 1b60c21f..6dbefee6 100644 --- a/vendor/github.com/DataDog/zstd/zstd_fast.c +++ b/vendor/github.com/DataDog/zstd/zstd_fast.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -12,42 +11,8 @@ #include "zstd_compress_internal.h" /* ZSTD_hashPtr, ZSTD_count, ZSTD_storeSeq */ #include "zstd_fast.h" -static void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms, - const void* const end, - ZSTD_dictTableLoadMethod_e dtlm) -{ - const ZSTD_compressionParameters* const cParams = &ms->cParams; - U32* const hashTable = ms->hashTable; - U32 const hBits = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; - U32 const mls = cParams->minMatch; - const BYTE* const base = ms->window.base; - const BYTE* ip = base + ms->nextToUpdate; - const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; - const U32 fastHashFillStep = 3; - - /* Currently, we always use ZSTD_dtlm_full for filling CDict tables. - * Feel free to remove this assert if there's a good reason! */ - assert(dtlm == ZSTD_dtlm_full); - /* Always insert every fastHashFillStep position into the hash table. - * Insert the other positions if their hash entry is empty. - */ - for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); - { size_t const hashAndTag = ZSTD_hashPtr(ip, hBits, mls); - ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr); } - - if (dtlm == ZSTD_dtlm_fast) continue; - /* Only load extra positions for ZSTD_dtlm_full */ - { U32 p; - for (p = 1; p < fastHashFillStep; ++p) { - size_t const hashAndTag = ZSTD_hashPtr(ip + p, hBits, mls); - if (hashTable[hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { /* not yet filled */ - ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr + p); - } } } } -} - -static void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms, +void ZSTD_fillHashTable(ZSTD_matchState_t* ms, const void* const end, ZSTD_dictTableLoadMethod_e dtlm) { @@ -60,365 +25,152 @@ static void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms, const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; const U32 fastHashFillStep = 3; - /* Currently, we always use ZSTD_dtlm_fast for filling CCtx tables. - * Feel free to remove this assert if there's a good reason! */ - assert(dtlm == ZSTD_dtlm_fast); - /* Always insert every fastHashFillStep position into the hash table. * Insert the other positions if their hash entry is empty. */ for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); + U32 const current = (U32)(ip - base); size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls); - hashTable[hash0] = curr; + hashTable[hash0] = current; if (dtlm == ZSTD_dtlm_fast) continue; /* Only load extra positions for ZSTD_dtlm_full */ { U32 p; for (p = 1; p < fastHashFillStep; ++p) { size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls); if (hashTable[hash] == 0) { /* not yet filled */ - hashTable[hash] = curr + p; + hashTable[hash] = current + p; } } } } } -void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - const void* const end, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp) -{ - if (tfp == ZSTD_tfp_forCDict) { - ZSTD_fillHashTableForCDict(ms, end, dtlm); - } else { - ZSTD_fillHashTableForCCtx(ms, end, dtlm); - } -} - -/** - * If you squint hard enough (and ignore repcodes), the search operation at any - * given position is broken into 4 stages: - * - * 1. Hash (map position to hash value via input read) - * 2. Lookup (map hash val to index via hashtable read) - * 3. Load (map index to value at that position via input read) - * 4. Compare - * - * Each of these steps involves a memory read at an address which is computed - * from the previous step. This means these steps must be sequenced and their - * latencies are cumulative. - * - * Rather than do 1->2->3->4 sequentially for a single position before moving - * onto the next, this implementation interleaves these operations across the - * next few positions: - * - * R = Repcode Read & Compare - * H = Hash - * T = Table Lookup - * M = Match Read & Compare - * - * Pos | Time --> - * ----+------------------- - * N | ... M - * N+1 | ... TM - * N+2 | R H T M - * N+3 | H TM - * N+4 | R H T M - * N+5 | H ... - * N+6 | R ... - * - * This is very much analogous to the pipelining of execution in a CPU. And just - * like a CPU, we have to dump the pipeline when we find a match (i.e., take a - * branch). - * - * When this happens, we throw away our current state, and do the following prep - * to re-enter the loop: - * - * Pos | Time --> - * ----+------------------- - * N | H T - * N+1 | H - * - * This is also the work we do at the beginning to enter the loop initially. - */ FORCE_INLINE_TEMPLATE size_t -ZSTD_compressBlock_fast_noDict_generic( +ZSTD_compressBlock_fast_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls, U32 const hasStep) + U32 const mls) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - size_t const stepSize = hasStep ? (cParams->targetLength + !(cParams->targetLength) + 1) : 2; + size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; + /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */ + const BYTE* ip0 = istart; + const BYTE* ip1; + const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 validStartIndex = ms->window.dictLimit; + const U32 prefixStartIndex = (endIndex - validStartIndex > maxDistance) ? endIndex - maxDistance : validStartIndex; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; + U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved = 0; - const BYTE* anchor = istart; - const BYTE* ip0 = istart; - const BYTE* ip1; - const BYTE* ip2; - const BYTE* ip3; - U32 current0; - - U32 rep_offset1 = rep[0]; - U32 rep_offset2 = rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; - - size_t hash0; /* hash for ip0 */ - size_t hash1; /* hash for ip1 */ - U32 idx; /* match idx for ip0 */ - U32 mval; /* src value at match idx */ - - U32 offcode; - const BYTE* match0; - size_t mLength; - - /* ip0 and ip1 are always adjacent. The targetLength skipping and - * uncompressibility acceleration is applied to every other position, - * matching the behavior of #1562. step therefore represents the gap - * between pairs of positions, from ip0 to ip2 or ip1 to ip3. */ - size_t step; - const BYTE* nextStep; - const size_t kStepIncr = (1 << (kSearchStrength - 1)); - + /* init */ DEBUGLOG(5, "ZSTD_compressBlock_fast_generic"); ip0 += (ip0 == prefixStart); - { U32 const curr = (U32)(ip0 - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog); - U32 const maxRep = curr - windowLow; - if (rep_offset2 > maxRep) offsetSaved2 = rep_offset2, rep_offset2 = 0; - if (rep_offset1 > maxRep) offsetSaved1 = rep_offset1, rep_offset1 = 0; - } - - /* start each op */ -_start: /* Requires: ip0 */ - - step = stepSize; - nextStep = ip0 + kStepIncr; - - /* calculate positions, ip0 - anchor == 0, so we skip step calc */ ip1 = ip0 + 1; - ip2 = ip0 + step; - ip3 = ip2 + 1; - - if (ip3 >= ilimit) { - goto _cleanup; + { U32 const maxRep = (U32)(ip0 - prefixStart); + if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; } - hash0 = ZSTD_hashPtr(ip0, hlog, mls); - hash1 = ZSTD_hashPtr(ip1, hlog, mls); - - idx = hashTable[hash0]; - - do { - /* load repcode match for ip[2]*/ - const U32 rval = MEM_read32(ip2 - rep_offset1); - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - /* check repcode at ip[2] */ - if ((MEM_read32(ip2) == rval) & (rep_offset1 > 0)) { - ip0 = ip2; - match0 = ip0 - rep_offset1; - mLength = ip0[-1] == match0[-1]; - ip0 -= mLength; - match0 -= mLength; - offcode = REPCODE1_TO_OFFBASE; - mLength += 4; - - /* First write next hash table entry; we've already calculated it. - * This write is known to be safe because the ip1 is before the - * repcode (ip2). */ - hashTable[hash1] = (U32)(ip1 - base); - + /* Main Search Loop */ + while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */ + size_t mLength; + BYTE const* ip2 = ip0 + 2; + size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls); + U32 const val0 = MEM_read32(ip0); + size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls); + U32 const val1 = MEM_read32(ip1); + U32 const current0 = (U32)(ip0-base); + U32 const current1 = (U32)(ip1-base); + U32 const matchIndex0 = hashTable[h0]; + U32 const matchIndex1 = hashTable[h1]; + BYTE const* repMatch = ip2-offset_1; + const BYTE* match0 = base + matchIndex0; + const BYTE* match1 = base + matchIndex1; + U32 offcode; + hashTable[h0] = current0; /* update hash table */ + hashTable[h1] = current1; /* update hash table */ + + assert(ip0 + 1 == ip1); + + if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) { + mLength = ip2[-1] == repMatch[-1] ? 1 : 0; + ip0 = ip2 - mLength; + match0 = repMatch - mLength; + offcode = 0; goto _match; } - - /* load match for ip[0] */ - if (idx >= prefixStartIndex) { - mval = MEM_read32(base + idx); - } else { - mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ - } - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - - /* First write next hash table entry; we've already calculated it. - * This write is known to be safe because the ip1 == ip0 + 1, so - * we know we will resume searching after ip1 */ - hashTable[hash1] = (U32)(ip1 - base); - + if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) { + /* found a regular match */ goto _offset; } - - /* lookup ip[1] */ - idx = hashTable[hash1]; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip3; - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - /* load match for ip[0] */ - if (idx >= prefixStartIndex) { - mval = MEM_read32(base + idx); - } else { - mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ - } - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - - /* first write next hash table entry; we've already calculated it */ - if (step <= 4) { - /* We need to avoid writing an index into the hash table >= the - * position at which we will pick up our searching after we've - * taken this match. - * - * The minimum possible match has length 4, so the earliest ip0 - * can be after we take this match will be the current ip0 + 4. - * ip1 is ip0 + step - 1. If ip1 is >= ip0 + 4, we can't safely - * write this position. - */ - hashTable[hash1] = (U32)(ip1 - base); - } - + if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) { + /* found a regular match after one literal */ + ip0 = ip1; + match0 = match1; goto _offset; } - - /* lookup ip[1] */ - idx = hashTable[hash1]; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip0 + step; - ip3 = ip1 + step; - - /* calculate step */ - if (ip2 >= nextStep) { - step++; - PREFETCH_L1(ip1 + 64); - PREFETCH_L1(ip1 + 128); - nextStep += kStepIncr; + { size_t const step = ((size_t)(ip0-anchor) >> (kSearchStrength - 1)) + stepSize; + assert(step >= 2); + ip0 += step; + ip1 += step; + continue; } - } while (ip3 < ilimit); - -_cleanup: - /* Note that there are probably still a couple positions we could search. - * However, it seems to be a meaningful performance hit to try to search - * them. So let's not. */ - - /* When the repcodes are outside of the prefix, we set them to zero before the loop. - * When the offsets are still zero, we need to restore them after the block to have a correct - * repcode history. If only one offset was invalid, it is easy. The tricky case is when both - * offsets were invalid. We need to figure out which offset to refill with. - * - If both offsets are zero they are in the same order. - * - If both offsets are non-zero, we won't restore the offsets from `offsetSaved[12]`. - * - If only one is zero, we need to decide which offset to restore. - * - If rep_offset1 is non-zero, then rep_offset2 must be offsetSaved1. - * - It is impossible for rep_offset2 to be non-zero. - * - * So if rep_offset1 started invalid (offsetSaved1 != 0) and became valid (rep_offset1 != 0), then - * set rep[0] = rep_offset1 and rep[1] = offsetSaved1. - */ - offsetSaved2 = ((offsetSaved1 != 0) && (rep_offset1 != 0)) ? offsetSaved1 : offsetSaved2; - - /* save reps for next block */ - rep[0] = rep_offset1 ? rep_offset1 : offsetSaved1; - rep[1] = rep_offset2 ? rep_offset2 : offsetSaved2; - - /* Return the last literals size */ - return (size_t)(iend - anchor); - -_offset: /* Requires: ip0, idx */ - - /* Compute the offset code. */ - match0 = base + idx; - rep_offset2 = rep_offset1; - rep_offset1 = (U32)(ip0-match0); - offcode = OFFSET_TO_OFFBASE(rep_offset1); - mLength = 4; - - /* Count the backwards match length. */ - while (((ip0>anchor) & (match0>prefixStart)) && (ip0[-1] == match0[-1])) { - ip0--; - match0--; - mLength++; - } +_offset: /* Requires: ip0, match0 */ + /* Compute the offset code */ + offset_2 = offset_1; + offset_1 = (U32)(ip0-match0); + offcode = offset_1 + ZSTD_REP_MOVE; + mLength = 0; + /* Count the backwards match length */ + while (((ip0>anchor) & (match0>prefixStart)) + && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */ _match: /* Requires: ip0, match0, offcode */ + /* Count the forward length */ + mLength += ZSTD_count(ip0+mLength+4, match0+mLength+4, iend) + 4; + ZSTD_storeSeq(seqStore, (size_t)(ip0-anchor), anchor, iend, offcode, mLength-MINMATCH); + /* match found */ + ip0 += mLength; + anchor = ip0; + ip1 = ip0 + 1; - /* Count the forward length. */ - mLength += ZSTD_count(ip0 + mLength, match0 + mLength, iend); - - ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); - - ip0 += mLength; - anchor = ip0; - - /* Fill table and check for immediate repcode. */ - if (ip0 <= ilimit) { - /* Fill Table */ - assert(base+current0+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + if (ip0 <= ilimit) { + /* Fill Table */ + assert(base+current0+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); - if (rep_offset2 > 0) { /* rep_offset2==0 means rep_offset2 is invalidated */ - while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - rep_offset2)) ) { + while ( ((ip0 <= ilimit) & (offset_2>0)) /* offset_2==0 means offset_2 is invalidated */ + && (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) ) { /* store sequence */ - size_t const rLength = ZSTD_count(ip0+4, ip0+4-rep_offset2, iend) + 4; - { U32 const tmpOff = rep_offset2; rep_offset2 = rep_offset1; rep_offset1 = tmpOff; } /* swap rep_offset2 <=> rep_offset1 */ + size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4; + { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); ip0 += rLength; - ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, REPCODE1_TO_OFFBASE, rLength); + ip1 = ip0 + 1; + ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, 0 /*offCode*/, rLength-MINMATCH); anchor = ip0; continue; /* faster when present (confirmed on gcc-8) ... (?) */ - } } } - - goto _start; -} - -#define ZSTD_GEN_FAST_FN(dictMode, mls, step) \ - static size_t ZSTD_compressBlock_fast_##dictMode##_##mls##_##step( \ - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ - void const* src, size_t srcSize) \ - { \ - return ZSTD_compressBlock_fast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls, step); \ + } + } } -ZSTD_GEN_FAST_FN(noDict, 4, 1) -ZSTD_GEN_FAST_FN(noDict, 5, 1) -ZSTD_GEN_FAST_FN(noDict, 6, 1) -ZSTD_GEN_FAST_FN(noDict, 7, 1) + /* save reps for next block */ + rep[0] = offset_1 ? offset_1 : offsetSaved; + rep[1] = offset_2 ? offset_2 : offsetSaved; + + /* Return the last literals size */ + return (size_t)(iend - anchor); +} -ZSTD_GEN_FAST_FN(noDict, 4, 0) -ZSTD_GEN_FAST_FN(noDict, 5, 0) -ZSTD_GEN_FAST_FN(noDict, 6, 0) -ZSTD_GEN_FAST_FN(noDict, 7, 0) size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -426,40 +178,24 @@ size_t ZSTD_compressBlock_fast( { U32 const mls = ms->cParams.minMatch; assert(ms->dictMatchState == NULL); - if (ms->cParams.targetLength > 1) { - switch(mls) - { - default: /* includes case 3 */ - case 4 : - return ZSTD_compressBlock_fast_noDict_4_1(ms, seqStore, rep, src, srcSize); - case 5 : - return ZSTD_compressBlock_fast_noDict_5_1(ms, seqStore, rep, src, srcSize); - case 6 : - return ZSTD_compressBlock_fast_noDict_6_1(ms, seqStore, rep, src, srcSize); - case 7 : - return ZSTD_compressBlock_fast_noDict_7_1(ms, seqStore, rep, src, srcSize); - } - } else { - switch(mls) - { - default: /* includes case 3 */ - case 4 : - return ZSTD_compressBlock_fast_noDict_4_0(ms, seqStore, rep, src, srcSize); - case 5 : - return ZSTD_compressBlock_fast_noDict_5_0(ms, seqStore, rep, src, srcSize); - case 6 : - return ZSTD_compressBlock_fast_noDict_6_0(ms, seqStore, rep, src, srcSize); - case 7 : - return ZSTD_compressBlock_fast_noDict_7_0(ms, seqStore, rep, src, srcSize); - } - + switch(mls) + { + default: /* includes case 3 */ + case 4 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4); + case 5 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5); + case 6 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6); + case 7 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7); } } FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_fast_dictMatchState_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls, U32 const hasStep) + void const* src, size_t srcSize, U32 const mls) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; @@ -468,14 +204,14 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( U32 const stepSize = cParams->targetLength + !(cParams->targetLength); const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const BYTE* ip0 = istart; - const BYTE* ip1 = ip0 + stepSize; /* we assert below that stepSize >= 1 */ + const BYTE* ip = istart; const BYTE* anchor = istart; const U32 prefixStartIndex = ms->window.dictLimit; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; @@ -485,182 +221,125 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( const BYTE* const dictStart = dictBase + dictStartIndex; const BYTE* const dictEnd = dms->window.nextSrc; const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase); - const U32 dictAndPrefixLength = (U32)(istart - prefixStart + dictEnd - dictStart); - const U32 dictHBits = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); + const U32 dictHLog = dictCParams->hashLog; /* if a dictionary is still attached, it necessarily means that * it is within window size. So we just check it. */ const U32 maxDistance = 1U << cParams->windowLog; - const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); assert(endIndex - prefixStartIndex <= maxDistance); (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ - (void)hasStep; /* not currently specialized on whether it's accelerated */ - - /* ensure there will be no underflow + /* ensure there will be no no underflow * when translating a dict index into a local index */ assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); - if (ms->prefetchCDictTables) { - size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); - PREFETCH_AREA(dictHashTable, hashTableBytes) - } - /* init */ DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic"); - ip0 += (dictAndPrefixLength == 0); + ip += (dictAndPrefixLength == 0); /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); - /* Outer search loop */ - assert(stepSize >= 1); - while (ip1 <= ilimit) { /* repcode check at (ip0 + 1) is safe because ip0 < ip1 */ + /* Main Search Loop */ + while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ size_t mLength; - size_t hash0 = ZSTD_hashPtr(ip0, hlog, mls); - - size_t const dictHashAndTag0 = ZSTD_hashPtr(ip0, dictHBits, mls); - U32 dictMatchIndexAndTag = dictHashTable[dictHashAndTag0 >> ZSTD_SHORT_CACHE_TAG_BITS]; - int dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag0); - - U32 matchIndex = hashTable[hash0]; - U32 curr = (U32)(ip0 - base); - size_t step = stepSize; - const size_t kStepIncr = 1 << kSearchStrength; - const BYTE* nextStep = ip0 + kStepIncr; - - /* Inner search loop */ - while (1) { - const BYTE* match = base + matchIndex; - const U32 repIndex = curr + 1 - offset_1; - const BYTE* repMatch = (repIndex < prefixStartIndex) ? - dictBase + (repIndex - dictIndexDelta) : - base + repIndex; - const size_t hash1 = ZSTD_hashPtr(ip1, hlog, mls); - size_t const dictHashAndTag1 = ZSTD_hashPtr(ip1, dictHBits, mls); - hashTable[hash0] = curr; /* update hash table */ - - if (((U32) ((prefixStartIndex - 1) - repIndex) >= - 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ - && (MEM_read32(repMatch) == MEM_read32(ip0 + 1))) { - const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - mLength = ZSTD_count_2segments(ip0 + 1 + 4, repMatch + 4, iend, repMatchEnd, prefixStart) + 4; - ip0++; - ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); - break; - } - - if (dictTagsMatch) { - /* Found a possible dict match */ - const U32 dictMatchIndex = dictMatchIndexAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; - const BYTE* dictMatch = dictBase + dictMatchIndex; - if (dictMatchIndex > dictStartIndex && - MEM_read32(dictMatch) == MEM_read32(ip0)) { - /* To replicate extDict parse behavior, we only use dict matches when the normal matchIndex is invalid */ - if (matchIndex <= prefixStartIndex) { - U32 const offset = (U32) (curr - dictMatchIndex - dictIndexDelta); - mLength = ZSTD_count_2segments(ip0 + 4, dictMatch + 4, iend, dictEnd, prefixStart) + 4; - while (((ip0 > anchor) & (dictMatch > dictStart)) - && (ip0[-1] == dictMatch[-1])) { - ip0--; - dictMatch--; - mLength++; - } /* catch up */ - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); - break; - } - } - } - - if (matchIndex > prefixStartIndex && MEM_read32(match) == MEM_read32(ip0)) { - /* found a regular match */ - U32 const offset = (U32) (ip0 - match); - mLength = ZSTD_count(ip0 + 4, match + 4, iend) + 4; - while (((ip0 > anchor) & (match > prefixStart)) - && (ip0[-1] == match[-1])) { - ip0--; - match--; - mLength++; + size_t const h = ZSTD_hashPtr(ip, hlog, mls); + U32 const current = (U32)(ip-base); + U32 const matchIndex = hashTable[h]; + const BYTE* match = base + matchIndex; + const U32 repIndex = current + 1 - offset_1; + const BYTE* repMatch = (repIndex < prefixStartIndex) ? + dictBase + (repIndex - dictIndexDelta) : + base + repIndex; + hashTable[h] = current; /* update hash table */ + + if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ + && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { + const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + } else if ( (matchIndex <= prefixStartIndex) ) { + size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); + U32 const dictMatchIndex = dictHashTable[dictHash]; + const BYTE* dictMatch = dictBase + dictMatchIndex; + if (dictMatchIndex <= dictStartIndex || + MEM_read32(dictMatch) != MEM_read32(ip)) { + assert(stepSize >= 1); + ip += ((ip-anchor) >> kSearchStrength) + stepSize; + continue; + } else { + /* found a dict match */ + U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta); + mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; + while (((ip>anchor) & (dictMatch>dictStart)) + && (ip[-1] == dictMatch[-1])) { + ip--; dictMatch--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); - break; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } - - /* Prepare for next iteration */ - dictMatchIndexAndTag = dictHashTable[dictHashAndTag1 >> ZSTD_SHORT_CACHE_TAG_BITS]; - dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag1); - matchIndex = hashTable[hash1]; - - if (ip1 >= nextStep) { - step++; - nextStep += kStepIncr; - } - ip0 = ip1; - ip1 = ip1 + step; - if (ip1 > ilimit) goto _cleanup; - - curr = (U32)(ip0 - base); - hash0 = hash1; - } /* end inner search loop */ + } else if (MEM_read32(match) != MEM_read32(ip)) { + /* it's not a match, and we're not going to check the dictionary */ + assert(stepSize >= 1); + ip += ((ip-anchor) >> kSearchStrength) + stepSize; + continue; + } else { + /* found a regular match */ + U32 const offset = (U32)(ip-match); + mLength = ZSTD_count(ip+4, match+4, iend) + 4; + while (((ip>anchor) & (match>prefixStart)) + && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + } /* match found */ - assert(mLength); - ip0 += mLength; - anchor = ip0; + ip += mLength; + anchor = ip; - if (ip0 <= ilimit) { + if (ip <= ilimit) { /* Fill Table */ - assert(base+curr+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2; /* here because curr+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + assert(base+current+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); /* check immediate repcode */ - while (ip0 <= ilimit) { - U32 const current2 = (U32)(ip0-base); + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase - dictIndexDelta + repIndex2 : base + repIndex2; if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip0))) { + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); - hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = current2; - ip0 += repLength2; - anchor = ip0; + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); + hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; + ip += repLength2; + anchor = ip; continue; } break; } } - - /* Prepare for next iteration */ - assert(ip0 == anchor); - ip1 = ip0 + stepSize; } -_cleanup: /* save reps for next block */ - rep[0] = offset_1; - rep[1] = offset_2; + rep[0] = offset_1 ? offset_1 : offsetSaved; + rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ return (size_t)(iend - anchor); } - -ZSTD_GEN_FAST_FN(dictMatchState, 4, 0) -ZSTD_GEN_FAST_FN(dictMatchState, 5, 0) -ZSTD_GEN_FAST_FN(dictMatchState, 6, 0) -ZSTD_GEN_FAST_FN(dictMatchState, 7, 0) - size_t ZSTD_compressBlock_fast_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -671,29 +350,30 @@ size_t ZSTD_compressBlock_fast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_dictMatchState_4_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_fast_dictMatchState_5_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_fast_dictMatchState_6_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_fast_dictMatchState_7_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7); } } static size_t ZSTD_compressBlock_fast_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls, U32 const hasStep) + void const* src, size_t srcSize, U32 const mls) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; + U32 const stepSize = cParams->targetLength + !(cParams->targetLength); const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); @@ -706,258 +386,99 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; - - const BYTE* ip0 = istart; - const BYTE* ip1; - const BYTE* ip2; - const BYTE* ip3; - U32 current0; - - size_t hash0; /* hash for ip0 */ - size_t hash1; /* hash for ip1 */ - U32 idx; /* match idx for ip0 */ - const BYTE* idxBase; /* base pointer for idx */ - - U32 offcode; - const BYTE* match0; - size_t mLength; - const BYTE* matchEnd = 0; /* initialize to avoid warning, assert != 0 later */ - - size_t step; - const BYTE* nextStep; - const size_t kStepIncr = (1 << (kSearchStrength - 1)); - - (void)hasStep; /* not currently specialized on whether it's accelerated */ - - DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1); + DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic"); /* switch to "regular" variant if extDict is invalidated due to maxDistance */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_fast(ms, seqStore, rep, src, srcSize); - - { U32 const curr = (U32)(ip0 - base); - U32 const maxRep = curr - dictStartIndex; - if (offset_2 >= maxRep) offsetSaved2 = offset_2, offset_2 = 0; - if (offset_1 >= maxRep) offsetSaved1 = offset_1, offset_1 = 0; - } - - /* start each op */ -_start: /* Requires: ip0 */ - - step = stepSize; - nextStep = ip0 + kStepIncr; - - /* calculate positions, ip0 - anchor == 0, so we skip step calc */ - ip1 = ip0 + 1; - ip2 = ip0 + step; - ip3 = ip2 + 1; - - if (ip3 >= ilimit) { - goto _cleanup; - } - - hash0 = ZSTD_hashPtr(ip0, hlog, mls); - hash1 = ZSTD_hashPtr(ip1, hlog, mls); - - idx = hashTable[hash0]; - idxBase = idx < prefixStartIndex ? dictBase : base; - - do { - { /* load repcode match for ip[2] */ - U32 const current2 = (U32)(ip2 - base); - U32 const repIndex = current2 - offset_1; - const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; - U32 rval; - if ( ((U32)(prefixStartIndex - repIndex) >= 4) /* intentional underflow */ - & (offset_1 > 0) ) { - rval = MEM_read32(repBase + repIndex); - } else { - rval = MEM_read32(ip2) ^ 1; /* guaranteed to not match. */ + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls); + + /* Search Loop */ + while (ip < ilimit) { /* < instead of <=, because (ip+1) */ + const size_t h = ZSTD_hashPtr(ip, hlog, mls); + const U32 matchIndex = hashTable[h]; + const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; + const BYTE* match = matchBase + matchIndex; + const U32 current = (U32)(ip-base); + const U32 repIndex = current + 1 - offset_1; + const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + hashTable[h] = current; /* update hash table */ + assert(offset_1 <= current +1); /* check repIndex */ + + if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex)) + && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { + const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, rLength-MINMATCH); + ip += rLength; + anchor = ip; + } else { + if ( (matchIndex < dictStartIndex) || + (MEM_read32(match) != MEM_read32(ip)) ) { + assert(stepSize >= 1); + ip += ((ip-anchor) >> kSearchStrength) + stepSize; + continue; } - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - /* check repcode at ip[2] */ - if (MEM_read32(ip2) == rval) { - ip0 = ip2; - match0 = repBase + repIndex; - matchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - assert((match0 != prefixStart) & (match0 != dictStart)); - mLength = ip0[-1] == match0[-1]; - ip0 -= mLength; - match0 -= mLength; - offcode = REPCODE1_TO_OFFBASE; - mLength += 4; - goto _match; + { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; + const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; + U32 const offset = current - matchIndex; + size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; + while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ + offset_2 = offset_1; offset_1 = offset; /* update offset history */ + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ip += mLength; + anchor = ip; } } - { /* load match for ip[0] */ - U32 const mval = idx >= dictStartIndex ? - MEM_read32(idxBase + idx) : - MEM_read32(ip0) ^ 1; /* guaranteed not to match */ - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - goto _offset; - } } - - /* lookup ip[1] */ - idx = hashTable[hash1]; - idxBase = idx < prefixStartIndex ? dictBase : base; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip3; - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - { /* load match for ip[0] */ - U32 const mval = idx >= dictStartIndex ? - MEM_read32(idxBase + idx) : - MEM_read32(ip0) ^ 1; /* guaranteed not to match */ - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - goto _offset; - } } - - /* lookup ip[1] */ - idx = hashTable[hash1]; - idxBase = idx < prefixStartIndex ? dictBase : base; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip0 + step; - ip3 = ip1 + step; - - /* calculate step */ - if (ip2 >= nextStep) { - step++; - PREFETCH_L1(ip1 + 64); - PREFETCH_L1(ip1 + 128); - nextStep += kStepIncr; - } - } while (ip3 < ilimit); - -_cleanup: - /* Note that there are probably still a couple positions we could search. - * However, it seems to be a meaningful performance hit to try to search - * them. So let's not. */ - - /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), - * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ - offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; + if (ip <= ilimit) { + /* Fill Table */ + hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; + hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); + /* check immediate repcode */ + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; + const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; + if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */ + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, 0 /*offcode*/, repLength2-MINMATCH); + hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; + ip += repLength2; + anchor = ip; + continue; + } + break; + } } } /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved1; - rep[1] = offset_2 ? offset_2 : offsetSaved2; + rep[0] = offset_1; + rep[1] = offset_2; /* Return the last literals size */ return (size_t)(iend - anchor); - -_offset: /* Requires: ip0, idx, idxBase */ - - /* Compute the offset code. */ - { U32 const offset = current0 - idx; - const BYTE* const lowMatchPtr = idx < prefixStartIndex ? dictStart : prefixStart; - matchEnd = idx < prefixStartIndex ? dictEnd : iend; - match0 = idxBase + idx; - offset_2 = offset_1; - offset_1 = offset; - offcode = OFFSET_TO_OFFBASE(offset); - mLength = 4; - - /* Count the backwards match length. */ - while (((ip0>anchor) & (match0>lowMatchPtr)) && (ip0[-1] == match0[-1])) { - ip0--; - match0--; - mLength++; - } } - -_match: /* Requires: ip0, match0, offcode, matchEnd */ - - /* Count the forward length. */ - assert(matchEnd != 0); - mLength += ZSTD_count_2segments(ip0 + mLength, match0 + mLength, iend, matchEnd, prefixStart); - - ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); - - ip0 += mLength; - anchor = ip0; - - /* write next hash table entry */ - if (ip1 < ip0) { - hashTable[hash1] = (U32)(ip1 - base); - } - - /* Fill table and check for immediate repcode. */ - if (ip0 <= ilimit) { - /* Fill Table */ - assert(base+current0+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); - - while (ip0 <= ilimit) { - U32 const repIndex2 = (U32)(ip0-base) - offset_2; - const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; - if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 > 0)) /* intentional underflow */ - && (MEM_read32(repMatch2) == MEM_read32(ip0)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; - { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); - hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); - ip0 += repLength2; - anchor = ip0; - continue; - } - break; - } } - - goto _start; } -ZSTD_GEN_FAST_FN(extDict, 4, 0) -ZSTD_GEN_FAST_FN(extDict, 5, 0) -ZSTD_GEN_FAST_FN(extDict, 6, 0) -ZSTD_GEN_FAST_FN(extDict, 7, 0) size_t ZSTD_compressBlock_fast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { U32 const mls = ms->cParams.minMatch; - assert(ms->dictMatchState == NULL); switch(mls) { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_extDict_4_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_fast_extDict_5_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_fast_extDict_6_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_fast_extDict_7_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); } } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_fast.h b/vendor/github.com/DataDog/zstd/zstd_fast.h index 88f8f8e2..b74a88c5 100644 --- a/vendor/github.com/DataDog/zstd/zstd_fast.h +++ b/vendor/github.com/DataDog/zstd/zstd_fast.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,8 +19,7 @@ extern "C" { #include "zstd_compress_internal.h" void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp); + void const* end, ZSTD_dictTableLoadMethod_e dtlm); size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -37,5 +35,3 @@ size_t ZSTD_compressBlock_fast_extDict( #endif #endif /* ZSTD_FAST_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_internal.h b/vendor/github.com/DataDog/zstd/zstd_internal.h index 09707543..dcdcbdb8 100644 --- a/vendor/github.com/DataDog/zstd/zstd_internal.h +++ b/vendor/github.com/DataDog/zstd/zstd_internal.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -21,7 +20,6 @@ * Dependencies ***************************************/ #include "compiler.h" -#include "cpu.h" #include "mem.h" #include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ #include "error_private.h" @@ -29,16 +27,12 @@ #include "zstd.h" #define FSE_STATIC_LINKING_ONLY #include "fse.h" +#define HUF_STATIC_LINKING_ONLY #include "huf.h" #ifndef XXH_STATIC_LINKING_ONLY # define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ #endif #include "xxhash.h" /* XXH_reset, update, digest */ -#ifndef ZSTD_NO_TRACE -# include "zstd_trace.h" -#else -# define ZSTD_TRACE 0 -#endif #if defined (__cplusplus) extern "C" { @@ -58,7 +52,50 @@ extern "C" { #undef MAX #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) -#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0); + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0); /*-************************************* @@ -67,7 +104,8 @@ extern "C" { #define ZSTD_OPT_NUM (1<<12) #define ZSTD_REP_NUM 3 /* number of repcodes */ -static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; +#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) +static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define KB *(1 <<10) #define MB *(1 <<20) @@ -81,21 +119,19 @@ static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define BIT0 1 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 -static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; -static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; +static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; #define ZSTD_FRAMEIDSIZE 4 /* magic number size */ #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ -static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; -#define ZSTD_FRAMECHECKSUMSIZE 4 - #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ -#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */) /* for a non-null block */ -#define MIN_LITERALS_FOR_4_STREAMS 6 +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ +#define HufLog 12 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; #define LONGNBSEQ 0x7F00 @@ -103,7 +139,6 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy #define MINMATCH 3 #define Litbits 8 -#define LitHufLog 11 #define MaxLit ((1<= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN)); + if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) { /* Handle short offset copies. */ do { @@ -232,16 +230,15 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e } while (op < oend); } else { assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); - /* Separate out the first COPY16() call because the copy length is + /* Separate out the first two COPY16() calls because the copy length is * almost certain to be short, so the branches have different - * probabilities. Since it is almost certain to be short, only do - * one COPY16() in the first call. Then, do two calls per loop since - * at that point it is more likely to have a high trip count. + * probabilities. + * On gcc-9 unrolling once is +1.6%, twice is +2%, thrice is +1.8%. + * On clang-8 unrolling once is +1.4%, twice is +3.3%, thrice is +3%. */ - ZSTD_copy16(op, ip); - if (16 >= length) return; - op += 16; - ip += 16; + COPY16(op, ip); + COPY16(op, ip); + if (op >= oend) return; do { COPY16(op, ip); COPY16(op, ip); @@ -250,92 +247,30 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e } } -MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - size_t const length = MIN(dstCapacity, srcSize); - if (length > 0) { - ZSTD_memcpy(dst, src, length); - } - return length; -} - -/* define "workspace is too large" as this number of times larger than needed */ -#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 - -/* when workspace is continuously too large - * during at least this number of times, - * context's memory usage is considered wasteful, - * because it's sized to handle a worst case scenario which rarely happens. - * In which case, resize it down to free some memory */ -#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 - -/* Controls whether the input/output buffer is buffered or stable. */ -typedef enum { - ZSTD_bm_buffered = 0, /* Buffer the input/output */ - ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ -} ZSTD_bufferMode_e; - /*-******************************************* * Private declarations *********************************************/ typedef struct seqDef_s { - U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ + U32 offset; U16 litLength; - U16 mlBase; /* mlBase == matchLength - MINMATCH */ + U16 matchLength; } seqDef; -/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ -typedef enum { - ZSTD_llt_none = 0, /* no longLengthType */ - ZSTD_llt_literalLength = 1, /* represents a long literal */ - ZSTD_llt_matchLength = 2 /* represents a long match */ -} ZSTD_longLengthType_e; - typedef struct { seqDef* sequencesStart; - seqDef* sequences; /* ptr to end of sequences */ - BYTE* litStart; - BYTE* lit; /* ptr to end of literals */ - BYTE* llCode; - BYTE* mlCode; - BYTE* ofCode; + seqDef* sequences; + BYTE* litStart; + BYTE* lit; + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; size_t maxNbSeq; size_t maxNbLit; - - /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength - * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment - * the existing value of the litLength or matchLength by 0x10000. - */ - ZSTD_longLengthType_e longLengthType; - U32 longLengthPos; /* Index of the sequence to apply long length modification to */ + U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */ + U32 longLengthPos; } seqStore_t; -typedef struct { - U32 litLength; - U32 matchLength; -} ZSTD_sequenceLength; - -/** - * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences - * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. - */ -MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) -{ - ZSTD_sequenceLength seqLen; - seqLen.litLength = seq->litLength; - seqLen.matchLength = seq->mlBase + MINMATCH; - if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { - if (seqStore->longLengthType == ZSTD_llt_literalLength) { - seqLen.litLength += 0x10000; - } - if (seqStore->longLengthType == ZSTD_llt_matchLength) { - seqLen.matchLength += 0x10000; - } - } - return seqLen; -} - /** * Contains the compressed frame size and an upper-bound for the decompressed frame size. * Note: before using `compressedSize`, check for errors using ZSTD_isError(). @@ -343,13 +278,43 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` */ typedef struct { - size_t nbBlocks; size_t compressedSize; unsigned long long decompressedBound; } ZSTD_frameSizeInfo; /* decompress & legacy */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ -int ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ + +/* custom memory allocation functions */ +void* ZSTD_malloc(size_t size, ZSTD_customMem customMem); +void* ZSTD_calloc(size_t size, ZSTD_customMem customMem); +void ZSTD_free(void* ptr, ZSTD_customMem customMem); + + +MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + _BitScanReverse(&r, val); + return (unsigned)r; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; +# endif + } +} /* ZSTD_invalidateRepCodes() : @@ -377,19 +342,9 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize); -/** - * @returns true iff the CPU supports dynamic BMI2 dispatch. - */ -MEM_STATIC int ZSTD_cpuSupportsBmi2(void) -{ - ZSTD_cpuid_t cpuid = ZSTD_cpuid(); - return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); -} #if defined (__cplusplus) } #endif #endif /* ZSTD_CCOMMON_H_MODULE */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_lazy.c b/vendor/github.com/DataDog/zstd/zstd_lazy.c index 9463e667..9ad7e03b 100644 --- a/vendor/github.com/DataDog/zstd/zstd_lazy.c +++ b/vendor/github.com/DataDog/zstd/zstd_lazy.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,9 +10,6 @@ #include "zstd_compress_internal.h" #include "zstd_lazy.h" -#include "bits.h" /* ZSTD_countTrailingZeros64 */ - -#define kLazySkippingStep 8 /*-************************************* @@ -62,11 +58,11 @@ ZSTD_updateDUBT(ZSTD_matchState_t* ms, /** ZSTD_insertDUBT1() : * sort one already inserted but unsorted position - * assumption : curr >= btlow == (curr - btmask) + * assumption : current >= btlow == (current - btmask) * doesn't fail */ static void -ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, - U32 curr, const BYTE* inputEnd, +ZSTD_insertDUBT1(ZSTD_matchState_t* ms, + U32 current, const BYTE* inputEnd, U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode) { @@ -78,41 +74,41 @@ ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const U32 dictLimit = ms->window.dictLimit; - const BYTE* const ip = (curr>=dictLimit) ? base + curr : dictBase + curr; - const BYTE* const iend = (curr>=dictLimit) ? inputEnd : dictBase + dictLimit; + const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current; + const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - U32* smallerPtr = bt + 2*(curr&btMask); + U32* smallerPtr = bt + 2*(current&btMask); U32* largerPtr = smallerPtr + 1; U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */ U32 dummy32; /* to be nullified at the end */ U32 const windowValid = ms->window.lowLimit; U32 const maxDistance = 1U << cParams->windowLog; - U32 const windowLow = (curr - windowValid > maxDistance) ? curr - maxDistance : windowValid; + U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid; DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)", - curr, dictLimit, windowLow); - assert(curr >= btLow); + current, dictLimit, windowLow); + assert(current >= btLow); assert(ip < iend); /* condition for ZSTD_count */ - for (; nbCompares && (matchIndex > windowLow); --nbCompares) { + while (nbCompares-- && (matchIndex > windowLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < curr); + assert(matchIndex < current); /* note : all candidates are now supposed sorted, * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */ if ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit) /* both in current segment*/ - || (curr < dictLimit) /* both in extDict */) { + || (current < dictLimit) /* both in extDict */) { const BYTE* const mBase = ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) ? base : dictBase; assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */ - || (curr < dictLimit) ); + || (current < dictLimit) ); match = mBase + matchIndex; matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); } else { @@ -123,7 +119,7 @@ ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, } DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ", - curr, matchIndex, (U32)matchLength); + current, matchIndex, (U32)matchLength); if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */ @@ -155,7 +151,7 @@ ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, static size_t ZSTD_DUBT_findBetterDictMatch ( - const ZSTD_matchState_t* ms, + ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, size_t* offsetPtr, size_t bestLength, @@ -172,7 +168,7 @@ ZSTD_DUBT_findBetterDictMatch ( const BYTE* const base = ms->window.base; const BYTE* const prefixStart = base + ms->window.dictLimit; - U32 const curr = (U32)(ip-base); + U32 const current = (U32)(ip-base); const BYTE* const dictBase = dms->window.base; const BYTE* const dictEnd = dms->window.nextSrc; U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base); @@ -189,7 +185,7 @@ ZSTD_DUBT_findBetterDictMatch ( (void)dictMode; assert(dictMode == ZSTD_dictMatchState); - for (; nbCompares && (dictMatchIndex > dictLowLimit); --nbCompares) { + while (nbCompares-- && (dictMatchIndex > dictLowLimit)) { U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dictBase + dictMatchIndex; @@ -199,10 +195,10 @@ ZSTD_DUBT_findBetterDictMatch ( if (matchLength > bestLength) { U32 matchIndex = dictMatchIndex + dictIndexDelta; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)", - curr, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, OFFSET_TO_OFFBASE(curr - matchIndex), dictMatchIndex, matchIndex); - bestLength = matchLength, *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); + current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex); + bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; } if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ @@ -222,9 +218,9 @@ ZSTD_DUBT_findBetterDictMatch ( } if (bestLength >= MINMATCH) { - U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offsetPtr); (void)mIndex; + U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - curr, (U32)bestLength, (U32)*offsetPtr, mIndex); + current, (U32)bestLength, (U32)*offsetPtr, mIndex); } return bestLength; @@ -234,7 +230,7 @@ ZSTD_DUBT_findBetterDictMatch ( static size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, - size_t* offBasePtr, + size_t* offsetPtr, U32 const mls, const ZSTD_dictMode_e dictMode) { @@ -245,13 +241,13 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 matchIndex = hashTable[h]; const BYTE* const base = ms->window.base; - U32 const curr = (U32)(ip-base); - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); + U32 const current = (U32)(ip-base); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; U32 const btMask = (1 << btLog) - 1; - U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; + U32 const btLow = (btMask >= current) ? 0 : current - btMask; U32 const unsortLimit = MAX(btLow, windowLow); U32* nextCandidate = bt + 2*(matchIndex&btMask); @@ -260,9 +256,8 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 nbCandidates = nbCompares; U32 previousCandidate = 0; - DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", curr); + DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current); assert(ip <= iend-8); /* required for h calculation */ - assert(dictMode != ZSTD_dedicatedDictSearch); /* reach end of unsorted candidates list */ while ( (matchIndex > unsortLimit) @@ -304,16 +299,16 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const U32 dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32* smallerPtr = bt + 2*(curr&btMask); - U32* largerPtr = bt + 2*(curr&btMask) + 1; - U32 matchEndIdx = curr + 8 + 1; + U32* smallerPtr = bt + 2*(current&btMask); + U32* largerPtr = bt + 2*(current&btMask) + 1; + U32 matchEndIdx = current + 8 + 1; U32 dummy32; /* to be nullified at the end */ size_t bestLength = 0; matchIndex = hashTable[h]; - hashTable[h] = curr; /* Update Hash Table */ + hashTable[h] = current; /* Update Hash Table */ - for (; nbCompares && (matchIndex > windowLow); --nbCompares) { + while (nbCompares-- && (matchIndex > windowLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match; @@ -331,8 +326,8 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, if (matchLength > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr - matchIndex + 1) - ZSTD_highbit32((U32)*offBasePtr)) ) - bestLength = matchLength, *offBasePtr = OFFSET_TO_OFFBASE(curr - matchIndex); + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) + bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ if (dictMode == ZSTD_dictMatchState) { nbCompares = 0; /* in addition to avoiding checking any @@ -361,20 +356,19 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, *smallerPtr = *largerPtr = 0; - assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { bestLength = ZSTD_DUBT_findBetterDictMatch( ms, ip, iend, - offBasePtr, bestLength, nbCompares, + offsetPtr, bestLength, nbCompares, mls, dictMode); } - assert(matchEndIdx > curr+8); /* ensure nextToUpdate is increased */ + assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ if (bestLength >= MINMATCH) { - U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offBasePtr); (void)mIndex; + U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - curr, (U32)bestLength, (U32)*offBasePtr, mIndex); + current, (U32)bestLength, (U32)*offsetPtr, mIndex); } return bestLength; } @@ -385,232 +379,66 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, FORCE_INLINE_TEMPLATE size_t ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, - size_t* offBasePtr, + size_t* offsetPtr, const U32 mls /* template */, const ZSTD_dictMode_e dictMode) { DEBUGLOG(7, "ZSTD_BtFindBestMatch"); if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ ZSTD_updateDUBT(ms, ip, iLimit, mls); - return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offBasePtr, mls, dictMode); + return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode); } -/*********************************** -* Dedicated dict search -***********************************/ -void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip) +static size_t +ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) { - const BYTE* const base = ms->window.base; - U32 const target = (U32)(ip - base); - U32* const hashTable = ms->hashTable; - U32* const chainTable = ms->chainTable; - U32 const chainSize = 1 << ms->cParams.chainLog; - U32 idx = ms->nextToUpdate; - U32 const minChain = chainSize < target - idx ? target - chainSize : idx; - U32 const bucketSize = 1 << ZSTD_LAZY_DDSS_BUCKET_LOG; - U32 const cacheSize = bucketSize - 1; - U32 const chainAttempts = (1 << ms->cParams.searchLog) - cacheSize; - U32 const chainLimit = chainAttempts > 255 ? 255 : chainAttempts; - - /* We know the hashtable is oversized by a factor of `bucketSize`. - * We are going to temporarily pretend `bucketSize == 1`, keeping only a - * single entry. We will use the rest of the space to construct a temporary - * chaintable. - */ - U32 const hashLog = ms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; - U32* const tmpHashTable = hashTable; - U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog); - U32 const tmpChainSize = (U32)((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog; - U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx; - U32 hashIdx; - - assert(ms->cParams.chainLog <= 24); - assert(ms->cParams.hashLog > ms->cParams.chainLog); - assert(idx != 0); - assert(tmpMinChain <= minChain); - - /* fill conventional hash table and conventional chain table */ - for ( ; idx < target; idx++) { - U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch); - if (idx >= tmpMinChain) { - tmpChainTable[idx - tmpMinChain] = hashTable[h]; - } - tmpHashTable[h] = idx; - } - - /* sort chains into ddss chain table */ + switch(ms->cParams.minMatch) { - U32 chainPos = 0; - for (hashIdx = 0; hashIdx < (1U << hashLog); hashIdx++) { - U32 count; - U32 countBeyondMinChain = 0; - U32 i = tmpHashTable[hashIdx]; - for (count = 0; i >= tmpMinChain && count < cacheSize; count++) { - /* skip through the chain to the first position that won't be - * in the hash cache bucket */ - if (i < minChain) { - countBeyondMinChain++; - } - i = tmpChainTable[i - tmpMinChain]; - } - if (count == cacheSize) { - for (count = 0; count < chainLimit;) { - if (i < minChain) { - if (!i || ++countBeyondMinChain > cacheSize) { - /* only allow pulling `cacheSize` number of entries - * into the cache or chainTable beyond `minChain`, - * to replace the entries pulled out of the - * chainTable into the cache. This lets us reach - * back further without increasing the total number - * of entries in the chainTable, guaranteeing the - * DDSS chain table will fit into the space - * allocated for the regular one. */ - break; - } - } - chainTable[chainPos++] = i; - count++; - if (i < tmpMinChain) { - break; - } - i = tmpChainTable[i - tmpMinChain]; - } - } else { - count = 0; - } - if (count) { - tmpHashTable[hashIdx] = ((chainPos - count) << 8) + count; - } else { - tmpHashTable[hashIdx] = 0; - } - } - assert(chainPos <= chainSize); /* I believe this is guaranteed... */ - } - - /* move chain pointers into the last entry of each hash bucket */ - for (hashIdx = (1 << hashLog); hashIdx; ) { - U32 const bucketIdx = --hashIdx << ZSTD_LAZY_DDSS_BUCKET_LOG; - U32 const chainPackedPointer = tmpHashTable[hashIdx]; - U32 i; - for (i = 0; i < cacheSize; i++) { - hashTable[bucketIdx + i] = 0; - } - hashTable[bucketIdx + bucketSize - 1] = chainPackedPointer; - } - - /* fill the buckets of the hash table */ - for (idx = ms->nextToUpdate; idx < target; idx++) { - U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch) - << ZSTD_LAZY_DDSS_BUCKET_LOG; - U32 i; - /* Shift hash cache down 1. */ - for (i = cacheSize - 1; i; i--) - hashTable[h + i] = hashTable[h + i - 1]; - hashTable[h] = idx; + default : /* includes case 3 */ + case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); + case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); + case 7 : + case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); } - - ms->nextToUpdate = target; } -/* Returns the longest match length found in the dedicated dict search structure. - * If none are longer than the argument ml, then ml will be returned. - */ -FORCE_INLINE_TEMPLATE -size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nbAttempts, - const ZSTD_matchState_t* const dms, - const BYTE* const ip, const BYTE* const iLimit, - const BYTE* const prefixStart, const U32 curr, - const U32 dictLimit, const size_t ddsIdx) { - const U32 ddsLowestIndex = dms->window.dictLimit; - const BYTE* const ddsBase = dms->window.base; - const BYTE* const ddsEnd = dms->window.nextSrc; - const U32 ddsSize = (U32)(ddsEnd - ddsBase); - const U32 ddsIndexDelta = dictLimit - ddsSize; - const U32 bucketSize = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG); - const U32 bucketLimit = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1; - U32 ddsAttempt; - U32 matchIndex; - - for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) { - PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]); - } +static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS ( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) +{ + switch(ms->cParams.minMatch) { - U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; - U32 const chainIndex = chainPackedPointer >> 8; - - PREFETCH_L1(&dms->chainTable[chainIndex]); + default : /* includes case 3 */ + case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); + case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); + case 7 : + case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); } +} - for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) { - size_t currentMl=0; - const BYTE* match; - matchIndex = dms->hashTable[ddsIdx + ddsAttempt]; - match = ddsBase + matchIndex; - - if (!matchIndex) { - return ml; - } - - /* guaranteed by table construction */ - (void)ddsLowestIndex; - assert(matchIndex >= ddsLowestIndex); - assert(match+4 <= ddsEnd); - if (MEM_read32(match) == MEM_read32(ip)) { - /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; - } - - /* save best solution */ - if (currentMl > ml) { - ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); - if (ip+currentMl == iLimit) { - /* best possible, avoids read overflow on next attempt */ - return ml; - } - } - } +static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) +{ + switch(ms->cParams.minMatch) { - U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; - U32 chainIndex = chainPackedPointer >> 8; - U32 const chainLength = chainPackedPointer & 0xFF; - U32 const chainAttempts = nbAttempts - ddsAttempt; - U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts; - U32 chainAttempt; - - for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) { - PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]); - } - - for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) { - size_t currentMl=0; - const BYTE* match; - matchIndex = dms->chainTable[chainIndex]; - match = ddsBase + matchIndex; - - /* guaranteed by table construction */ - assert(matchIndex >= ddsLowestIndex); - assert(match+4 <= ddsEnd); - if (MEM_read32(match) == MEM_read32(ip)) { - /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; - } - - /* save best solution */ - if (currentMl > ml) { - ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); - if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ - } - } + default : /* includes case 3 */ + case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); + case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); + case 7 : + case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); } - return ml; } + /* ********************************* * Hash Chain ***********************************/ @@ -618,10 +446,10 @@ size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nb /* Update chains up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal( +static U32 ZSTD_insertAndFindFirstIndex_internal( ZSTD_matchState_t* ms, const ZSTD_compressionParameters* const cParams, - const BYTE* ip, U32 const mls, U32 const lazySkipping) + const BYTE* ip, U32 const mls) { U32* const hashTable = ms->hashTable; const U32 hashLog = cParams->hashLog; @@ -636,9 +464,6 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal( NEXT_IN_CHAIN(idx, chainMask) = hashTable[h]; hashTable[h] = idx; idx++; - /* Stop inserting every position when in the lazy skipping mode. */ - if (lazySkipping) - break; } ms->nextToUpdate = target; @@ -647,12 +472,13 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal( U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) { const ZSTD_compressionParameters* const cParams = &ms->cParams; - return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch, /* lazySkipping*/ 0); + return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch); } + /* inlining is important to hardwire a hot branch (template emulation) */ FORCE_INLINE_TEMPLATE -size_t ZSTD_HcFindBestMatch( +size_t ZSTD_HcFindBestMatch_generic ( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -667,39 +493,25 @@ size_t ZSTD_HcFindBestMatch( const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; - const U32 curr = (U32)(ip-base); + const U32 current = (U32)(ip-base); const U32 maxDistance = 1U << cParams->windowLog; const U32 lowestValid = ms->window.lowLimit; - const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; const U32 isDictionary = (ms->loadedDictEnd != 0); const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; - const U32 minChain = curr > chainSize ? curr - chainSize : 0; + const U32 minChain = current > chainSize ? current - chainSize : 0; U32 nbAttempts = 1U << cParams->searchLog; size_t ml=4-1; - const ZSTD_matchState_t* const dms = ms->dictMatchState; - const U32 ddsHashLog = dictMode == ZSTD_dedicatedDictSearch - ? dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0; - const size_t ddsIdx = dictMode == ZSTD_dedicatedDictSearch - ? ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG : 0; - - U32 matchIndex; - - if (dictMode == ZSTD_dedicatedDictSearch) { - const U32* entry = &dms->hashTable[ddsIdx]; - PREFETCH_L1(entry); - } - /* HC4 match finder */ - matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls, ms->lazySkipping); + U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls); - for ( ; (matchIndex>=lowLimit) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { const BYTE* const match = base + matchIndex; assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ - /* read 4B starting from (match + ml + 1 - sizeof(U32)) */ - if (MEM_read32(match + ml - 3) == MEM_read32(ip + ml - 3)) /* potentially better */ + if (match[ml] == ip[ml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iLimit); } else { const BYTE* const match = dictBase + matchIndex; @@ -711,7 +523,7 @@ size_t ZSTD_HcFindBestMatch( /* save best solution */ if (currentMl > ml) { ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); + *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } @@ -719,11 +531,8 @@ size_t ZSTD_HcFindBestMatch( matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); } - assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ - if (dictMode == ZSTD_dedicatedDictSearch) { - ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts, dms, - ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); - } else if (dictMode == ZSTD_dictMatchState) { + if (dictMode == ZSTD_dictMatchState) { + const ZSTD_matchState_t* const dms = ms->dictMatchState; const U32* const dmsChainTable = dms->chainTable; const U32 dmsChainSize = (1 << dms->cParams.chainLog); const U32 dmsChainMask = dmsChainSize - 1; @@ -736,7 +545,7 @@ size_t ZSTD_HcFindBestMatch( matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)]; - for ( ; (matchIndex>=dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; const BYTE* const match = dmsBase + matchIndex; assert(match+4 <= dmsEnd); @@ -746,13 +555,11 @@ size_t ZSTD_HcFindBestMatch( /* save best solution */ if (currentMl > ml) { ml = currentMl; - assert(curr > matchIndex + dmsIndexDelta); - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); + *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } if (matchIndex <= dmsMinChain) break; - matchIndex = dmsChainTable[matchIndex & dmsChainMask]; } } @@ -760,735 +567,59 @@ size_t ZSTD_HcFindBestMatch( return ml; } -/* ********************************* -* (SIMD) Row-based matchfinder -***********************************/ -/* Constants for row-based hash */ -#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1) -#define ZSTD_ROW_HASH_MAX_ENTRIES 64 /* absolute maximum number of entries per row, for all configurations */ - -#define ZSTD_ROW_HASH_CACHE_MASK (ZSTD_ROW_HASH_CACHE_SIZE - 1) - -typedef U64 ZSTD_VecMask; /* Clarifies when we are interacting with a U64 representing a mask of matches */ - -/* ZSTD_VecMask_next(): - * Starting from the LSB, returns the idx of the next non-zero bit. - * Basically counting the nb of trailing zeroes. - */ -MEM_STATIC U32 ZSTD_VecMask_next(ZSTD_VecMask val) { - return ZSTD_countTrailingZeros64(val); -} - -/* ZSTD_row_nextIndex(): - * Returns the next index to insert at within a tagTable row, and updates the "head" - * value to reflect the update. Essentially cycles backwards from [1, {entries per row}) - */ -FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) { - U32 next = (*tagRow-1) & rowMask; - next += (next == 0) ? rowMask : 0; /* skip first position */ - *tagRow = (BYTE)next; - return next; -} - -/* ZSTD_isAligned(): - * Checks that a pointer is aligned to "align" bytes which must be a power of 2. - */ -MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) { - assert((align & (align - 1)) == 0); - return (((size_t)ptr) & (align - 1)) == 0; -} - -/* ZSTD_row_prefetch(): - * Performs prefetching for the hashTable and tagTable at a given row. - */ -FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, BYTE const* tagTable, U32 const relRow, U32 const rowLog) { - PREFETCH_L1(hashTable + relRow); - if (rowLog >= 5) { - PREFETCH_L1(hashTable + relRow + 16); - /* Note: prefetching more of the hash table does not appear to be beneficial for 128-entry rows */ - } - PREFETCH_L1(tagTable + relRow); - if (rowLog == 6) { - PREFETCH_L1(tagTable + relRow + 32); - } - assert(rowLog == 4 || rowLog == 5 || rowLog == 6); - assert(ZSTD_isAligned(hashTable + relRow, 64)); /* prefetched hash row always 64-byte aligned */ - assert(ZSTD_isAligned(tagTable + relRow, (size_t)1 << rowLog)); /* prefetched tagRow sits on correct multiple of bytes (32,64,128) */ -} - -/* ZSTD_row_fillHashCache(): - * Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries, - * but not beyond iLimit. - */ -FORCE_INLINE_TEMPLATE void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base, - U32 const rowLog, U32 const mls, - U32 idx, const BYTE* const iLimit) -{ - U32 const* const hashTable = ms->hashTable; - BYTE const* const tagTable = ms->tagTable; - U32 const hashLog = ms->rowHashLog; - U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1); - U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch); - - for (; idx < lim; ++idx) { - U32 const hash = (U32)ZSTD_hashPtrSalted(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt); - U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); - ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash; - } - - DEBUGLOG(6, "ZSTD_row_fillHashCache(): [%u %u %u %u %u %u %u %u]", ms->hashCache[0], ms->hashCache[1], - ms->hashCache[2], ms->hashCache[3], ms->hashCache[4], - ms->hashCache[5], ms->hashCache[6], ms->hashCache[7]); -} - -/* ZSTD_row_nextCachedHash(): - * Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at - * base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable. - */ -FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable, - BYTE const* tagTable, BYTE const* base, - U32 idx, U32 const hashLog, - U32 const rowLog, U32 const mls, - U64 const hashSalt) -{ - U32 const newHash = (U32)ZSTD_hashPtrSalted(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt); - U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); - { U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK]; - cache[idx & ZSTD_ROW_HASH_CACHE_MASK] = newHash; - return hash; - } -} - -/* ZSTD_row_update_internalImpl(): - * Updates the hash table with positions starting from updateStartIdx until updateEndIdx. - */ -FORCE_INLINE_TEMPLATE void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms, - U32 updateStartIdx, U32 const updateEndIdx, - U32 const mls, U32 const rowLog, - U32 const rowMask, U32 const useCache) -{ - U32* const hashTable = ms->hashTable; - BYTE* const tagTable = ms->tagTable; - U32 const hashLog = ms->rowHashLog; - const BYTE* const base = ms->window.base; - - DEBUGLOG(6, "ZSTD_row_update_internalImpl(): updateStartIdx=%u, updateEndIdx=%u", updateStartIdx, updateEndIdx); - for (; updateStartIdx < updateEndIdx; ++updateStartIdx) { - U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, updateStartIdx, hashLog, rowLog, mls, ms->hashSalt) - : (U32)ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt); - U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - U32* const row = hashTable + relRow; - BYTE* tagRow = tagTable + relRow; - U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); - - assert(hash == ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt)); - tagRow[pos] = hash & ZSTD_ROW_HASH_TAG_MASK; - row[pos] = updateStartIdx; - } -} - -/* ZSTD_row_update_internal(): - * Inserts the byte at ip into the appropriate position in the hash table, and updates ms->nextToUpdate. - * Skips sections of long matches as is necessary. - */ -FORCE_INLINE_TEMPLATE void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip, - U32 const mls, U32 const rowLog, - U32 const rowMask, U32 const useCache) -{ - U32 idx = ms->nextToUpdate; - const BYTE* const base = ms->window.base; - const U32 target = (U32)(ip - base); - const U32 kSkipThreshold = 384; - const U32 kMaxMatchStartPositionsToUpdate = 96; - const U32 kMaxMatchEndPositionsToUpdate = 32; - - if (useCache) { - /* Only skip positions when using hash cache, i.e. - * if we are loading a dict, don't skip anything. - * If we decide to skip, then we only update a set number - * of positions at the beginning and end of the match. - */ - if (UNLIKELY(target - idx > kSkipThreshold)) { - U32 const bound = idx + kMaxMatchStartPositionsToUpdate; - ZSTD_row_update_internalImpl(ms, idx, bound, mls, rowLog, rowMask, useCache); - idx = target - kMaxMatchEndPositionsToUpdate; - ZSTD_row_fillHashCache(ms, base, rowLog, mls, idx, ip+1); - } - } - assert(target >= idx); - ZSTD_row_update_internalImpl(ms, idx, target, mls, rowLog, rowMask, useCache); - ms->nextToUpdate = target; -} -/* ZSTD_row_update(): - * External wrapper for ZSTD_row_update_internal(). Used for filling the hashtable during dictionary - * processing. - */ -void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip) { - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); - const U32 rowMask = (1u << rowLog) - 1; - const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */); - - DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog); - ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* don't use cache */); -} - -/* Returns the mask width of bits group of which will be set to 1. Given not all - * architectures have easy movemask instruction, this helps to iterate over - * groups of bits easier and faster. - */ -FORCE_INLINE_TEMPLATE U32 -ZSTD_row_matchMaskGroupWidth(const U32 rowEntries) +FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS ( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) { - assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64); - assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES); - (void)rowEntries; -#if defined(ZSTD_ARCH_ARM_NEON) - /* NEON path only works for little endian */ - if (!MEM_isLittleEndian()) { - return 1; - } - if (rowEntries == 16) { - return 4; - } - if (rowEntries == 32) { - return 2; - } - if (rowEntries == 64) { - return 1; + switch(ms->cParams.minMatch) + { + default : /* includes case 3 */ + case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); + case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); + case 7 : + case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); } -#endif - return 1; } -#if defined(ZSTD_ARCH_X86_SSE2) -FORCE_INLINE_TEMPLATE ZSTD_VecMask -ZSTD_row_getSSEMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) -{ - const __m128i comparisonMask = _mm_set1_epi8((char)tag); - int matches[4] = {0}; - int i; - assert(nbChunks == 1 || nbChunks == 2 || nbChunks == 4); - for (i=0; icParams.minMatch) + { + default : /* includes case 3 */ + case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); + case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); + case 7 : + case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); } } -#endif - -/* Returns a ZSTD_VecMask (U64) that has the nth group (determined by - * ZSTD_row_matchMaskGroupWidth) of bits set to 1 if the newly-computed "tag" - * matches the hash at the nth position in a row of the tagTable. - * Each row is a circular buffer beginning at the value of "headGrouped". So we - * must rotate the "matches" bitfield to match up with the actual layout of the - * entries within the hashTable */ -FORCE_INLINE_TEMPLATE ZSTD_VecMask -ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 headGrouped, const U32 rowEntries) -{ - const BYTE* const src = tagRow; - assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64); - assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES); - assert(ZSTD_row_matchMaskGroupWidth(rowEntries) * rowEntries <= sizeof(ZSTD_VecMask) * 8); - -#if defined(ZSTD_ARCH_X86_SSE2) - - return ZSTD_row_getSSEMask(rowEntries / 16, src, tag, headGrouped); -#else /* SW or NEON-LE */ -# if defined(ZSTD_ARCH_ARM_NEON) - /* This NEON path only works for little endian - otherwise use SWAR below */ - if (MEM_isLittleEndian()) { - return ZSTD_row_getNEONMask(rowEntries, src, tag, headGrouped); - } -# endif /* ZSTD_ARCH_ARM_NEON */ - /* SWAR */ - { const int chunkSize = sizeof(size_t); - const size_t shiftAmount = ((chunkSize * 8) - chunkSize); - const size_t xFF = ~((size_t)0); - const size_t x01 = xFF / 0xFF; - const size_t x80 = x01 << 7; - const size_t splatChar = tag * x01; - ZSTD_VecMask matches = 0; - int i = rowEntries - chunkSize; - assert((sizeof(size_t) == 4) || (sizeof(size_t) == 8)); - if (MEM_isLittleEndian()) { /* runtime check so have two loops */ - const size_t extractMagic = (xFF / 0x7F) >> chunkSize; - do { - size_t chunk = MEM_readST(&src[i]); - chunk ^= splatChar; - chunk = (((chunk | x80) - x01) | chunk) & x80; - matches <<= chunkSize; - matches |= (chunk * extractMagic) >> shiftAmount; - i -= chunkSize; - } while (i >= 0); - } else { /* big endian: reverse bits during extraction */ - const size_t msb = xFF ^ (xFF >> 1); - const size_t extractMagic = (msb / 0x1FF) | msb; - do { - size_t chunk = MEM_readST(&src[i]); - chunk ^= splatChar; - chunk = (((chunk | x80) - x01) | chunk) & x80; - matches <<= chunkSize; - matches |= ((chunk >> 7) * extractMagic) >> shiftAmount; - i -= chunkSize; - } while (i >= 0); - } - matches = ~matches; - if (rowEntries == 16) { - return ZSTD_rotateRight_U16((U16)matches, headGrouped); - } else if (rowEntries == 32) { - return ZSTD_rotateRight_U32((U32)matches, headGrouped); - } else { - return ZSTD_rotateRight_U64((U64)matches, headGrouped); - } - } -#endif -} - -/* The high-level approach of the SIMD row based match finder is as follows: - * - Figure out where to insert the new entry: - * - Generate a hash from a byte along with an additional 1-byte "short hash". The additional byte is our "tag" - * - The hashTable is effectively split into groups or "rows" of 16 or 32 entries of U32, and the hash determines - * which row to insert into. - * - Determine the correct position within the row to insert the entry into. Each row of 16 or 32 can - * be considered as a circular buffer with a "head" index that resides in the tagTable. - * - Also insert the "tag" into the equivalent row and position in the tagTable. - * - Note: The tagTable has 17 or 33 1-byte entries per row, due to 16 or 32 tags, and 1 "head" entry. - * The 17 or 33 entry rows are spaced out to occur every 32 or 64 bytes, respectively, - * for alignment/performance reasons, leaving some bytes unused. - * - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte "short hash" and - * generate a bitfield that we can cycle through to check the collisions in the hash table. - * - Pick the longest match. - */ -FORCE_INLINE_TEMPLATE -size_t ZSTD_RowFindBestMatch( +FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( ZSTD_matchState_t* ms, - const BYTE* const ip, const BYTE* const iLimit, - size_t* offsetPtr, - const U32 mls, const ZSTD_dictMode_e dictMode, - const U32 rowLog) + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) { - U32* const hashTable = ms->hashTable; - BYTE* const tagTable = ms->tagTable; - U32* const hashCache = ms->hashCache; - const U32 hashLog = ms->rowHashLog; - const ZSTD_compressionParameters* const cParams = &ms->cParams; - const BYTE* const base = ms->window.base; - const BYTE* const dictBase = ms->window.dictBase; - const U32 dictLimit = ms->window.dictLimit; - const BYTE* const prefixStart = base + dictLimit; - const BYTE* const dictEnd = dictBase + dictLimit; - const U32 curr = (U32)(ip-base); - const U32 maxDistance = 1U << cParams->windowLog; - const U32 lowestValid = ms->window.lowLimit; - const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; - const U32 isDictionary = (ms->loadedDictEnd != 0); - const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; - const U32 rowEntries = (1U << rowLog); - const U32 rowMask = rowEntries - 1; - const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */ - const U32 groupWidth = ZSTD_row_matchMaskGroupWidth(rowEntries); - const U64 hashSalt = ms->hashSalt; - U32 nbAttempts = 1U << cappedSearchLog; - size_t ml=4-1; - U32 hash; - - /* DMS/DDS variables that may be referenced laster */ - const ZSTD_matchState_t* const dms = ms->dictMatchState; - - /* Initialize the following variables to satisfy static analyzer */ - size_t ddsIdx = 0; - U32 ddsExtraAttempts = 0; /* cctx hash tables are limited in searches, but allow extra searches into DDS */ - U32 dmsTag = 0; - U32* dmsRow = NULL; - BYTE* dmsTagRow = NULL; - - if (dictMode == ZSTD_dedicatedDictSearch) { - const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; - { /* Prefetch DDS hashtable entry */ - ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG; - PREFETCH_L1(&dms->hashTable[ddsIdx]); - } - ddsExtraAttempts = cParams->searchLog > rowLog ? 1U << (cParams->searchLog - rowLog) : 0; - } - - if (dictMode == ZSTD_dictMatchState) { - /* Prefetch DMS rows */ - U32* const dmsHashTable = dms->hashTable; - BYTE* const dmsTagTable = dms->tagTable; - U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls); - U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK; - dmsTagRow = (BYTE*)(dmsTagTable + dmsRelRow); - dmsRow = dmsHashTable + dmsRelRow; - ZSTD_row_prefetch(dmsHashTable, dmsTagTable, dmsRelRow, rowLog); - } - - /* Update the hashTable and tagTable up to (but not including) ip */ - if (!ms->lazySkipping) { - ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */); - hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls, hashSalt); - } else { - /* Stop inserting every position when in the lazy skipping mode. - * The hash cache is also not kept up to date in this mode. - */ - hash = (U32)ZSTD_hashPtrSalted(ip, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt); - ms->nextToUpdate = curr; - } - ms->hashSaltEntropy += hash; /* collect salt entropy */ - - { /* Get the hash for ip, compute the appropriate row */ - U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK; - U32* const row = hashTable + relRow; - BYTE* tagRow = (BYTE*)(tagTable + relRow); - U32 const headGrouped = (*tagRow & rowMask) * groupWidth; - U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; - size_t numMatches = 0; - size_t currMatch = 0; - ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, headGrouped, rowEntries); - - /* Cycle through the matches and prefetch */ - for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) { - U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; - U32 const matchIndex = row[matchPos]; - if(matchPos == 0) continue; - assert(numMatches < rowEntries); - if (matchIndex < lowLimit) - break; - if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { - PREFETCH_L1(base + matchIndex); - } else { - PREFETCH_L1(dictBase + matchIndex); - } - matchBuffer[numMatches++] = matchIndex; - --nbAttempts; - } - - /* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop - in ZSTD_row_update_internal() at the next search. */ - { - U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); - tagRow[pos] = (BYTE)tag; - row[pos] = ms->nextToUpdate++; - } - - /* Return the longest match */ - for (; currMatch < numMatches; ++currMatch) { - U32 const matchIndex = matchBuffer[currMatch]; - size_t currentMl=0; - assert(matchIndex < curr); - assert(matchIndex >= lowLimit); - - if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { - const BYTE* const match = base + matchIndex; - assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ - /* read 4B starting from (match + ml + 1 - sizeof(U32)) */ - if (MEM_read32(match + ml - 3) == MEM_read32(ip + ml - 3)) /* potentially better */ - currentMl = ZSTD_count(ip, match, iLimit); - } else { - const BYTE* const match = dictBase + matchIndex; - assert(match+4 <= dictEnd); - if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4; - } - - /* Save best solution */ - if (currentMl > ml) { - ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); - if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ - } - } - } - - assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ - if (dictMode == ZSTD_dedicatedDictSearch) { - ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts + ddsExtraAttempts, dms, - ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); - } else if (dictMode == ZSTD_dictMatchState) { - /* TODO: Measure and potentially add prefetching to DMS */ - const U32 dmsLowestIndex = dms->window.dictLimit; - const BYTE* const dmsBase = dms->window.base; - const BYTE* const dmsEnd = dms->window.nextSrc; - const U32 dmsSize = (U32)(dmsEnd - dmsBase); - const U32 dmsIndexDelta = dictLimit - dmsSize; - - { U32 const headGrouped = (*dmsTagRow & rowMask) * groupWidth; - U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; - size_t numMatches = 0; - size_t currMatch = 0; - ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, headGrouped, rowEntries); - - for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) { - U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; - U32 const matchIndex = dmsRow[matchPos]; - if(matchPos == 0) continue; - if (matchIndex < dmsLowestIndex) - break; - PREFETCH_L1(dmsBase + matchIndex); - matchBuffer[numMatches++] = matchIndex; - --nbAttempts; - } - - /* Return the longest match */ - for (; currMatch < numMatches; ++currMatch) { - U32 const matchIndex = matchBuffer[currMatch]; - size_t currentMl=0; - assert(matchIndex >= dmsLowestIndex); - assert(matchIndex < curr); - - { const BYTE* const match = dmsBase + matchIndex; - assert(match+4 <= dmsEnd); - if (MEM_read32(match) == MEM_read32(ip)) - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4; - } - - if (currentMl > ml) { - ml = currentMl; - assert(curr > matchIndex + dmsIndexDelta); - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); - if (ip+currentMl == iLimit) break; - } - } - } + switch(ms->cParams.minMatch) + { + default : /* includes case 3 */ + case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); + case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); + case 7 : + case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); } - return ml; } -/** - * Generate search functions templated on (dictMode, mls, rowLog). - * These functions are outlined for code size & compilation time. - * ZSTD_searchMax() dispatches to the correct implementation function. - * - * TODO: The start of the search function involves loading and calculating a - * bunch of constants from the ZSTD_matchState_t. These computations could be - * done in an initialization function, and saved somewhere in the match state. - * Then we could pass a pointer to the saved state instead of the match state, - * and avoid duplicate computations. - * - * TODO: Move the match re-winding into searchMax. This improves compression - * ratio, and unlocks further simplifications with the next TODO. - * - * TODO: Try moving the repcode search into searchMax. After the re-winding - * and repcode search are in searchMax, there is no more logic in the match - * finder loop that requires knowledge about the dictMode. So we should be - * able to avoid force inlining it, and we can join the extDict loop with - * the single segment loop. It should go in searchMax instead of its own - * function to avoid having multiple virtual function calls per search. - */ - -#define ZSTD_BT_SEARCH_FN(dictMode, mls) ZSTD_BtFindBestMatch_##dictMode##_##mls -#define ZSTD_HC_SEARCH_FN(dictMode, mls) ZSTD_HcFindBestMatch_##dictMode##_##mls -#define ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog) ZSTD_RowFindBestMatch_##dictMode##_##mls##_##rowLog - -#define ZSTD_SEARCH_FN_ATTRS FORCE_NOINLINE - -#define GEN_ZSTD_BT_SEARCH_FN(dictMode, mls) \ - ZSTD_SEARCH_FN_ATTRS size_t ZSTD_BT_SEARCH_FN(dictMode, mls)( \ - ZSTD_matchState_t* ms, \ - const BYTE* ip, const BYTE* const iLimit, \ - size_t* offBasePtr) \ - { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - return ZSTD_BtFindBestMatch(ms, ip, iLimit, offBasePtr, mls, ZSTD_##dictMode); \ - } \ - -#define GEN_ZSTD_HC_SEARCH_FN(dictMode, mls) \ - ZSTD_SEARCH_FN_ATTRS size_t ZSTD_HC_SEARCH_FN(dictMode, mls)( \ - ZSTD_matchState_t* ms, \ - const BYTE* ip, const BYTE* const iLimit, \ - size_t* offsetPtr) \ - { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - return ZSTD_HcFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode); \ - } \ - -#define GEN_ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog) \ - ZSTD_SEARCH_FN_ATTRS size_t ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog)( \ - ZSTD_matchState_t* ms, \ - const BYTE* ip, const BYTE* const iLimit, \ - size_t* offsetPtr) \ - { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - assert(MAX(4, MIN(6, ms->cParams.searchLog)) == rowLog); \ - return ZSTD_RowFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode, rowLog); \ - } \ - -#define ZSTD_FOR_EACH_ROWLOG(X, dictMode, mls) \ - X(dictMode, mls, 4) \ - X(dictMode, mls, 5) \ - X(dictMode, mls, 6) - -#define ZSTD_FOR_EACH_MLS_ROWLOG(X, dictMode) \ - ZSTD_FOR_EACH_ROWLOG(X, dictMode, 4) \ - ZSTD_FOR_EACH_ROWLOG(X, dictMode, 5) \ - ZSTD_FOR_EACH_ROWLOG(X, dictMode, 6) - -#define ZSTD_FOR_EACH_MLS(X, dictMode) \ - X(dictMode, 4) \ - X(dictMode, 5) \ - X(dictMode, 6) - -#define ZSTD_FOR_EACH_DICT_MODE(X, ...) \ - X(__VA_ARGS__, noDict) \ - X(__VA_ARGS__, extDict) \ - X(__VA_ARGS__, dictMatchState) \ - X(__VA_ARGS__, dedicatedDictSearch) - -/* Generate row search fns for each combination of (dictMode, mls, rowLog) */ -ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS_ROWLOG, GEN_ZSTD_ROW_SEARCH_FN) -/* Generate binary Tree search fns for each combination of (dictMode, mls) */ -ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_BT_SEARCH_FN) -/* Generate hash chain search fns for each combination of (dictMode, mls) */ -ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_HC_SEARCH_FN) - -typedef enum { search_hashChain=0, search_binaryTree=1, search_rowHash=2 } searchMethod_e; - -#define GEN_ZSTD_CALL_BT_SEARCH_FN(dictMode, mls) \ - case mls: \ - return ZSTD_BT_SEARCH_FN(dictMode, mls)(ms, ip, iend, offsetPtr); -#define GEN_ZSTD_CALL_HC_SEARCH_FN(dictMode, mls) \ - case mls: \ - return ZSTD_HC_SEARCH_FN(dictMode, mls)(ms, ip, iend, offsetPtr); -#define GEN_ZSTD_CALL_ROW_SEARCH_FN(dictMode, mls, rowLog) \ - case rowLog: \ - return ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog)(ms, ip, iend, offsetPtr); - -#define ZSTD_SWITCH_MLS(X, dictMode) \ - switch (mls) { \ - ZSTD_FOR_EACH_MLS(X, dictMode) \ - } - -#define ZSTD_SWITCH_ROWLOG(dictMode, mls) \ - case mls: \ - switch (rowLog) { \ - ZSTD_FOR_EACH_ROWLOG(GEN_ZSTD_CALL_ROW_SEARCH_FN, dictMode, mls) \ - } \ - ZSTD_UNREACHABLE; \ - break; - -#define ZSTD_SWITCH_SEARCH_METHOD(dictMode) \ - switch (searchMethod) { \ - case search_hashChain: \ - ZSTD_SWITCH_MLS(GEN_ZSTD_CALL_HC_SEARCH_FN, dictMode) \ - break; \ - case search_binaryTree: \ - ZSTD_SWITCH_MLS(GEN_ZSTD_CALL_BT_SEARCH_FN, dictMode) \ - break; \ - case search_rowHash: \ - ZSTD_SWITCH_MLS(ZSTD_SWITCH_ROWLOG, dictMode) \ - break; \ - } \ - ZSTD_UNREACHABLE; - -/** - * Searches for the longest match at @p ip. - * Dispatches to the correct implementation function based on the - * (searchMethod, dictMode, mls, rowLog). We use switch statements - * here instead of using an indirect function call through a function - * pointer because after Spectre and Meltdown mitigations, indirect - * function calls can be very costly, especially in the kernel. - * - * NOTE: dictMode and searchMethod should be templated, so those switch - * statements should be optimized out. Only the mls & rowLog switches - * should be left. - * - * @param ms The match state. - * @param ip The position to search at. - * @param iend The end of the input data. - * @param[out] offsetPtr Stores the match offset into this pointer. - * @param mls The minimum search length, in the range [4, 6]. - * @param rowLog The row log (if applicable), in the range [4, 6]. - * @param searchMethod The search method to use (templated). - * @param dictMode The dictMode (templated). - * - * @returns The length of the longest match found, or < mls if no match is found. - * If a match is found its offset is stored in @p offsetPtr. - */ -FORCE_INLINE_TEMPLATE size_t ZSTD_searchMax( - ZSTD_matchState_t* ms, - const BYTE* ip, - const BYTE* iend, - size_t* offsetPtr, - U32 const mls, - U32 const rowLog, - searchMethod_e const searchMethod, - ZSTD_dictMode_e const dictMode) -{ - if (dictMode == ZSTD_noDict) { - ZSTD_SWITCH_SEARCH_METHOD(noDict) - } else if (dictMode == ZSTD_extDict) { - ZSTD_SWITCH_SEARCH_METHOD(extDict) - } else if (dictMode == ZSTD_dictMatchState) { - ZSTD_SWITCH_SEARCH_METHOD(dictMatchState) - } else if (dictMode == ZSTD_dedicatedDictSearch) { - ZSTD_SWITCH_SEARCH_METHOD(dedicatedDictSearch) - } - ZSTD_UNREACHABLE; - return 0; -} - /* ******************************* * Common parser - lazy strategy *********************************/ +typedef enum { search_hashChain, search_binaryTree } searchMethod_e; FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_lazy_generic( @@ -1502,69 +633,59 @@ ZSTD_compressBlock_lazy_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = (searchMethod == search_rowHash) ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; + const BYTE* const ilimit = iend - 8; const BYTE* const base = ms->window.base; const U32 prefixLowestIndex = ms->window.dictLimit; const BYTE* const prefixLowest = base + prefixLowestIndex; - const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); - U32 offset_1 = rep[0], offset_2 = rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; + typedef size_t (*searchMax_f)( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); + searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ? + (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS + : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) : + (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS + : ZSTD_HcFindBestMatch_selectMLS); + U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0; - const int isDMS = dictMode == ZSTD_dictMatchState; - const int isDDS = dictMode == ZSTD_dedicatedDictSearch; - const int isDxS = isDMS || isDDS; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const U32 dictLowestIndex = isDxS ? dms->window.dictLimit : 0; - const BYTE* const dictBase = isDxS ? dms->window.base : NULL; - const BYTE* const dictLowest = isDxS ? dictBase + dictLowestIndex : NULL; - const BYTE* const dictEnd = isDxS ? dms->window.nextSrc : NULL; - const U32 dictIndexDelta = isDxS ? + const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ? + dms->window.dictLimit : 0; + const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? + dms->window.base : NULL; + const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ? + dictBase + dictLowestIndex : NULL; + const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? + dms->window.nextSrc : NULL; + const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? prefixLowestIndex - (U32)(dictEnd - dictBase) : 0; - const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest)); + const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest); - DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u) (searchFunc=%u)", (U32)dictMode, (U32)searchMethod); + /* init */ ip += (dictAndPrefixLength == 0); if (dictMode == ZSTD_noDict) { - U32 const curr = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, ms->cParams.windowLog); - U32 const maxRep = curr - windowLow; - if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; + U32 const maxRep = (U32)(ip - prefixLowest); + if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; + if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0; } - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); } - /* Reset the lazy skipping state */ - ms->lazySkipping = 0; - - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } - /* Match Loop */ -#if defined(__GNUC__) && defined(__x86_64__) - /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the - * code alignment is perturbed. To fix the instability align the loop on 32-bytes. - */ - __asm__(".p2align 5"); -#endif while (ip < ilimit) { size_t matchLength=0; - size_t offBase = REPCODE1_TO_OFFBASE; + size_t offset=0; const BYTE* start=ip+1; - DEBUGLOG(7, "search baseline (depth 0)"); /* check repCode */ - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { const U32 repIndex = (U32)(ip - base) + 1 - offset_1; - const BYTE* repMatch = ((dictMode == ZSTD_dictMatchState || dictMode == ZSTD_dedicatedDictSearch) + const BYTE* repMatch = (dictMode == ZSTD_dictMatchState && repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; @@ -1582,40 +703,30 @@ ZSTD_compressBlock_lazy_generic( } /* first search (depth 0) */ - { size_t offbaseFound = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &offbaseFound, mls, rowLog, searchMethod, dictMode); + { size_t offsetFound = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); if (ml2 > matchLength) - matchLength = ml2, start = ip, offBase = offbaseFound; + matchLength = ml2, start = ip, offset=offsetFound; } if (matchLength < 4) { - size_t const step = ((size_t)(ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */; - ip += step; - /* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time. - * In this mode we stop inserting every position into our tables, and only insert - * positions that we search, which is one in step positions. - * The exact cutoff is flexible, I've just chosen a number that is reasonably high, - * so we minimize the compression ratio loss in "normal" scenarios. This mode gets - * triggered once we've gone 2KB without finding any matches. - */ - ms->lazySkipping = step > kLazySkippingStep; + ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ continue; } /* let's try to find a better solution */ if (depth>=1) while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -1625,33 +736,32 @@ ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } } - { size_t ofbCandidate=999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, dictMode); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -1661,69 +771,64 @@ ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } } - { size_t ofbCandidate=999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, dictMode); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* NOTE: - * Pay attention that `start[-value]` can lead to strange undefined behavior - * notably if `value` is unsigned, resulting in a large positive `-value`. + * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior. + * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which + * overflows the pointer, which is undefined behavior. */ /* catch up */ - if (OFFBASE_IS_OFFSET(offBase)) { + if (offset) { if (dictMode == ZSTD_noDict) { - while ( ((start > anchor) & (start - OFFBASE_TO_OFFSET(offBase) > prefixLowest)) - && (start[-1] == (start-OFFBASE_TO_OFFSET(offBase))[-1]) ) /* only search for offset within prefix */ + while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest)) + && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ { start--; matchLength++; } } - if (isDxS) { - U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); + if (dictMode == ZSTD_dictMatchState) { + U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex; const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ } - offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); + offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); } /* store sequence */ _storeSequence: - { size_t const litLength = (size_t)(start - anchor); - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); + { size_t const litLength = start - anchor; + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } - if (ms->lazySkipping) { - /* We've found a match, disable lazy skipping mode, and refill the hash cache. */ - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } - ms->lazySkipping = 0; - } /* check immediate repcode */ - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { while (ip <= ilimit) { U32 const current2 = (U32)(ip-base); U32 const repIndex = current2 - offset_2; - const BYTE* repMatch = repIndex < prefixLowestIndex ? + const BYTE* repMatch = dictMode == ZSTD_dictMatchState + && repIndex < prefixLowestIndex ? dictBase - dictIndexDelta + repIndex : base + repIndex; if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */) && (MEM_read32(repMatch) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4; - offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); + offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); ip += matchLength; anchor = ip; continue; @@ -1737,20 +842,16 @@ ZSTD_compressBlock_lazy_generic( && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap repcodes */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); + offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ } } } - /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), - * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ - offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; - - /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved1; - rep[1] = offset_2 ? offset_2 : offsetSaved2; + /* Save reps for next block */ + rep[0] = offset_1 ? offset_1 : savedOffset; + rep[1] = offset_2 ? offset_2 : savedOffset; /* Return the last literals size */ return (size_t)(iend - anchor); @@ -1814,92 +915,6 @@ size_t ZSTD_compressBlock_greedy_dictMatchState( } -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch); -} - -/* Row-based matchfinder */ -size_t ZSTD_compressBlock_lazy2_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict); -} - -size_t ZSTD_compressBlock_lazy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict); -} - -size_t ZSTD_compressBlock_greedy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict); -} - -size_t ZSTD_compressBlock_lazy2_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState); -} - -size_t ZSTD_compressBlock_lazy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState); -} - -size_t ZSTD_compressBlock_greedy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState); -} - - -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch); -} - FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_lazy_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, @@ -1911,50 +926,37 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; + const BYTE* const ilimit = iend - 8; const BYTE* const base = ms->window.base; const U32 dictLimit = ms->window.dictLimit; + const U32 lowestIndex = ms->window.lowLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const dictEnd = dictBase + dictLimit; - const BYTE* const dictStart = dictBase + ms->window.lowLimit; - const U32 windowLog = ms->cParams.windowLog; - const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); + const BYTE* const dictStart = dictBase + lowestIndex; - U32 offset_1 = rep[0], offset_2 = rep[1]; - - DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod); + typedef size_t (*searchMax_f)( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); + searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS; - /* Reset the lazy skipping state */ - ms->lazySkipping = 0; + U32 offset_1 = rep[0], offset_2 = rep[1]; /* init */ ip += (ip == prefixStart); - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } /* Match Loop */ -#if defined(__GNUC__) && defined(__x86_64__) - /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the - * code alignment is perturbed. To fix the instability align the loop on 32-bytes. - */ - __asm__(".p2align 5"); -#endif while (ip < ilimit) { size_t matchLength=0; - size_t offBase = REPCODE1_TO_OFFBASE; + size_t offset=0; const BYTE* start=ip+1; - U32 curr = (U32)(ip-base); + U32 current = (U32)(ip-base); /* check repCode */ - { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1, windowLog); - const U32 repIndex = (U32)(curr+1 - offset_1); + { const U32 repIndex = (U32)(current+1 - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - & (offset_1 <= curr+1 - windowLow) ) /* note: we are searching at curr+1 */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */ if (MEM_read32(ip+1) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; @@ -1963,23 +965,14 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( } } /* first search (depth 0) */ - { size_t ofbCandidate = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); + { size_t offsetFound = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); if (ml2 > matchLength) - matchLength = ml2, start = ip, offBase = ofbCandidate; + matchLength = ml2, start = ip, offset=offsetFound; } - if (matchLength < 4) { - size_t const step = ((size_t)(ip-anchor) >> kSearchStrength); - ip += step + 1; /* jump faster over incompressible sections */ - /* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time. - * In this mode we stop inserting every position into our tables, and only insert - * positions that we search, which is one in step positions. - * The exact cutoff is flexible, I've just chosen a number that is reasonably high, - * so we minimize the compression ratio loss in "normal" scenarios. This mode gets - * triggered once we've gone 2KB without finding any matches. - */ - ms->lazySkipping = step > kLazySkippingStep; + if (matchLength < 4) { + ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ continue; } @@ -1987,107 +980,93 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( if (depth>=1) while (ip= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ - & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = repLength, offset = 0, start = ip; } } /* search match, depth 1 */ - { size_t ofbCandidate = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ - & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = repLength, offset = 0, start = ip; } } /* search match, depth 2 */ - { size_t ofbCandidate = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* catch up */ - if (OFFBASE_IS_OFFSET(offBase)) { - U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); + if (offset) { + U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex; const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ - offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); + offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); } /* store sequence */ _storeSequence: - { size_t const litLength = (size_t)(start - anchor); - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); + { size_t const litLength = start - anchor; + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } - if (ms->lazySkipping) { - /* We've found a match, disable lazy skipping mode, and refill the hash cache. */ - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } - ms->lazySkipping = 0; - } /* check immediate repcode */ while (ip <= ilimit) { - const U32 repCurrent = (U32)(ip-base); - const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent, windowLog); - const U32 repIndex = repCurrent - offset_2; + const U32 repIndex = (U32)((ip-base) - offset_2); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ - & (offset_2 <= repCurrent - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; - offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset history */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); + offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ @@ -2134,27 +1113,3 @@ size_t ZSTD_compressBlock_btlazy2_extDict( { return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2); } - -size_t ZSTD_compressBlock_greedy_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0); -} - -size_t ZSTD_compressBlock_lazy_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) - -{ - return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1); -} - -size_t ZSTD_compressBlock_lazy2_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2); -} - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_lazy.h b/vendor/github.com/DataDog/zstd/zstd_lazy.h index abadc7c4..bb176306 100644 --- a/vendor/github.com/DataDog/zstd/zstd_lazy.h +++ b/vendor/github.com/DataDog/zstd/zstd_lazy.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,20 +17,7 @@ extern "C" { #include "zstd_compress_internal.h" -/** - * Dedicated Dictionary Search Structure bucket log. In the - * ZSTD_dedicatedDictSearch mode, the hashTable has - * 2 ** ZSTD_LAZY_DDSS_BUCKET_LOG entries in each bucket, rather than just - * one. - */ -#define ZSTD_LAZY_DDSS_BUCKET_LOG 2 - -#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */ - U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip); -void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip); - -void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip); void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */ @@ -47,15 +33,6 @@ size_t ZSTD_compressBlock_lazy( size_t ZSTD_compressBlock_greedy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); size_t ZSTD_compressBlock_btlazy2_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -69,34 +46,6 @@ size_t ZSTD_compressBlock_lazy_dictMatchState( size_t ZSTD_compressBlock_greedy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); - -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); size_t ZSTD_compressBlock_greedy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -107,24 +56,12 @@ size_t ZSTD_compressBlock_lazy_extDict( size_t ZSTD_compressBlock_lazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); size_t ZSTD_compressBlock_btlazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); - #if defined (__cplusplus) } #endif #endif /* ZSTD_LAZY_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_ldm.c b/vendor/github.com/DataDog/zstd/zstd_ldm.c index b6c4d968..c3312ad3 100644 --- a/vendor/github.com/DataDog/zstd/zstd_ldm.c +++ b/vendor/github.com/DataDog/zstd/zstd_ldm.c @@ -1,137 +1,22 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the * LICENSE file in the root directory of this source tree) and the GPLv2 (found * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. */ #include "zstd_ldm.h" #include "debug.h" -#include "xxhash.h" #include "zstd_fast.h" /* ZSTD_fillHashTable() */ #include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ -#include "zstd_ldm_geartab.h" #define LDM_BUCKET_SIZE_LOG 3 #define LDM_MIN_MATCH_LENGTH 64 #define LDM_HASH_RLOG 7 - -typedef struct { - U64 rolling; - U64 stopMask; -} ldmRollingHashState_t; - -/** ZSTD_ldm_gear_init(): - * - * Initializes the rolling hash state such that it will honor the - * settings in params. */ -static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params) -{ - unsigned maxBitsInMask = MIN(params->minMatchLength, 64); - unsigned hashRateLog = params->hashRateLog; - - state->rolling = ~(U32)0; - - /* The choice of the splitting criterion is subject to two conditions: - * 1. it has to trigger on average every 2^(hashRateLog) bytes; - * 2. ideally, it has to depend on a window of minMatchLength bytes. - * - * In the gear hash algorithm, bit n depends on the last n bytes; - * so in order to obtain a good quality splitting criterion it is - * preferable to use bits with high weight. - * - * To match condition 1 we use a mask with hashRateLog bits set - * and, because of the previous remark, we make sure these bits - * have the highest possible weight while still respecting - * condition 2. - */ - if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) { - state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog); - } else { - /* In this degenerate case we simply honor the hash rate. */ - state->stopMask = ((U64)1 << hashRateLog) - 1; - } -} - -/** ZSTD_ldm_gear_reset() - * Feeds [data, data + minMatchLength) into the hash without registering any - * splits. This effectively resets the hash state. This is used when skipping - * over data, either at the beginning of a block, or skipping sections. - */ -static void ZSTD_ldm_gear_reset(ldmRollingHashState_t* state, - BYTE const* data, size_t minMatchLength) -{ - U64 hash = state->rolling; - size_t n = 0; - -#define GEAR_ITER_ONCE() do { \ - hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ - n += 1; \ - } while (0) - while (n + 3 < minMatchLength) { - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - } - while (n < minMatchLength) { - GEAR_ITER_ONCE(); - } -#undef GEAR_ITER_ONCE -} - -/** ZSTD_ldm_gear_feed(): - * - * Registers in the splits array all the split points found in the first - * size bytes following the data pointer. This function terminates when - * either all the data has been processed or LDM_BATCH_SIZE splits are - * present in the splits array. - * - * Precondition: The splits array must not be full. - * Returns: The number of bytes processed. */ -static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state, - BYTE const* data, size_t size, - size_t* splits, unsigned* numSplits) -{ - size_t n; - U64 hash, mask; - - hash = state->rolling; - mask = state->stopMask; - n = 0; - -#define GEAR_ITER_ONCE() do { \ - hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ - n += 1; \ - if (UNLIKELY((hash & mask) == 0)) { \ - splits[*numSplits] = n; \ - *numSplits += 1; \ - if (*numSplits == LDM_BATCH_SIZE) \ - goto done; \ - } \ - } while (0) - - while (n + 3 < size) { - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - } - while (n < size) { - GEAR_ITER_ONCE(); - } - -#undef GEAR_ITER_ONCE - -done: - state->rolling = hash; - return n; -} +#define LDM_HASH_CHAR_OFFSET 10 void ZSTD_ldm_adjustParameters(ldmParams_t* params, ZSTD_compressionParameters const* cParams) @@ -141,6 +26,13 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, DEBUGLOG(4, "ZSTD_ldm_adjustParameters"); if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH; + if (cParams->strategy >= ZSTD_btopt) { + /* Get out of the way of the optimal parser */ + U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength); + assert(minMatch >= ZSTD_LDM_MINMATCH_MIN); + assert(minMatch <= ZSTD_LDM_MINMATCH_MAX); + params->minMatchLength = minMatch; + } if (params->hashLog == 0) { params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG); assert(params->hashLog <= ZSTD_HASHLOG_MAX); @@ -160,12 +52,47 @@ size_t ZSTD_ldm_getTableSize(ldmParams_t params) size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog); size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize) + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t)); - return params.enableLdm == ZSTD_ps_enable ? totalSize : 0; + return params.enableLdm ? totalSize : 0; } size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize) { - return params.enableLdm == ZSTD_ps_enable ? (maxChunkSize / params.minMatchLength) : 0; + return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0; +} + +/** ZSTD_ldm_getSmallHash() : + * numBits should be <= 32 + * If numBits==0, returns 0. + * @return : the most significant numBits of value. */ +static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) +{ + assert(numBits <= 32); + return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); +} + +/** ZSTD_ldm_getChecksum() : + * numBitsToDiscard should be <= 32 + * @return : the next most significant 32 bits after numBitsToDiscard */ +static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) +{ + assert(numBitsToDiscard <= 32); + return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; +} + +/** ZSTD_ldm_getTag() ; + * Given the hash, returns the most significant numTagBits bits + * after (32 + hbits) bits. + * + * If there are not enough bits remaining, return the last + * numTagBits bits. */ +static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) +{ + assert(numTagBits < 32 && hbits <= 32); + if (32 - hbits < numTagBits) { + return hash & (((U32)1 << numTagBits) - 1); + } else { + return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1); + } } /** ZSTD_ldm_getBucket() : @@ -182,12 +109,38 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, size_t const hash, const ldmEntry_t entry, ldmParams_t const ldmParams) { - BYTE* const pOffset = ldmState->bucketOffsets + hash; - unsigned const offset = *pOffset; - - *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry; - *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1)); + BYTE* const bucketOffsets = ldmState->bucketOffsets; + *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; + bucketOffsets[hash]++; + bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1; +} +/** ZSTD_ldm_makeEntryAndInsertByTag() : + * + * Gets the small hash, checksum, and tag from the rollingHash. + * + * If the tag matches (1 << ldmParams.hashRateLog)-1, then + * creates an ldmEntry from the offset, and inserts it into the hash table. + * + * hBits is the length of the small hash, which is the most significant hBits + * of rollingHash. The checksum is the next 32 most significant bits, followed + * by ldmParams.hashRateLog bits that make up the tag. */ +static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, + U64 const rollingHash, + U32 const hBits, + U32 const offset, + ldmParams_t const ldmParams) +{ + U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog); + U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1; + if (tag == tagMask) { + U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + ldmEntry_t entry; + entry.offset = offset; + entry.checksum = checksum; + ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); + } } /** ZSTD_ldm_countBackwardsMatch() : @@ -196,10 +149,10 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ static size_t ZSTD_ldm_countBackwardsMatch( const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pMatchBase) + const BYTE* pMatch, const BYTE* pBase) { size_t matchLength = 0; - while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) { + while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { pIn--; pMatch--; matchLength++; @@ -207,27 +160,6 @@ static size_t ZSTD_ldm_countBackwardsMatch( return matchLength; } -/** ZSTD_ldm_countBackwardsMatch_2segments() : - * Returns the number of bytes that match backwards from pMatch, - * even with the backwards match spanning 2 different segments. - * - * On reaching `pMatchBase`, start counting from mEnd */ -static size_t ZSTD_ldm_countBackwardsMatch_2segments( - const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pMatchBase, - const BYTE* pExtDictStart, const BYTE* pExtDictEnd) -{ - size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase); - if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) { - /* If backwards match is entirely in the extDict or prefix, immediately return */ - return matchLength; - } - DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength); - matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart); - DEBUGLOG(7, "final backwards match length = %zu", matchLength); - return matchLength; -} - /** ZSTD_ldm_fillFastTables() : * * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. @@ -243,11 +175,11 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, switch(ms->cParams.strategy) { case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); + ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast); break; case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); + ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast); break; case ZSTD_greedy: @@ -265,43 +197,30 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, return 0; } -void ZSTD_ldm_fillHashTable( - ldmState_t* ldmState, const BYTE* ip, - const BYTE* iend, ldmParams_t const* params) +/** ZSTD_ldm_fillLdmHashTable() : + * + * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). + * lastHash is the rolling hash that corresponds to lastHashed. + * + * Returns the rolling hash corresponding to position iend-1. */ +static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, + U64 lastHash, const BYTE* lastHashed, + const BYTE* iend, const BYTE* base, + U32 hBits, ldmParams_t const ldmParams) { - U32 const minMatchLength = params->minMatchLength; - U32 const hBits = params->hashLog - params->bucketSizeLog; - BYTE const* const base = ldmState->window.base; - BYTE const* const istart = ip; - ldmRollingHashState_t hashState; - size_t* const splits = ldmState->splitIndices; - unsigned numSplits; - - DEBUGLOG(5, "ZSTD_ldm_fillHashTable"); - - ZSTD_ldm_gear_init(&hashState, params); - while (ip < iend) { - size_t hashed; - unsigned n; - - numSplits = 0; - hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits); - - for (n = 0; n < numSplits; n++) { - if (ip + splits[n] >= istart + minMatchLength) { - BYTE const* const split = ip + splits[n] - minMatchLength; - U64 const xxhash = XXH64(split, minMatchLength, 0); - U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); - ldmEntry_t entry; - - entry.offset = (U32)(split - base); - entry.checksum = (U32)(xxhash >> 32); - ZSTD_ldm_insertEntry(ldmState, hash, entry, *params); - } - } - - ip += hashed; + U64 rollingHash = lastHash; + const BYTE* cur = lastHashed + 1; + + while (cur < iend) { + rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1], + cur[ldmParams.minMatchLength-1], + state->hashPower); + ZSTD_ldm_makeEntryAndInsertByTag(state, + rollingHash, hBits, + (U32)(cur - base), ldmParams); + ++cur; } + return rollingHash; } @@ -312,10 +231,10 @@ void ZSTD_ldm_fillHashTable( * (after a long match, only update tables a limited amount). */ static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor) { - U32 const curr = (U32)(anchor - ms->window.base); - if (curr > ms->nextToUpdate + 1024) { + U32 const current = (U32)(anchor - ms->window.base); + if (current > ms->nextToUpdate + 1024) { ms->nextToUpdate = - curr - MIN(512, curr - ms->nextToUpdate - 1024); + current - MIN(512, current - ms->nextToUpdate - 1024); } } @@ -326,8 +245,11 @@ static size_t ZSTD_ldm_generateSequences_internal( /* LDM parameters */ int const extDict = ZSTD_window_hasExtDict(ldmState->window); U32 const minMatchLength = params->minMatchLength; - U32 const entsPerBucket = 1U << params->bucketSizeLog; + U64 const hashPower = ldmState->hashPower; U32 const hBits = params->hashLog - params->bucketSizeLog; + U32 const ldmBucketSize = 1U << params->bucketSizeLog; + U32 const hashRateLog = params->hashRateLog; + U32 const ldmTagMask = (1U << params->hashRateLog) - 1; /* Prefix and extDict parameters */ U32 const dictLimit = ldmState->window.dictLimit; U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit; @@ -339,69 +261,45 @@ static size_t ZSTD_ldm_generateSequences_internal( /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; - BYTE const* const ilimit = iend - HASH_READ_SIZE; + BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE); /* Input positions */ BYTE const* anchor = istart; BYTE const* ip = istart; - /* Rolling hash state */ - ldmRollingHashState_t hashState; - /* Arrays for staged-processing */ - size_t* const splits = ldmState->splitIndices; - ldmMatchCandidate_t* const candidates = ldmState->matchCandidates; - unsigned numSplits; - - if (srcSize < minMatchLength) - return iend - anchor; - - /* Initialize the rolling hash state with the first minMatchLength bytes */ - ZSTD_ldm_gear_init(&hashState, params); - ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength); - ip += minMatchLength; - - while (ip < ilimit) { - size_t hashed; - unsigned n; - - numSplits = 0; - hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip, - splits, &numSplits); - - for (n = 0; n < numSplits; n++) { - BYTE const* const split = ip + splits[n] - minMatchLength; - U64 const xxhash = XXH64(split, minMatchLength, 0); - U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); - - candidates[n].split = split; - candidates[n].hash = hash; - candidates[n].checksum = (U32)(xxhash >> 32); - candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params); - PREFETCH_L1(candidates[n].bucket); + /* Rolling hash */ + BYTE const* lastHashed = NULL; + U64 rollingHash = 0; + + while (ip <= ilimit) { + size_t mLength; + U32 const current = (U32)(ip - base); + size_t forwardMatchLength = 0, backwardMatchLength = 0; + ldmEntry_t* bestEntry = NULL; + if (ip != istart) { + rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0], + lastHashed[minMatchLength], + hashPower); + } else { + rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength); } + lastHashed = ip; - for (n = 0; n < numSplits; n++) { - size_t forwardMatchLength = 0, backwardMatchLength = 0, - bestMatchLength = 0, mLength; - U32 offset; - BYTE const* const split = candidates[n].split; - U32 const checksum = candidates[n].checksum; - U32 const hash = candidates[n].hash; - ldmEntry_t* const bucket = candidates[n].bucket; - ldmEntry_t const* cur; - ldmEntry_t const* bestEntry = NULL; - ldmEntry_t newEntry; - - newEntry.offset = (U32)(split - base); - newEntry.checksum = checksum; - - /* If a split point would generate a sequence overlapping with - * the previous one, we merely register it in the hash table and - * move on */ - if (split < anchor) { - ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); - continue; - } + /* Do not insert and do not look for a match */ + if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) { + ip++; + continue; + } - for (cur = bucket; cur < bucket + entsPerBucket; cur++) { + /* Get the best entry and compute the match lengths */ + { + ldmEntry_t* const bucket = + ZSTD_ldm_getBucket(ldmState, + ZSTD_ldm_getSmallHash(rollingHash, hBits), + *params); + ldmEntry_t* cur; + size_t bestMatchLength = 0; + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + + for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { size_t curForwardMatchLength, curBackwardMatchLength, curTotalMatchLength; if (cur->checksum != checksum || cur->offset <= lowestIndex) { @@ -415,23 +313,30 @@ static size_t ZSTD_ldm_generateSequences_internal( cur->offset < dictLimit ? dictEnd : iend; BYTE const* const lowMatchPtr = cur->offset < dictLimit ? dictStart : lowPrefixPtr; - curForwardMatchLength = - ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr); + + curForwardMatchLength = ZSTD_count_2segments( + ip, pMatch, iend, + matchEnd, lowPrefixPtr); if (curForwardMatchLength < minMatchLength) { continue; } - curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments( - split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd); + curBackwardMatchLength = + ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, + lowMatchPtr); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; } else { /* !extDict */ BYTE const* const pMatch = base + cur->offset; - curForwardMatchLength = ZSTD_count(split, pMatch, iend); + curForwardMatchLength = ZSTD_count(ip, pMatch, iend); if (curForwardMatchLength < minMatchLength) { continue; } curBackwardMatchLength = - ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr); + ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, + lowPrefixPtr); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; } - curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength; if (curTotalMatchLength > bestMatchLength) { bestMatchLength = curTotalMatchLength; @@ -440,54 +345,57 @@ static size_t ZSTD_ldm_generateSequences_internal( bestEntry = cur; } } + } - /* No match found -- insert an entry into the hash table - * and process the next candidate match */ - if (bestEntry == NULL) { - ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); - continue; - } - - /* Match found */ - offset = (U32)(split - base) - bestEntry->offset; - mLength = forwardMatchLength + backwardMatchLength; - { - rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; - - /* Out of sequence storage */ - if (rawSeqStore->size == rawSeqStore->capacity) - return ERROR(dstSize_tooSmall); - seq->litLength = (U32)(split - backwardMatchLength - anchor); - seq->matchLength = (U32)mLength; - seq->offset = offset; - rawSeqStore->size++; - } - - /* Insert the current entry into the hash table --- it must be - * done after the previous block to avoid clobbering bestEntry */ - ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); + /* No match found -- continue searching */ + if (bestEntry == NULL) { + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, + hBits, current, + *params); + ip++; + continue; + } - anchor = split + forwardMatchLength; + /* Match found */ + mLength = forwardMatchLength + backwardMatchLength; + ip -= backwardMatchLength; - /* If we find a match that ends after the data that we've hashed - * then we have a repeating, overlapping, pattern. E.g. all zeros. - * If one repetition of the pattern matches our `stopMask` then all - * repetitions will. We don't need to insert them all into out table, - * only the first one. So skip over overlapping matches. - * This is a major speed boost (20x) for compressing a single byte - * repeated, when that byte ends up in the table. + { + /* Store the sequence: + * ip = current - backwardMatchLength + * The match is at (bestEntry->offset - backwardMatchLength) */ - if (anchor > ip + hashed) { - ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength); - /* Continue the outer loop at anchor (ip + hashed == anchor). */ - ip = anchor - hashed; - break; - } + U32 const matchIndex = bestEntry->offset; + U32 const offset = current - matchIndex; + rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; + + /* Out of sequence storage */ + if (rawSeqStore->size == rawSeqStore->capacity) + return ERROR(dstSize_tooSmall); + seq->litLength = (U32)(ip - anchor); + seq->matchLength = (U32)mLength; + seq->offset = offset; + rawSeqStore->size++; } - ip += hashed; - } + /* Insert the current entry into the hash table */ + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base), + *params); + assert(ip + backwardMatchLength == lastHashed); + + /* Fill the hash table from lastHashed+1 to ip+mLength*/ + /* Heuristic: don't need to fill the entire table at end of block */ + if (ip + mLength <= ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + mLength, base, hBits, *params); + lastHashed = ip + mLength - 1; + } + ip += mLength; + anchor = ip; + } return iend - anchor; } @@ -536,13 +444,11 @@ size_t ZSTD_ldm_generateSequences( assert(chunkStart < iend); /* 1. Perform overflow correction if necessary. */ - if (ZSTD_window_needOverflowCorrection(ldmState->window, 0, maxDist, ldmState->loadedDictEnd, chunkStart, chunkEnd)) { + if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) { U32 const ldmHSize = 1U << params->hashLog; U32 const correction = ZSTD_window_correctOverflow( &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart); ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction); - /* invalidate dictionaries on overflow correction */ - ldmState->loadedDictEnd = 0; } /* 2. We enforce the maximum offset allowed. * @@ -550,15 +456,9 @@ size_t ZSTD_ldm_generateSequences( * the window through early invalidation. * TODO: * Test the chunk size. * * Try invalidation after the sequence generation and test the - * offset against maxDist directly. - * - * NOTE: Because of dictionaries + sequence splitting we MUST make sure - * that any offset used is valid at the END of the sequence, since it may - * be split into two sequences. This condition holds when using - * ZSTD_window_enforceMaxDist(), but if we move to checking offsets - * against maxDist directly, we'll have to carefully handle that case. + * the offset against maxDist directly. */ - ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, &ldmState->loadedDictEnd, NULL); + ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL, NULL); /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */ newLeftoverSize = ZSTD_ldm_generateSequences_internal( ldmState, sequences, params, chunkStart, chunkSize); @@ -580,9 +480,7 @@ size_t ZSTD_ldm_generateSequences( return 0; } -void -ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) -{ +void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) { while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) { rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos; if (srcSize <= seq->litLength) { @@ -641,32 +539,14 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore, return sequence; } -void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) { - U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); - while (currPos && rawSeqStore->pos < rawSeqStore->size) { - rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; - if (currPos >= currSeq.litLength + currSeq.matchLength) { - currPos -= currSeq.litLength + currSeq.matchLength; - rawSeqStore->pos++; - } else { - rawSeqStore->posInSequence = currPos; - break; - } - } - if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { - rawSeqStore->posInSequence = 0; - } -} - size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize) { const ZSTD_compressionParameters* const cParams = &ms->cParams; unsigned const minMatch = cParams->minMatch; ZSTD_blockCompressor const blockCompressor = - ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms)); + ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms)); /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; @@ -674,18 +554,9 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, BYTE const* ip = istart; DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize); - /* If using opt parser, use LDMs only as candidates rather than always accepting them */ - if (cParams->strategy >= ZSTD_btopt) { - size_t lastLLSize; - ms->ldmSeqStore = rawSeqStore; - lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize); - ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize); - return lastLLSize; - } - assert(rawSeqStore->pos <= rawSeqStore->size); assert(rawSeqStore->size <= rawSeqStore->capacity); - /* Loop through each sequence and apply the block compressor to the literals */ + /* Loop through each sequence and apply the block compressor to the lits */ while (rawSeqStore->pos < rawSeqStore->size && ip < iend) { /* maybeSplitSequence updates rawSeqStore->pos */ rawSeq const sequence = maybeSplitSequence(rawSeqStore, @@ -695,13 +566,14 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, if (sequence.offset == 0) break; + assert(sequence.offset <= (1U << cParams->windowLog)); assert(ip + sequence.litLength + sequence.matchLength <= iend); /* Fill tables for block compressor */ ZSTD_ldm_limitTableUpdate(ms, ip); ZSTD_ldm_fillFastTables(ms, ip); /* Run the block compressor */ - DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength); + DEBUGLOG(5, "calling block compressor on segment of size %u", sequence.litLength); { size_t const newLitLength = blockCompressor(ms, seqStore, rep, ip, sequence.litLength); @@ -712,8 +584,8 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, rep[0] = sequence.offset; /* Store the sequence */ ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend, - OFFSET_TO_OFFBASE(sequence.offset), - sequence.matchLength); + sequence.offset + ZSTD_REP_MOVE, + sequence.matchLength - MINMATCH); ip += sequence.matchLength; } } @@ -723,5 +595,3 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, /* Compress the last literals */ return blockCompressor(ms, seqStore, rep, ip, iend - ip); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_ldm.h b/vendor/github.com/DataDog/zstd/zstd_ldm.h index ceabc238..a4784612 100644 --- a/vendor/github.com/DataDog/zstd/zstd_ldm.h +++ b/vendor/github.com/DataDog/zstd/zstd_ldm.h @@ -1,12 +1,10 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the * LICENSE file in the root directory of this source tree) and the GPLv2 (found * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. */ #ifndef ZSTD_LDM_H @@ -25,10 +23,6 @@ extern "C" { #define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT -void ZSTD_ldm_fillHashTable( - ldmState_t* state, const BYTE* ip, - const BYTE* iend, ldmParams_t const* params); - /** * ZSTD_ldm_generateSequences(): * @@ -67,7 +61,6 @@ size_t ZSTD_ldm_generateSequences( */ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize); /** @@ -75,17 +68,11 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, * * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`. * Avoids emitting matches less than `minMatch` bytes. - * Must be called for data that is not passed to ZSTD_ldm_blockCompress(). + * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). */ void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch); -/* ZSTD_ldm_skipRawSeqStoreBytes(): - * Moves forward in rawSeqStore by nbBytes, updating fields 'pos' and 'posInSequence'. - * Not to be used in conjunction with ZSTD_ldm_skipSequences(). - * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). - */ -void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes); /** ZSTD_ldm_getTableSize() : * Estimate the space needed for long distance matching tables or 0 if LDM is @@ -116,5 +103,3 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, #endif #endif /* ZSTD_FAST_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_ldm_geartab.h b/vendor/github.com/DataDog/zstd/zstd_ldm_geartab.h deleted file mode 100644 index 5d799e7f..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_ldm_geartab.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_LDM_GEARTAB_H -#define ZSTD_LDM_GEARTAB_H - -#include "compiler.h" /* UNUSED_ATTR */ -#include "mem.h" /* U64 */ - -static UNUSED_ATTR const U64 ZSTD_ldm_gearTab[256] = { - 0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc, - 0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05, - 0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e, - 0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889, - 0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e, - 0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140, - 0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e, - 0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f, - 0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391, - 0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210, - 0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be, - 0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a, - 0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b, - 0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4, - 0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb, - 0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312, - 0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01, - 0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc, - 0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967, - 0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553, - 0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f, - 0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2, - 0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d, - 0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a, - 0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74, - 0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3, - 0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1, - 0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b, - 0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568, - 0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a, - 0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1, - 0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9, - 0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463, - 0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba, - 0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9, - 0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61, - 0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec, - 0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6, - 0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab, - 0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5, - 0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59, - 0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7, - 0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc, - 0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb, - 0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be, - 0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312, - 0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1, - 0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc, - 0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d, - 0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445, - 0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c, - 0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5, - 0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5, - 0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28, - 0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a, - 0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9, - 0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15, - 0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef, - 0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2, - 0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375, - 0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3, - 0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595, - 0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389, - 0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4, - 0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756, - 0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc, - 0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45, - 0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea, - 0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f, - 0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc, - 0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c, - 0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a, - 0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17, - 0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3, - 0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4, - 0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91, - 0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40, - 0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741, - 0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f, - 0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4, - 0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad, - 0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047, - 0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2, - 0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e, - 0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b, - 0x2b4da14f2613d8f4 -}; - -#endif /* ZSTD_LDM_GEARTAB_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_legacy.h b/vendor/github.com/DataDog/zstd/zstd_legacy.h index a43c232e..0dbd3c7a 100644 --- a/vendor/github.com/DataDog/zstd/zstd_legacy.h +++ b/vendor/github.com/DataDog/zstd/zstd_legacy.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -243,13 +242,6 @@ MEM_STATIC ZSTD_frameSizeInfo ZSTD_findFrameSizeInfoLegacy(const void *src, size frameSizeInfo.compressedSize = ERROR(srcSize_wrong); frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR; } - /* In all cases, decompressedBound == nbBlocks * ZSTD_BLOCKSIZE_MAX. - * So we can compute nbBlocks without having to change every function. - */ - if (frameSizeInfo.decompressedBound != ZSTD_CONTENTSIZE_ERROR) { - assert((frameSizeInfo.decompressedBound & (ZSTD_BLOCKSIZE_MAX - 1)) == 0); - frameSizeInfo.nbBlocks = (size_t)(frameSizeInfo.decompressedBound / ZSTD_BLOCKSIZE_MAX); - } return frameSizeInfo; } @@ -421,5 +413,3 @@ MEM_STATIC size_t ZSTD_decompressLegacyStream(void* legacyContext, U32 version, #endif #endif /* ZSTD_LEGACY_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_opt.c b/vendor/github.com/DataDog/zstd/zstd_opt.c index ca5fdb77..2e50fca6 100644 --- a/vendor/github.com/DataDog/zstd/zstd_opt.c +++ b/vendor/github.com/DataDog/zstd/zstd_opt.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,47 +14,40 @@ #define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */ +#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */ #define ZSTD_MAX_PRICE (1<<30) -#define ZSTD_PREDEF_THRESHOLD 8 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ +#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ /*-************************************* * Price functions for optimal parser ***************************************/ -#if 0 /* approximation at bit level (for tests) */ +#if 0 /* approximation at bit level */ # define BITCOST_ACCURACY 0 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat, opt) ((void)(opt), ZSTD_bitWeight(stat)) -#elif 0 /* fractional bit accuracy (for tests) */ +# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat)) +#elif 0 /* fractional bit accuracy */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat,opt) ((void)(opt), ZSTD_fracWeight(stat)) +# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat)) #else /* opt==approx, ultra==accurate */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat,opt) ((opt) ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) +# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) #endif -/* ZSTD_bitWeight() : - * provide estimated "cost" of a stat in full bits only */ MEM_STATIC U32 ZSTD_bitWeight(U32 stat) { return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER); } -/* ZSTD_fracWeight() : - * provide fractional-bit "cost" of a stat, - * using linear interpolation approximation */ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) { U32 const stat = rawStat + 1; U32 const hb = ZSTD_highbit32(stat); U32 const BWeight = hb * BITCOST_MULTIPLIER; - /* Fweight was meant for "Fractional weight" - * but it's effectively a value between 1 and 2 - * using fixed point arithmetic */ U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb; U32 const weight = BWeight + FWeight; assert(hb + BITCOST_ACCURACY < 31); @@ -66,7 +58,7 @@ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) /* debugging function, * @return price in bytes as fractional value * for debug messages only */ -MEM_STATIC double ZSTD_fCost(int price) +MEM_STATIC double ZSTD_fCost(U32 price) { return (double)price / (BITCOST_MULTIPLIER*8); } @@ -74,7 +66,7 @@ MEM_STATIC double ZSTD_fCost(int price) static int ZSTD_compressedLiterals(optState_t const* const optPtr) { - return optPtr->literalCompressionMode != ZSTD_ps_disable; + return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed; } static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) @@ -87,52 +79,25 @@ static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) } -static U32 sum_u32(const unsigned table[], size_t nbElts) -{ - size_t n; - U32 total = 0; - for (n=0; n 0 && ZSTD_FREQ_DIV+malus < 31); for (s=0; s0); - unsigned const newStat = base + (table[s] >> shift); - sum += newStat; - table[s] = newStat; + table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus)); + sum += table[s]; } return sum; } -/* ZSTD_scaleStats() : - * reduce all elt frequencies in table if sum too large - * return the resulting sum of elements */ -static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget) -{ - U32 const prevsum = sum_u32(table, lastEltIndex+1); - U32 const factor = prevsum >> logTarget; - DEBUGLOG(5, "ZSTD_scaleStats (nbElts=%u, target=%u)", (unsigned)lastEltIndex+1, (unsigned)logTarget); - assert(logTarget < 30); - if (factor <= 1) return prevsum; - return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor), base_1guaranteed); -} - /* ZSTD_rescaleFreqs() : * if first block (detected by optPtr->litLengthSum == 0) : init statistics * take hints from dictionary if there is one - * and init from zero if there is none, - * using src for literals stats, and baseline stats for sequence symbols + * or init from zero, using src for literals stats, or flat 1 for match symbols * otherwise downscale existing stats, to be used as seed for next block. */ static void @@ -144,28 +109,24 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize); optPtr->priceType = zop_dynamic; - if (optPtr->litLengthSum == 0) { /* no literals stats collected -> first block assumed -> init */ - - /* heuristic: use pre-defined stats for too small inputs */ - if (srcSize <= ZSTD_PREDEF_THRESHOLD) { - DEBUGLOG(5, "srcSize <= %i : use predefined stats", ZSTD_PREDEF_THRESHOLD); + if (optPtr->litLengthSum == 0) { /* first block : init */ + if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */ + DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef"); optPtr->priceType = zop_predef; } assert(optPtr->symbolCosts != NULL); if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) { - - /* huffman stats covering the full value set : table presumed generated by dictionary */ + /* huffman table presumed generated by dictionary */ optPtr->priceType = zop_dynamic; if (compressedLiterals) { - /* generate literals statistics from huffman table */ unsigned lit; assert(optPtr->litFreq != NULL); optPtr->litSum = 0; for (lit=0; lit<=MaxLit; lit++) { U32 const scaleLog = 11; /* scale to 2K */ - U32 const bitCost = HUF_getNbBitsFromCTable(optPtr->symbolCosts->huf.CTable, lit); + U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit); assert(bitCost <= scaleLog); optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; optPtr->litSum += optPtr->litFreq[lit]; @@ -207,26 +168,20 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, optPtr->offCodeSum += optPtr->offCodeFreq[of]; } } - } else { /* first block, no dictionary */ + } else { /* not a dictionary */ assert(optPtr->litFreq != NULL); if (compressedLiterals) { - /* base initial cost of literals on direct frequency within src */ unsigned lit = MaxLit; HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ - optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8, base_0possible); + optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); } - { unsigned const baseLLfreqs[MaxLL+1] = { - 4, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1 - }; - ZSTD_memcpy(optPtr->litLengthFreq, baseLLfreqs, sizeof(baseLLfreqs)); - optPtr->litLengthSum = sum_u32(baseLLfreqs, MaxLL+1); + { unsigned ll; + for (ll=0; ll<=MaxLL; ll++) + optPtr->litLengthFreq[ll] = 1; } + optPtr->litLengthSum = MaxLL+1; { unsigned ml; for (ml=0; ml<=MaxML; ml++) @@ -234,25 +189,21 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, } optPtr->matchLengthSum = MaxML+1; - { unsigned const baseOFCfreqs[MaxOff+1] = { - 6, 2, 1, 1, 2, 3, 4, 4, - 4, 3, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 - }; - ZSTD_memcpy(optPtr->offCodeFreq, baseOFCfreqs, sizeof(baseOFCfreqs)); - optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1); + { unsigned of; + for (of=0; of<=MaxOff; of++) + optPtr->offCodeFreq[of] = 1; } + optPtr->offCodeSum = MaxOff+1; } - } else { /* new block : scale down accumulated statistics */ + } else { /* new block : re-use previous statistics, scaled down */ if (compressedLiterals) - optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12); - optPtr->litLengthSum = ZSTD_scaleStats(optPtr->litLengthFreq, MaxLL, 11); - optPtr->matchLengthSum = ZSTD_scaleStats(optPtr->matchLengthFreq, MaxML, 11); - optPtr->offCodeSum = ZSTD_scaleStats(optPtr->offCodeFreq, MaxOff, 11); + optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); + optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0); + optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0); + optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0); } ZSTD_setBasePrices(optPtr, optLevel); @@ -274,14 +225,11 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */ /* dynamic statistics */ - { U32 price = optPtr->litSumBasePrice * litLength; - U32 const litPriceMax = optPtr->litSumBasePrice - BITCOST_MULTIPLIER; + { U32 price = litLength * optPtr->litSumBasePrice; U32 u; - assert(optPtr->litSumBasePrice >= BITCOST_MULTIPLIER); for (u=0; u < litLength; u++) { - U32 litPrice = WEIGHT(optPtr->litFreq[literals[u]], optLevel); - if (UNLIKELY(litPrice > litPriceMax)) litPrice = litPriceMax; - price -= litPrice; + assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */ + price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel); } return price; } @@ -291,17 +239,7 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, * cost of literalLength symbol */ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel) { - assert(litLength <= ZSTD_BLOCKSIZE_MAX); - if (optPtr->priceType == zop_predef) - return WEIGHT(litLength, optLevel); - - /* ZSTD_LLcode() can't compute litLength price for sizes >= ZSTD_BLOCKSIZE_MAX - * because it isn't representable in the zstd format. - * So instead just pretend it would cost 1 bit more than ZSTD_BLOCKSIZE_MAX - 1. - * In such a case, the block would be all literals. - */ - if (litLength == ZSTD_BLOCKSIZE_MAX) - return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel); + if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel); /* dynamic statistics */ { U32 const llCode = ZSTD_LLcode(litLength); @@ -311,26 +249,57 @@ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optP } } +/* ZSTD_litLengthContribution() : + * @return ( cost(litlength) - cost(0) ) + * this value can then be added to rawLiteralsCost() + * to provide a cost which is directly comparable to a match ending at same position */ +static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel) +{ + if (optPtr->priceType >= zop_predef) return (int)WEIGHT(litLength, optLevel); + + /* dynamic statistics */ + { U32 const llCode = ZSTD_LLcode(litLength); + int const contribution = (int)(LL_bits[llCode] * BITCOST_MULTIPLIER) + + (int)WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */ + - (int)WEIGHT(optPtr->litLengthFreq[llCode], optLevel); +#if 1 + return contribution; +#else + return MAX(0, contribution); /* sometimes better, sometimes not ... */ +#endif + } +} + +/* ZSTD_literalsContribution() : + * creates a fake cost for the literals part of a sequence + * which can be compared to the ending cost of a match + * should a new match start at this position */ +static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength, + const optState_t* const optPtr, + int optLevel) +{ + int const contribution = (int)ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel) + + ZSTD_litLengthContribution(litLength, optPtr, optLevel); + return contribution; +} + /* ZSTD_getMatchPrice() : - * Provides the cost of the match part (offset + matchLength) of a sequence. + * Provides the cost of the match part (offset + matchLength) of a sequence * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence. - * @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq() - * @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) - */ + * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */ FORCE_INLINE_TEMPLATE U32 -ZSTD_getMatchPrice(U32 const offBase, +ZSTD_getMatchPrice(U32 const offset, U32 const matchLength, const optState_t* const optPtr, int const optLevel) { U32 price; - U32 const offCode = ZSTD_highbit32(offBase); + U32 const offCode = ZSTD_highbit32(offset+1); U32 const mlBase = matchLength - MINMATCH; assert(matchLength >= MINMATCH); - if (optPtr->priceType == zop_predef) /* fixed scheme, does not use statistics */ - return WEIGHT(mlBase, optLevel) - + ((16 + offCode) * BITCOST_MULTIPLIER); /* emulated offset cost */ + if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */ + return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER); /* dynamic statistics */ price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel)); @@ -349,10 +318,10 @@ ZSTD_getMatchPrice(U32 const offBase, } /* ZSTD_updateStats() : - * assumption : literals + litLength <= iend */ + * assumption : literals + litLengtn <= iend */ static void ZSTD_updateStats(optState_t* const optPtr, U32 litLength, const BYTE* literals, - U32 offBase, U32 matchLength) + U32 offsetCode, U32 matchLength) { /* literals */ if (ZSTD_compressedLiterals(optPtr)) { @@ -368,8 +337,8 @@ static void ZSTD_updateStats(optState_t* const optPtr, optPtr->litLengthSum++; } - /* offset code : follows storeSeq() numeric representation */ - { U32 const offCode = ZSTD_highbit32(offBase); + /* match offset code (0-2=>repCode; 3+=>offset+2) */ + { U32 const offCode = ZSTD_highbit32(offsetCode+1); assert(offCode <= MaxOff); optPtr->offCodeFreq[offCode]++; optPtr->offCodeSum++; @@ -403,7 +372,7 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) /* Update hashTable3 up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms, +static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, U32* nextToUpdate3, const BYTE* const ip) { @@ -429,13 +398,11 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms, * Binary Tree search ***************************************/ /** ZSTD_insertBt1() : add one or multiple positions to tree. - * @param ip assumed <= iend-8 . - * @param target The target of ZSTD_updateTree_internal() - we are filling to this position + * ip : assumed <= iend-8 . * @return : nb of positions added */ static U32 ZSTD_insertBt1( - const ZSTD_matchState_t* ms, + ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, - U32 const target, U32 const mls, const int extDict) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -453,36 +420,32 @@ static U32 ZSTD_insertBt1( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - const U32 curr = (U32)(ip-base); - const U32 btLow = btMask >= curr ? 0 : curr - btMask; - U32* smallerPtr = bt + 2*(curr&btMask); + const U32 current = (U32)(ip-base); + const U32 btLow = btMask >= current ? 0 : current - btMask; + U32* smallerPtr = bt + 2*(current&btMask); U32* largerPtr = smallerPtr + 1; U32 dummy32; /* to be nullified at the end */ - /* windowLow is based on target because - * we only need positions that will be in the window at the end of the tree update. - */ - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target, cParams->windowLog); - U32 matchEndIdx = curr+8+1; + U32 const windowLow = ms->window.lowLimit; + U32 matchEndIdx = current+8+1; size_t bestLength = 8; U32 nbCompares = 1U << cParams->searchLog; #ifdef ZSTD_C_PREDICT - U32 predictedSmall = *(bt + 2*((curr-1)&btMask) + 0); - U32 predictedLarge = *(bt + 2*((curr-1)&btMask) + 1); + U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); + U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); predictedSmall += (predictedSmall>0); predictedLarge += (predictedLarge>0); #endif /* ZSTD_C_PREDICT */ - DEBUGLOG(8, "ZSTD_insertBt1 (%u)", curr); + DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current); - assert(curr <= target); assert(ip <= iend-8); /* required for h calculation */ - hashTable[h] = curr; /* Update Hash Table */ + hashTable[h] = current; /* Update Hash Table */ assert(windowLow > 0); - for (; nbCompares && (matchIndex >= windowLow); --nbCompares) { + while (nbCompares-- && (matchIndex >= windowLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < curr); + assert(matchIndex < current); #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ @@ -545,8 +508,8 @@ static U32 ZSTD_insertBt1( *smallerPtr = *largerPtr = 0; { U32 positions = 0; if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */ - assert(matchEndIdx > curr + 8); - return MAX(positions, matchEndIdx - (curr + 8)); + assert(matchEndIdx > current + 8); + return MAX(positions, matchEndIdx - (current + 8)); } } @@ -563,7 +526,7 @@ void ZSTD_updateTree_internal( idx, target, dictMode); while(idx < target) { - U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, target, mls, dictMode == ZSTD_extDict); + U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); assert(idx < (U32)(idx + forward)); idx += forward; } @@ -576,22 +539,21 @@ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) { ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict); } -FORCE_INLINE_TEMPLATE U32 -ZSTD_insertBtAndGetAllMatches ( - ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* const ip, const BYTE* const iLimit, - const ZSTD_dictMode_e dictMode, - const U32 rep[ZSTD_REP_NUM], - const U32 ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ - const U32 lengthToBeat, - const U32 mls /* template */) +FORCE_INLINE_TEMPLATE +U32 ZSTD_insertBtAndGetAllMatches ( + ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ + const U32 lengthToBeat, + U32 const mls /* template */) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); const BYTE* const base = ms->window.base; - U32 const curr = (U32)(ip-base); + U32 const current = (U32)(ip-base); U32 const hashLog = cParams->hashLog; U32 const minMatch = (mls==3) ? 3 : 4; U32* const hashTable = ms->hashTable; @@ -605,12 +567,12 @@ ZSTD_insertBtAndGetAllMatches ( U32 const dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); + U32 const btLow = (btMask >= current) ? 0 : current - btMask; + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); U32 const matchLow = windowLow ? windowLow : 1; - U32* smallerPtr = bt + 2*(curr&btMask); - U32* largerPtr = bt + 2*(curr&btMask) + 1; - U32 matchEndIdx = curr+8+1; /* farthest referenced position of any match => detects repetitive patterns */ + U32* smallerPtr = bt + 2*(current&btMask); + U32* largerPtr = bt + 2*(current&btMask) + 1; + U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */ U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; U32 nbCompares = 1U << cParams->searchLog; @@ -629,7 +591,7 @@ ZSTD_insertBtAndGetAllMatches ( U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit; size_t bestLength = lengthToBeat-1; - DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", curr); + DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current); /* check repCode */ assert(ll0 <= 1); /* necessarily 1 or 0 */ @@ -637,29 +599,26 @@ ZSTD_insertBtAndGetAllMatches ( U32 repCode; for (repCode = ll0; repCode < lastR; repCode++) { U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - U32 const repIndex = curr - repOffset; + U32 const repIndex = current - repOffset; U32 repLen = 0; - assert(curr >= dictLimit); - if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < curr-dictLimit) { /* equivalent to `curr > repIndex >= dictLimit` */ - /* We must validate the repcode offset because when we're using a dictionary the - * valid offset range shrinks when the dictionary goes out of bounds. - */ - if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) { + assert(current >= dictLimit); + if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */ + if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) { repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch; } - } else { /* repIndex < dictLimit || repIndex >= curr */ + } else { /* repIndex < dictLimit || repIndex >= current */ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ? dmsBase + repIndex - dmsIndexDelta : dictBase + repIndex; - assert(curr >= windowLow); + assert(current >= windowLow); if ( dictMode == ZSTD_extDict - && ( ((repOffset-1) /*intentional overflow*/ < curr - windowLow) /* equivalent to `curr > repIndex >= windowLow` */ + && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */ & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */) && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch; } if (dictMode == ZSTD_dictMatchState - && ( ((repOffset-1) /*intentional overflow*/ < curr - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `curr > repIndex >= dmsLowLimit` */ + && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */ & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch; @@ -669,7 +628,7 @@ ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u", repCode, ll0, repOffset, repLen); bestLength = repLen; - matches[mnum].off = REPCODE_TO_OFFBASE(repCode - ll0 + 1); /* expect value between 1 and 3 */ + matches[mnum].off = repCode - ll0; matches[mnum].len = (U32)repLen; mnum++; if ( (repLen > sufficient_len) @@ -681,7 +640,7 @@ ZSTD_insertBtAndGetAllMatches ( if ((mls == 3) /*static*/ && (bestLength < mls)) { U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip); if ((matchIndex3 >= matchLow) - & (curr - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { + & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { size_t mlen; if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) { const BYTE* const match = base + matchIndex3; @@ -696,26 +655,26 @@ ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found small match with hlog3, of length %u", (U32)mlen); bestLength = mlen; - assert(curr > matchIndex3); + assert(current > matchIndex3); assert(mnum==0); /* no prior solution */ - matches[0].off = OFFSET_TO_OFFBASE(curr - matchIndex3); + matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE; matches[0].len = (U32)mlen; mnum = 1; if ( (mlen > sufficient_len) | (ip+mlen == iLimit) ) { /* best possible length */ - ms->nextToUpdate = curr+1; /* skip insertion */ + ms->nextToUpdate = current+1; /* skip insertion */ return 1; } } } /* no dictMatchState lookup: dicts don't have a populated HC3 table */ - } /* if (mls == 3) */ + } - hashTable[h] = curr; /* Update Hash Table */ + hashTable[h] = current; /* Update Hash Table */ - for (; nbCompares && (matchIndex >= matchLow); --nbCompares) { + while (nbCompares-- && (matchIndex >= matchLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); const BYTE* match; size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(curr > matchIndex); + assert(current > matchIndex); if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) { assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */ @@ -731,20 +690,21 @@ ZSTD_insertBtAndGetAllMatches ( } if (matchLength > bestLength) { - DEBUGLOG(8, "found match of length %u at distance %u (offBase=%u)", - (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); + DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)", + (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); assert(matchEndIdx > matchIndex); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); + matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */ break; /* drop, to preserve bt consistency (miss a little bit of compression) */ - } } + } + } if (match[matchLength] < ip[matchLength]) { /* match smaller than current */ @@ -763,13 +723,12 @@ ZSTD_insertBtAndGetAllMatches ( *smallerPtr = *largerPtr = 0; - assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls); U32 dictMatchIndex = dms->hashTable[dmsH]; const U32* const dmsBt = dms->chainTable; commonLengthSmaller = commonLengthLarger = 0; - for (; nbCompares && (dictMatchIndex > dmsLowLimit); --nbCompares) { + while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) { const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dmsBase + dictMatchIndex; @@ -779,18 +738,19 @@ ZSTD_insertBtAndGetAllMatches ( if (matchLength > bestLength) { matchIndex = dictMatchIndex + dmsIndexDelta; - DEBUGLOG(8, "found dms match of length %u at distance %u (offBase=%u)", - (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); + DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)", + (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); + matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { break; /* drop, to guarantee consistency (miss a little bit of compression) */ - } } + } + } if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */ if (match[matchLength] < ip[matchLength]) { @@ -800,242 +760,71 @@ ZSTD_insertBtAndGetAllMatches ( /* match is larger than current */ commonLengthLarger = matchLength; dictMatchIndex = nextPtr[0]; - } } } /* if (dictMode == ZSTD_dictMatchState) */ + } + } + } - assert(matchEndIdx > curr+8); + assert(matchEndIdx > current+8); ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ return mnum; } -typedef U32 (*ZSTD_getAllMatchesFn)( - ZSTD_match_t*, - ZSTD_matchState_t*, - U32*, - const BYTE*, - const BYTE*, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, - U32 const lengthToBeat); - -FORCE_INLINE_TEMPLATE U32 ZSTD_btGetAllMatches_internal( - ZSTD_match_t* matches, - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* ip, - const BYTE* const iHighLimit, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, - U32 const lengthToBeat, - const ZSTD_dictMode_e dictMode, - const U32 mls) -{ - assert(BOUNDED(3, ms->cParams.minMatch, 6) == mls); - DEBUGLOG(8, "ZSTD_BtGetAllMatches(dictMode=%d, mls=%u)", (int)dictMode, mls); - if (ip < ms->window.base + ms->nextToUpdate) - return 0; /* skipped area */ - ZSTD_updateTree_internal(ms, ip, iHighLimit, mls, dictMode); - return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, mls); -} - -#define ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls) ZSTD_btGetAllMatches_##dictMode##_##mls - -#define GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, mls) \ - static U32 ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls)( \ - ZSTD_match_t* matches, \ - ZSTD_matchState_t* ms, \ - U32* nextToUpdate3, \ - const BYTE* ip, \ - const BYTE* const iHighLimit, \ - const U32 rep[ZSTD_REP_NUM], \ - U32 const ll0, \ - U32 const lengthToBeat) \ - { \ - return ZSTD_btGetAllMatches_internal( \ - matches, ms, nextToUpdate3, ip, iHighLimit, \ - rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \ - } - -#define GEN_ZSTD_BT_GET_ALL_MATCHES(dictMode) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 3) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 4) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 5) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 6) - -GEN_ZSTD_BT_GET_ALL_MATCHES(noDict) -GEN_ZSTD_BT_GET_ALL_MATCHES(extDict) -GEN_ZSTD_BT_GET_ALL_MATCHES(dictMatchState) - -#define ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMode) \ - { \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 3), \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 4), \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 5), \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 6) \ - } - -static ZSTD_getAllMatchesFn -ZSTD_selectBtGetAllMatches(ZSTD_matchState_t const* ms, ZSTD_dictMode_e const dictMode) -{ - ZSTD_getAllMatchesFn const getAllMatchesFns[3][4] = { - ZSTD_BT_GET_ALL_MATCHES_ARRAY(noDict), - ZSTD_BT_GET_ALL_MATCHES_ARRAY(extDict), - ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMatchState) - }; - U32 const mls = BOUNDED(3, ms->cParams.minMatch, 6); - assert((U32)dictMode < 3); - assert(mls - 3 < 4); - return getAllMatchesFns[(int)dictMode][mls - 3]; -} -/************************* -* LDM helper functions * -*************************/ - -/* Struct containing info needed to make decision about ldm inclusion */ -typedef struct { - rawSeqStore_t seqStore; /* External match candidates store for this block */ - U32 startPosInBlock; /* Start position of the current match candidate */ - U32 endPosInBlock; /* End position of the current match candidate */ - U32 offset; /* Offset of the match candidate */ -} ZSTD_optLdm_t; - -/* ZSTD_optLdm_skipRawSeqStoreBytes(): - * Moves forward in @rawSeqStore by @nbBytes, - * which will update the fields 'pos' and 'posInSequence'. - */ -static void ZSTD_optLdm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) +FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( + ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */ + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat) { - U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); - while (currPos && rawSeqStore->pos < rawSeqStore->size) { - rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; - if (currPos >= currSeq.litLength + currSeq.matchLength) { - currPos -= currSeq.litLength + currSeq.matchLength; - rawSeqStore->pos++; - } else { - rawSeqStore->posInSequence = currPos; - break; - } - } - if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { - rawSeqStore->posInSequence = 0; - } -} - -/* ZSTD_opt_getNextMatchAndUpdateSeqStore(): - * Calculates the beginning and end of the next match in the current block. - * Updates 'pos' and 'posInSequence' of the ldmSeqStore. - */ -static void -ZSTD_opt_getNextMatchAndUpdateSeqStore(ZSTD_optLdm_t* optLdm, U32 currPosInBlock, - U32 blockBytesRemaining) -{ - rawSeq currSeq; - U32 currBlockEndPos; - U32 literalsBytesRemaining; - U32 matchBytesRemaining; - - /* Setting match end position to MAX to ensure we never use an LDM during this block */ - if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { - optLdm->startPosInBlock = UINT_MAX; - optLdm->endPosInBlock = UINT_MAX; - return; - } - /* Calculate appropriate bytes left in matchLength and litLength - * after adjusting based on ldmSeqStore->posInSequence */ - currSeq = optLdm->seqStore.seq[optLdm->seqStore.pos]; - assert(optLdm->seqStore.posInSequence <= currSeq.litLength + currSeq.matchLength); - currBlockEndPos = currPosInBlock + blockBytesRemaining; - literalsBytesRemaining = (optLdm->seqStore.posInSequence < currSeq.litLength) ? - currSeq.litLength - (U32)optLdm->seqStore.posInSequence : - 0; - matchBytesRemaining = (literalsBytesRemaining == 0) ? - currSeq.matchLength - ((U32)optLdm->seqStore.posInSequence - currSeq.litLength) : - currSeq.matchLength; - - /* If there are more literal bytes than bytes remaining in block, no ldm is possible */ - if (literalsBytesRemaining >= blockBytesRemaining) { - optLdm->startPosInBlock = UINT_MAX; - optLdm->endPosInBlock = UINT_MAX; - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, blockBytesRemaining); - return; - } - - /* Matches may be < MINMATCH by this process. In that case, we will reject them - when we are deciding whether or not to add the ldm */ - optLdm->startPosInBlock = currPosInBlock + literalsBytesRemaining; - optLdm->endPosInBlock = optLdm->startPosInBlock + matchBytesRemaining; - optLdm->offset = currSeq.offset; - - if (optLdm->endPosInBlock > currBlockEndPos) { - /* Match ends after the block ends, we can't use the whole match */ - optLdm->endPosInBlock = currBlockEndPos; - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, currBlockEndPos - currPosInBlock); - } else { - /* Consume nb of bytes equal to size of sequence left */ - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, literalsBytesRemaining + matchBytesRemaining); + const ZSTD_compressionParameters* const cParams = &ms->cParams; + U32 const matchLengthSearch = cParams->minMatch; + DEBUGLOG(8, "ZSTD_BtGetAllMatches"); + if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ + ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode); + switch(matchLengthSearch) + { + case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3); + default : + case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4); + case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5); + case 7 : + case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6); } } -/* ZSTD_optLdm_maybeAddMatch(): - * Adds a match if it's long enough, - * based on it's 'matchStartPosInBlock' and 'matchEndPosInBlock', - * into 'matches'. Maintains the correct ordering of 'matches'. - */ -static void ZSTD_optLdm_maybeAddMatch(ZSTD_match_t* matches, U32* nbMatches, - const ZSTD_optLdm_t* optLdm, U32 currPosInBlock) -{ - U32 const posDiff = currPosInBlock - optLdm->startPosInBlock; - /* Note: ZSTD_match_t actually contains offBase and matchLength (before subtracting MINMATCH) */ - U32 const candidateMatchLength = optLdm->endPosInBlock - optLdm->startPosInBlock - posDiff; - - /* Ensure that current block position is not outside of the match */ - if (currPosInBlock < optLdm->startPosInBlock - || currPosInBlock >= optLdm->endPosInBlock - || candidateMatchLength < MINMATCH) { - return; - } - if (*nbMatches == 0 || ((candidateMatchLength > matches[*nbMatches-1].len) && *nbMatches < ZSTD_OPT_NUM)) { - U32 const candidateOffBase = OFFSET_TO_OFFBASE(optLdm->offset); - DEBUGLOG(6, "ZSTD_optLdm_maybeAddMatch(): Adding ldm candidate match (offBase: %u matchLength %u) at block position=%u", - candidateOffBase, candidateMatchLength, currPosInBlock); - matches[*nbMatches].len = candidateMatchLength; - matches[*nbMatches].off = candidateOffBase; - (*nbMatches)++; - } -} +/*-******************************* +* Optimal parser +*********************************/ +typedef struct repcodes_s { + U32 rep[3]; +} repcodes_t; -/* ZSTD_optLdm_processMatchCandidate(): - * Wrapper function to update ldm seq store and call ldm functions as necessary. - */ -static void -ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm, - ZSTD_match_t* matches, U32* nbMatches, - U32 currPosInBlock, U32 remainingBytes) +static repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) { - if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { - return; - } - - if (currPosInBlock >= optLdm->endPosInBlock) { - if (currPosInBlock > optLdm->endPosInBlock) { - /* The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily - * at the end of a match from the ldm seq store, and will often be some bytes - * over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots" - */ - U32 const posOvershoot = currPosInBlock - optLdm->endPosInBlock; - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, posOvershoot); + repcodes_t newReps; + if (offset >= ZSTD_REP_NUM) { /* full offset */ + newReps.rep[2] = rep[1]; + newReps.rep[1] = rep[0]; + newReps.rep[0] = offset - ZSTD_REP_MOVE; + } else { /* repcode */ + U32 const repCode = offset + ll0; + if (repCode > 0) { /* note : if repCode==0, no change */ + U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; + newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2]; + newReps.rep[1] = rep[0]; + newReps.rep[0] = currentOffset; + } else { /* repCode == 0 */ + memcpy(&newReps, rep, sizeof(newReps)); } - ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes); } - ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock); + return newReps; } -/*-******************************* -* Optimal parser -*********************************/ - static U32 ZSTD_totalLen(ZSTD_optimal_t sol) { return sol.litlen + sol.mlen; @@ -1050,7 +839,7 @@ listStats(const U32* table, int lastEltID) int enb; for (enb=0; enb < nbElts; enb++) { (void)table; - /* RAWLOG(2, "%3i:%3i, ", enb, table[enb]); */ + //RAWLOG(2, "%3i:%3i, ", enb, table[enb]); RAWLOG(2, "%4i,", table[enb]); } RAWLOG(2, " \n"); @@ -1076,8 +865,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, const BYTE* const prefixStart = base + ms->window.dictLimit; const ZSTD_compressionParameters* const cParams = &ms->cParams; - ZSTD_getAllMatchesFn getAllMatches = ZSTD_selectBtGetAllMatches(ms, dictMode); - U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4; U32 nextToUpdate3 = ms->nextToUpdate; @@ -1085,13 +872,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_match_t* const matches = optStatePtr->matchTable; ZSTD_optimal_t lastSequence; - ZSTD_optLdm_t optLdm; - - ZSTD_memset(&lastSequence, 0, sizeof(ZSTD_optimal_t)); - - optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore; - optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0; - ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip)); /* init */ DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u", @@ -1107,32 +887,25 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* find first match */ { U32 const litlen = (U32)(ip - anchor); U32 const ll0 = !litlen; - U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch); - ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, - (U32)(ip-istart), (U32)(iend - ip)); + U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch); if (!nbMatches) { ip++; continue; } /* initialize opt[0] */ { U32 i ; for (i=0; i immediate encoding */ { U32 const maxML = matches[nbMatches-1].len; - U32 const maxOffBase = matches[nbMatches-1].off; - DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffBase=%u at cPos=%u => start new series", - nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart)); + U32 const maxOffset = matches[nbMatches-1].off; + DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series", + nbMatches, maxML, maxOffset, (U32)(ip-prefixStart)); if (maxML > sufficient_len) { lastSequence.litlen = litlen; lastSequence.mlen = maxML; - lastSequence.off = maxOffBase; + lastSequence.off = maxOffset; DEBUGLOG(6, "large match (%u>%u), immediate encoding", maxML, sufficient_len); cur = 0; @@ -1141,25 +914,27 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, } } /* set prices for first matches starting position == 0 */ - assert(opt[0].price >= 0); - { U32 const literalsPrice = (U32)opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); + { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); U32 pos; U32 matchNb; for (pos = 1; pos < minMatch; pos++) { opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */ } for (matchNb = 0; matchNb < nbMatches; matchNb++) { - U32 const offBase = matches[matchNb].off; + U32 const offset = matches[matchNb].off; U32 const end = matches[matchNb].len; + repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0); for ( ; pos <= end ; pos++ ) { - U32 const matchPrice = ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel); + U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel); U32 const sequencePrice = literalsPrice + matchPrice; DEBUGLOG(7, "rPos:%u => set initial price : %.2f", - pos, ZSTD_fCost((int)sequencePrice)); + pos, ZSTD_fCost(sequencePrice)); opt[pos].mlen = pos; - opt[pos].off = offBase; + opt[pos].off = offset; opt[pos].litlen = litlen; - opt[pos].price = (int)sequencePrice; + opt[pos].price = sequencePrice; + ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory)); + memcpy(opt[pos].rep, &repHistory, sizeof(repHistory)); } } last_pos = pos-1; } @@ -1174,9 +949,9 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* Fix current position with one literal if cheaper */ { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1; int const price = opt[cur-1].price - + (int)ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) - + (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) - - (int)ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); + + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) + + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) + - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); assert(price < 1000000000); /* overflow check */ if (price <= opt[cur].price) { DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)", @@ -1186,6 +961,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, opt[cur].off = 0; opt[cur].litlen = litlen; opt[cur].price = price; + memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep)); } else { DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)", inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), @@ -1193,21 +969,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, } } - /* Set the repcodes of the current position. We must do it here - * because we rely on the repcodes of the 2nd to last sequence being - * correct to set the next chunks repcodes during the backward - * traversal. - */ - ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t)); - assert(cur >= opt[cur].mlen); - if (opt[cur].mlen != 0) { - U32 const prev = cur - opt[cur].mlen; - repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0); - ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t)); - } else { - ZSTD_memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t)); - } - /* last match must start at a minimum distance of 8 from oend */ if (inr > ilimit) continue; @@ -1219,17 +980,12 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */ } - assert(opt[cur].price >= 0); { U32 const ll0 = (opt[cur].mlen != 0); U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; - U32 const previousPrice = (U32)opt[cur].price; + U32 const previousPrice = opt[cur].price; U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel); - U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch); + U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch); U32 matchNb; - - ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, - (U32)(inr-istart), (U32)(iend-inr)); - if (!nbMatches) { DEBUGLOG(7, "rPos:%u : no match found", cur); continue; @@ -1253,16 +1009,17 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* set prices using matches found at position == cur */ for (matchNb = 0; matchNb < nbMatches; matchNb++) { U32 const offset = matches[matchNb].off; + repcodes_t const repHistory = ZSTD_updateRep(opt[cur].rep, offset, ll0); U32 const lastML = matches[matchNb].len; U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch; U32 mlen; - DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u", + DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u", matchNb, matches[matchNb].off, lastML, litlen); for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */ U32 const pos = cur + mlen; - int const price = (int)basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); + int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); if ((pos > last_pos) || (price < opt[pos].price)) { DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)", @@ -1272,6 +1029,8 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, opt[pos].off = offset; opt[pos].litlen = litlen; opt[pos].price = price; + ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory)); + memcpy(opt[pos].rep, &repHistory, sizeof(repHistory)); } else { DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)", pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); @@ -1287,17 +1046,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ assert(opt[0].mlen == 0); - /* Set the next chunk's repcodes based on the repcodes of the beginning - * of the last match, and the last sequence. This avoids us having to - * update them while traversing the sequences. - */ - if (lastSequence.mlen != 0) { - repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0); - ZSTD_memcpy(rep, &reps, sizeof(reps)); - } else { - ZSTD_memcpy(rep, opt[cur].rep, sizeof(repcodes_t)); - } - { U32 const storeEnd = cur + 1; U32 storeStart = storeEnd; U32 seqPos = cur; @@ -1323,7 +1071,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, for (storePos=storeStart; storePos <= storeEnd; storePos++) { U32 const llen = opt[storePos].litlen; U32 const mlen = opt[storePos].mlen; - U32 const offBase = opt[storePos].off; + U32 const offCode = opt[storePos].off; U32 const advance = llen + mlen; DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u", anchor - istart, (unsigned)llen, (unsigned)mlen); @@ -1334,49 +1082,72 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, continue; /* will finish */ } + /* repcodes update : like ZSTD_updateRep(), but update in place */ + if (offCode >= ZSTD_REP_NUM) { /* full offset */ + rep[2] = rep[1]; + rep[1] = rep[0]; + rep[0] = offCode - ZSTD_REP_MOVE; + } else { /* repcode */ + U32 const repCode = offCode + (llen==0); + if (repCode) { /* note : if repCode==0, no change */ + U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; + if (repCode >= 2) rep[2] = rep[1]; + rep[1] = rep[0]; + rep[0] = currentOffset; + } } + assert(anchor + llen <= iend); - ZSTD_updateStats(optStatePtr, llen, anchor, offBase, mlen); - ZSTD_storeSeq(seqStore, llen, anchor, iend, offBase, mlen); + ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen); + ZSTD_storeSeq(seqStore, llen, anchor, iend, offCode, mlen-MINMATCH); anchor += advance; ip = anchor; } } ZSTD_setBasePrices(optStatePtr, optLevel); } + } /* while (ip < ilimit) */ /* Return the last literals size */ return (size_t)(iend - anchor); } -static size_t ZSTD_compressBlock_opt0( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) -{ - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /* optLevel */, dictMode); -} - -static size_t ZSTD_compressBlock_opt2( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) -{ - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /* optLevel */, dictMode); -} size_t ZSTD_compressBlock_btopt( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btopt"); - return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_noDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict); } +/* used in 2-pass strategy */ +static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus) +{ + U32 s, sum=0; + assert(ZSTD_FREQ_DIV+bonus >= 0); + for (s=0; slitSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0); + optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0); + optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0); + optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0); +} /* ZSTD_initStats_ultra(): * make a first compression pass, just to seed stats with more accurate starting values. * only works on first block, with no dictionary and no ldm. - * this function cannot error out, its narrow contract must be respected. + * this function cannot error, hence its contract must be respected. */ static void ZSTD_initStats_ultra(ZSTD_matchState_t* ms, @@ -1385,7 +1156,7 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, const void* src, size_t srcSize) { U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */ - ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep)); + memcpy(tmpRep, rep, sizeof(tmpRep)); DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize); assert(ms->opt.litLengthSum == 0); /* first block */ @@ -1393,15 +1164,17 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */ assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */ - ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict); /* generate stats into ms->opt*/ + ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/ - /* invalidate first scan from history, only keep entropy stats */ + /* invalidate first scan from history */ ZSTD_resetSeqStore(seqStore); ms->window.base -= srcSize; ms->window.dictLimit += (U32)srcSize; ms->window.lowLimit = ms->window.dictLimit; ms->nextToUpdate = ms->window.dictLimit; + /* re-inforce weight of collected statistics */ + ZSTD_upscaleStats(&ms->opt); } size_t ZSTD_compressBlock_btultra( @@ -1409,67 +1182,65 @@ size_t ZSTD_compressBlock_btultra( const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize); - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); } size_t ZSTD_compressBlock_btultra2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - U32 const curr = (U32)((const BYTE*)src - ms->window.base); + U32 const current = (U32)((const BYTE*)src - ms->window.base); DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize); - /* 2-passes strategy: + /* 2-pass strategy: * this strategy makes a first pass over first block to collect statistics - * in order to seed next round's statistics with it. - * After 1st pass, function forgets history, and starts a new block. + * and seed next round's statistics with it. + * After 1st pass, function forgets everything, and starts a new block. * Consequently, this can only work if no data has been previously loaded in tables, * aka, no dictionary, no prefix, no ldm preprocessing. * The compression ratio gain is generally small (~0.5% on first block), - ** the cost is 2x cpu time on first block. */ + * the cost is 2x cpu time on first block. */ assert(srcSize <= ZSTD_BLOCKSIZE_MAX); if ( (ms->opt.litLengthSum==0) /* first block */ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */ - && (curr == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ - && (srcSize > ZSTD_PREDEF_THRESHOLD) /* input large enough to not employ default stats */ + && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ + && (srcSize > ZSTD_PREDEF_THRESHOLD) ) { ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize); } - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); } size_t ZSTD_compressBlock_btopt_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState); } size_t ZSTD_compressBlock_btultra_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState); } size_t ZSTD_compressBlock_btopt_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_extDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict); } size_t ZSTD_compressBlock_btultra_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_extDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict); } /* note : no btultra2 variant for extDict nor dictMatchState, * because btultra2 is not meant to work with dictionaries * and is only specific for the first block (no prefix) */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_opt.h b/vendor/github.com/DataDog/zstd/zstd_opt.h index 3eb02f57..094f7476 100644 --- a/vendor/github.com/DataDog/zstd/zstd_opt.h +++ b/vendor/github.com/DataDog/zstd/zstd_opt.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -55,5 +54,3 @@ size_t ZSTD_compressBlock_btultra_extDict( #endif #endif /* ZSTD_OPT_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_stream.go b/vendor/github.com/DataDog/zstd/zstd_stream.go index e3b6c099..2df078c3 100644 --- a/vendor/github.com/DataDog/zstd/zstd_stream.go +++ b/vendor/github.com/DataDog/zstd/zstd_stream.go @@ -1,6 +1,8 @@ package zstd /* +#define ZSTD_STATIC_LINKING_ONLY +#include "stdint.h" // for uintptr_t #include "zstd.h" typedef struct compressStream2_result_s { @@ -9,10 +11,9 @@ typedef struct compressStream2_result_s { size_t bytes_written; } compressStream2_result; -static void ZSTD_compressStream2_wrapper(compressStream2_result* result, ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, const void* src, size_t srcSize) { - ZSTD_outBuffer outBuffer = { dst, maxDstSize, 0 }; - ZSTD_inBuffer inBuffer = { src, srcSize, 0 }; +static void ZSTD_compressStream2_wrapper(compressStream2_result* result, ZSTD_CCtx* ctx, uintptr_t dst, size_t maxDstSize, const uintptr_t src, size_t srcSize) { + ZSTD_outBuffer outBuffer = { (void*)dst, maxDstSize, 0 }; + ZSTD_inBuffer inBuffer = { (void*)src, srcSize, 0 }; size_t retCode = ZSTD_compressStream2(ctx, &outBuffer, &inBuffer, ZSTD_e_continue); result->return_code = retCode; @@ -20,21 +21,9 @@ static void ZSTD_compressStream2_wrapper(compressStream2_result* result, ZSTD_CC result->bytes_written = outBuffer.pos; } -static void ZSTD_compressStream2_flush(compressStream2_result* result, ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, const void* src, size_t srcSize) { - ZSTD_outBuffer outBuffer = { dst, maxDstSize, 0 }; - ZSTD_inBuffer inBuffer = { src, srcSize, 0 }; - size_t retCode = ZSTD_compressStream2(ctx, &outBuffer, &inBuffer, ZSTD_e_flush); - - result->return_code = retCode; - result->bytes_consumed = inBuffer.pos; - result->bytes_written = outBuffer.pos; -} - -static void ZSTD_compressStream2_finish(compressStream2_result* result, ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, const void* src, size_t srcSize) { - ZSTD_outBuffer outBuffer = { dst, maxDstSize, 0 }; - ZSTD_inBuffer inBuffer = { src, srcSize, 0 }; +static void ZSTD_compressStream2_finish(compressStream2_result* result, ZSTD_CCtx* ctx, uintptr_t dst, size_t maxDstSize, const uintptr_t src, size_t srcSize) { + ZSTD_outBuffer outBuffer = { (void*)dst, maxDstSize, 0 }; + ZSTD_inBuffer inBuffer = { (void*)src, srcSize, 0 }; size_t retCode = ZSTD_compressStream2(ctx, &outBuffer, &inBuffer, ZSTD_e_end); result->return_code = retCode; @@ -49,10 +38,9 @@ typedef struct decompressStream2_result_s { size_t bytes_written; } decompressStream2_result; -static void ZSTD_decompressStream_wrapper(decompressStream2_result* result, ZSTD_DCtx* ctx, - void* dst, size_t maxDstSize, const void* src, size_t srcSize) { - ZSTD_outBuffer outBuffer = { dst, maxDstSize, 0 }; - ZSTD_inBuffer inBuffer = { src, srcSize, 0 }; +static void ZSTD_decompressStream_wrapper(decompressStream2_result* result, ZSTD_DCtx* ctx, uintptr_t dst, size_t maxDstSize, const uintptr_t src, size_t srcSize) { + ZSTD_outBuffer outBuffer = { (void*)dst, maxDstSize, 0 }; + ZSTD_inBuffer inBuffer = { (void*)src, srcSize, 0 }; size_t retCode = ZSTD_decompressStream(ctx, &outBuffer, &inBuffer); result->return_code = retCode; @@ -72,7 +60,6 @@ import ( var errShortRead = errors.New("short read") var errReaderClosed = errors.New("Reader is closed") -var ErrNoParallelSupport = errors.New("No parallel support") // Writer is an io.WriteCloser that zstd-compresses its input. type Writer struct { @@ -168,19 +155,20 @@ func (w *Writer) Write(p []byte) (int, error) { srcData = w.srcBuffer } - if len(srcData) == 0 { - // this is technically unnecessary: srcData is p or w.srcBuffer, and len() > 0 checked above - // but this ensures the code can change without dereferencing an srcData[0] - return 0, nil + srcPtr := C.uintptr_t(uintptr(0)) // Do not point anywhere, if src is empty + if len(srcData) > 0 { + srcPtr = C.uintptr_t(uintptr(unsafe.Pointer(&srcData[0]))) } + C.ZSTD_compressStream2_wrapper( w.resultBuffer, w.ctx, - unsafe.Pointer(&w.dstBuffer[0]), + C.uintptr_t(uintptr(unsafe.Pointer(&w.dstBuffer[0]))), C.size_t(len(w.dstBuffer)), - unsafe.Pointer(&srcData[0]), + srcPtr, C.size_t(len(srcData)), ) + runtime.KeepAlive(p) // Ensure p is kept until here so pointer doesn't disappear during C call ret := int(w.resultBuffer.return_code) if err := getError(ret); err != nil { return 0, err @@ -215,49 +203,6 @@ func (w *Writer) Write(p []byte) (int, error) { return len(p), err } -// Flush writes any unwritten data to the underlying io.Writer. -func (w *Writer) Flush() error { - if w.firstError != nil { - return w.firstError - } - - ret := 1 // So we loop at least once - for ret > 0 { - var srcPtr *byte // Do not point anywhere, if src is empty - if len(w.srcBuffer) > 0 { - srcPtr = &w.srcBuffer[0] - } - - C.ZSTD_compressStream2_flush( - w.resultBuffer, - w.ctx, - unsafe.Pointer(&w.dstBuffer[0]), - C.size_t(len(w.dstBuffer)), - unsafe.Pointer(srcPtr), - C.size_t(len(w.srcBuffer)), - ) - ret = int(w.resultBuffer.return_code) - if err := getError(ret); err != nil { - return err - } - w.srcBuffer = w.srcBuffer[w.resultBuffer.bytes_consumed:] - written := int(w.resultBuffer.bytes_written) - _, err := w.underlyingWriter.Write(w.dstBuffer[:written]) - if err != nil { - return err - } - - if ret > 0 { // We have a hint if we need to resize the dstBuffer - w.dstBuffer = w.dstBuffer[:cap(w.dstBuffer)] - if len(w.dstBuffer) < ret { - w.dstBuffer = make([]byte, ret) - } - } - } - - return nil -} - // Close closes the Writer, flushing any unwritten data to the underlying // io.Writer and freeing objects, but does not close the underlying io.Writer. func (w *Writer) Close() error { @@ -267,17 +212,17 @@ func (w *Writer) Close() error { ret := 1 // So we loop at least once for ret > 0 { - var srcPtr *byte // Do not point anywhere, if src is empty + srcPtr := C.uintptr_t(uintptr(0)) // Do not point anywhere, if src is empty if len(w.srcBuffer) > 0 { - srcPtr = &w.srcBuffer[0] + srcPtr = C.uintptr_t(uintptr(unsafe.Pointer(&w.srcBuffer[0]))) } C.ZSTD_compressStream2_finish( w.resultBuffer, w.ctx, - unsafe.Pointer(&w.dstBuffer[0]), + C.uintptr_t(uintptr(unsafe.Pointer(&w.dstBuffer[0]))), C.size_t(len(w.dstBuffer)), - unsafe.Pointer(srcPtr), + srcPtr, C.size_t(len(w.srcBuffer)), ) ret = int(w.resultBuffer.return_code) @@ -286,11 +231,7 @@ func (w *Writer) Close() error { } w.srcBuffer = w.srcBuffer[w.resultBuffer.bytes_consumed:] written := int(w.resultBuffer.bytes_written) - _, err := w.underlyingWriter.Write(w.dstBuffer[:written]) - if err != nil { - C.ZSTD_freeCStream(w.ctx) - return err - } + w.underlyingWriter.Write(w.dstBuffer[:written]) if ret > 0 { // We have a hint if we need to resize the dstBuffer w.dstBuffer = w.dstBuffer[:cap(w.dstBuffer)] @@ -303,28 +244,6 @@ func (w *Writer) Close() error { return getError(int(C.ZSTD_freeCStream(w.ctx))) } -// Set the number of workers to run the compression in parallel using multiple threads -// If > 1, the Write() call will become asynchronous. This means data will be buffered until processed. -// If you call Write() too fast, you might incur a memory buffer up to as large as your input. -// Consider calling Flush() periodically if you need to compress a very large file that would not fit all in memory. -// By default only one worker is used. -func (w *Writer) SetNbWorkers(n int) error { - if w.firstError != nil { - return w.firstError - } - if err := getError(int(C.ZSTD_CCtx_setParameter(w.ctx, C.ZSTD_c_nbWorkers, C.int(n)))); err != nil { - w.firstError = err - // First error case, a shared libary is used, and the library was compiled without parallel support - if err.Error() == "Unsupported parameter" { - return ErrNoParallelSupport - } else { - // This could happen if a very large number is passed in, and possibly zstd refuse to create as many threads, or the OS fails to do so - return err - } - } - return nil -} - // cSize is the recommended size of reader.compressionBuffer. This func and // invocation allow for a one-time check for validity. var cSize = func() int { @@ -444,86 +363,49 @@ func (r *reader) Read(p []byte) (int, error) { return 0, r.firstError } - if len(p) == 0 { - return 0, nil + // If we already have enough bytes, return + if r.decompSize-r.decompOff >= len(p) { + copy(p, r.decompressionBuffer[r.decompOff:]) + r.decompOff += len(p) + return len(p), nil } - // If we already have some uncompressed bytes, return without blocking - if r.decompSize > r.decompOff { - if r.decompSize-r.decompOff > len(p) { - copy(p, r.decompressionBuffer[r.decompOff:]) - r.decompOff += len(p) - return len(p), nil - } - // From https://golang.org/pkg/io/#Reader - // > Read conventionally returns what is available instead of waiting for more. - copy(p, r.decompressionBuffer[r.decompOff:r.decompSize]) - got := r.decompSize - r.decompOff - r.decompOff = r.decompSize - return got, nil - } - - // Repeatedly read from the underlying reader until we get - // at least one zstd block, so that we don't block if the - // other end has flushed a block. - for { - // - If the last decompression didn't entirely fill the decompression buffer, - // zstd flushed all it could, and needs new data. In that case, do 1 Read. - // - If the last decompression did entirely fill the decompression buffer, - // it might have needed more room to decompress the input. In that case, - // don't do any unnecessary Read that might block. - needsData := r.decompSize < len(r.decompressionBuffer) - - var src []byte - if !needsData { - src = r.compressionBuffer[:r.compressionLeft] - } else { - src = r.compressionBuffer - var n int - var err error - // Read until data arrives or an error occurs. - for n == 0 && err == nil { - n, err = r.underlyingReader.Read(src[r.compressionLeft:]) - } - if err != nil && err != io.EOF { // Handle underlying reader errors first - return 0, fmt.Errorf("failed to read from underlying reader: %s", err) - } - if n == 0 { - // Ideally, we'd return with ErrUnexpectedEOF in all cases where the stream was unexpectedly EOF'd - // during a block or frame, i.e. when there are incomplete, pending compression data. - // However, it's hard to detect those cases with zstd. Namely, there is no way to know the size of - // the current buffered compression data in the zstd stream internal buffers. - // Best effort: throw ErrUnexpectedEOF if we still have some pending buffered compression data that - // zstd doesn't want to accept. - // If we don't have any buffered compression data but zstd still has some in its internal buffers, - // we will return with EOF instead. - if r.compressionLeft > 0 { - return 0, io.ErrUnexpectedEOF - } - return 0, io.EOF - } - src = src[:r.compressionLeft+n] + copy(p, r.decompressionBuffer[r.decompOff:r.decompSize]) + got := r.decompSize - r.decompOff + r.decompSize = 0 + r.decompOff = 0 + + for got < len(p) { + // Populate src + src := r.compressionBuffer + reader := r.underlyingReader + n, err := TryReadFull(reader, src[r.compressionLeft:]) + if err != nil && err != errShortRead { // Handle underlying reader errors first + return 0, fmt.Errorf("failed to read from underlying reader: %s", err) + } else if n == 0 && r.compressionLeft == 0 { + return got, io.EOF } + src = src[:r.compressionLeft+n] // C code - var srcPtr *byte // Do not point anywhere, if src is empty + srcPtr := C.uintptr_t(uintptr(0)) // Do not point anywhere, if src is empty if len(src) > 0 { - srcPtr = &src[0] + srcPtr = C.uintptr_t(uintptr(unsafe.Pointer(&src[0]))) } C.ZSTD_decompressStream_wrapper( r.resultBuffer, r.ctx, - unsafe.Pointer(&r.decompressionBuffer[0]), + C.uintptr_t(uintptr(unsafe.Pointer(&r.decompressionBuffer[0]))), C.size_t(len(r.decompressionBuffer)), - unsafe.Pointer(srcPtr), + srcPtr, C.size_t(len(src)), ) retCode := int(r.resultBuffer.return_code) - // Keep src here even though we reuse later, the code might be deleted at some point + // Keep src here eventhough we reuse later, the code might be deleted at some point runtime.KeepAlive(src) - if err := getError(retCode); err != nil { + if err = getError(retCode); err != nil { return 0, fmt.Errorf("failed to decompress: %s", err) } @@ -533,9 +415,10 @@ func (r *reader) Read(p []byte) (int, error) { left := src[bytesConsumed:] copy(r.compressionBuffer, left) } - r.compressionLeft = len(src) - bytesConsumed + r.compressionLeft = len(src) - int(bytesConsumed) r.decompSize = int(r.resultBuffer.bytes_written) - r.decompOff = copy(p, r.decompressionBuffer[:r.decompSize]) + r.decompOff = copy(p[got:], r.decompressionBuffer[:r.decompSize]) + got += r.decompOff // Resize buffers nsize := retCode // Hint for next src buffer size @@ -547,9 +430,25 @@ func (r *reader) Read(p []byte) (int, error) { nsize = r.compressionLeft } r.compressionBuffer = resize(r.compressionBuffer, nsize) + } + return got, nil +} - if r.decompOff > 0 { - return r.decompOff, nil - } +// TryReadFull reads buffer just as ReadFull does +// Here we expect that buffer may end and we do not return ErrUnexpectedEOF as ReadAtLeast does. +// We return errShortRead instead to distinguish short reads and failures. +// We cannot use ReadFull/ReadAtLeast because it masks Reader errors, such as network failures +// and causes panic instead of error. +func TryReadFull(r io.Reader, buf []byte) (n int, err error) { + for n < len(buf) && err == nil { + var nn int + nn, err = r.Read(buf[n:]) + n += nn + } + if n == len(buf) && err == io.EOF { + err = nil // EOF at the end is somewhat expected + } else if err == io.EOF { + err = errShortRead } + return } diff --git a/vendor/github.com/DataDog/zstd/zstd_trace.h b/vendor/github.com/DataDog/zstd/zstd_trace.h deleted file mode 100644 index 168ace45..00000000 --- a/vendor/github.com/DataDog/zstd/zstd_trace.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef USE_EXTERNAL_ZSTD -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_TRACE_H -#define ZSTD_TRACE_H - -#if defined (__cplusplus) -extern "C" { -#endif - -#include - -/* weak symbol support - * For now, enable conservatively: - * - Only GNUC - * - Only ELF - * - Only x86-64, i386 and aarch64 - * Also, explicitly disable on platforms known not to work so they aren't - * forgotten in the future. - */ -#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ - defined(__GNUC__) && defined(__ELF__) && \ - (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) || defined(__aarch64__)) && \ - !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ - !defined(__CYGWIN__) && !defined(_AIX) -# define ZSTD_HAVE_WEAK_SYMBOLS 1 -#else -# define ZSTD_HAVE_WEAK_SYMBOLS 0 -#endif -#if ZSTD_HAVE_WEAK_SYMBOLS -# define ZSTD_WEAK_ATTR __attribute__((__weak__)) -#else -# define ZSTD_WEAK_ATTR -#endif - -/* Only enable tracing when weak symbols are available. */ -#ifndef ZSTD_TRACE -# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS -#endif - -#if ZSTD_TRACE - -struct ZSTD_CCtx_s; -struct ZSTD_DCtx_s; -struct ZSTD_CCtx_params_s; - -typedef struct { - /** - * ZSTD_VERSION_NUMBER - * - * This is guaranteed to be the first member of ZSTD_trace. - * Otherwise, this struct is not stable between versions. If - * the version number does not match your expectation, you - * should not interpret the rest of the struct. - */ - unsigned version; - /** - * Non-zero if streaming (de)compression is used. - */ - unsigned streaming; - /** - * The dictionary ID. - */ - unsigned dictionaryID; - /** - * Is the dictionary cold? - * Only set on decompression. - */ - unsigned dictionaryIsCold; - /** - * The dictionary size or zero if no dictionary. - */ - size_t dictionarySize; - /** - * The uncompressed size of the data. - */ - size_t uncompressedSize; - /** - * The compressed size of the data. - */ - size_t compressedSize; - /** - * The fully resolved CCtx parameters (NULL on decompression). - */ - struct ZSTD_CCtx_params_s const* params; - /** - * The ZSTD_CCtx pointer (NULL on decompression). - */ - struct ZSTD_CCtx_s const* cctx; - /** - * The ZSTD_DCtx pointer (NULL on compression). - */ - struct ZSTD_DCtx_s const* dctx; -} ZSTD_Trace; - -/** - * A tracing context. It must be 0 when tracing is disabled. - * Otherwise, any non-zero value returned by a tracing begin() - * function is presented to any subsequent calls to end(). - * - * Any non-zero value is treated as tracing is enabled and not - * interpreted by the library. - * - * Two possible uses are: - * * A timestamp for when the begin() function was called. - * * A unique key identifying the (de)compression, like the - * address of the [dc]ctx pointer if you need to track - * more information than just a timestamp. - */ -typedef unsigned long long ZSTD_TraceCtx; - -/** - * Trace the beginning of a compression call. - * @param cctx The dctx pointer for the compression. - * It can be used as a key to map begin() to end(). - * @returns Non-zero if tracing is enabled. The return value is - * passed to ZSTD_trace_compress_end(). - */ -ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( - struct ZSTD_CCtx_s const* cctx); - -/** - * Trace the end of a compression call. - * @param ctx The return value of ZSTD_trace_compress_begin(). - * @param trace The zstd tracing info. - */ -ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( - ZSTD_TraceCtx ctx, - ZSTD_Trace const* trace); - -/** - * Trace the beginning of a decompression call. - * @param dctx The dctx pointer for the decompression. - * It can be used as a key to map begin() to end(). - * @returns Non-zero if tracing is enabled. The return value is - * passed to ZSTD_trace_compress_end(). - */ -ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( - struct ZSTD_DCtx_s const* dctx); - -/** - * Trace the end of a decompression call. - * @param ctx The return value of ZSTD_trace_decompress_begin(). - * @param trace The zstd tracing info. - */ -ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( - ZSTD_TraceCtx ctx, - ZSTD_Trace const* trace); - -#endif /* ZSTD_TRACE */ - -#if defined (__cplusplus) -} -#endif - -#endif /* ZSTD_TRACE_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v01.c b/vendor/github.com/DataDog/zstd/zstd_v01.c index cee369d8..8112527f 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v01.c +++ b/vendor/github.com/DataDog/zstd/zstd_v01.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -191,6 +190,28 @@ typedef signed long long S64; /**************************************************************** * Memory I/O *****************************************************************/ +/* FSE_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets generating assembly depending on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef FSE_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define FSE_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define FSE_FORCE_MEMORY_ACCESS 1 +# endif +#endif + static unsigned FSE_32bits(void) { @@ -203,6 +224,24 @@ static unsigned FSE_isLittleEndian(void) return one.c[0]; } +#if defined(FSE_FORCE_MEMORY_ACCESS) && (FSE_FORCE_MEMORY_ACCESS==2) + +static U16 FSE_read16(const void* memPtr) { return *(const U16*) memPtr; } +static U32 FSE_read32(const void* memPtr) { return *(const U32*) memPtr; } +static U64 FSE_read64(const void* memPtr) { return *(const U64*) memPtr; } + +#elif defined(FSE_FORCE_MEMORY_ACCESS) && (FSE_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign; + +static U16 FSE_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +static U32 FSE_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +static U64 FSE_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +#else + static U16 FSE_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -218,6 +257,8 @@ static U64 FSE_read64(const void* memPtr) U64 val; memcpy(&val, memPtr, sizeof(val)); return val; } +#endif // FSE_FORCE_MEMORY_ACCESS + static U16 FSE_readLE16(const void* memPtr) { if (FSE_isLittleEndian()) @@ -302,7 +343,8 @@ FORCE_INLINE unsigned FSE_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (GCC_VERSION >= 304) /* GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -1036,7 +1078,7 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */ BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; BYTE* const omax = op + maxDstSize; - BYTE* const olimit = maxDstSize < 15 ? op : omax-15; + BYTE* const olimit = omax-15; const void* ptr = DTable; const HUF_DElt* const dt = (const HUF_DElt*)(ptr)+1; @@ -1050,7 +1092,7 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */ const size_t length1 = FSE_readLE16(jumpTable); const size_t length2 = FSE_readLE16(jumpTable+1); const size_t length3 = FSE_readLE16(jumpTable+2); - const size_t length4 = cSrcSize - 6 - length1 - length2 - length3; /* check coherency !! */ + const size_t length4 = cSrcSize - 6 - length1 - length2 - length3; // check coherency !! const char* const start1 = (const char*)(cSrc) + 6; const char* const start2 = start1 + length1; const char* const start3 = start2 + length2; @@ -1108,11 +1150,11 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */ /* tail */ { - /* bitTail = bitD1; */ /* *much* slower : -20% !??! */ + // bitTail = bitD1; // *much* slower : -20% !??! FSE_DStream_t bitTail; bitTail.ptr = bitD1.ptr; bitTail.bitsConsumed = bitD1.bitsConsumed; - bitTail.bitContainer = bitD1.bitContainer; /* required in case of FSE_DStream_endOfBuffer */ + bitTail.bitContainer = bitD1.bitContainer; // required in case of FSE_DStream_endOfBuffer bitTail.start = start1; for ( ; (FSE_reloadDStream(&bitTail) < FSE_DStream_completed) && (op= 199901L /* C99 */ -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -1445,9 +1483,7 @@ static size_t ZSTDv01_getcBlockSize(const void* src, size_t srcSize, blockProper static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - if (srcSize > 0) { - memcpy(dst, src, srcSize); - } + memcpy(dst, src, srcSize); return srcSize; } @@ -1466,7 +1502,7 @@ static size_t ZSTD_decompressLiterals(void* ctx, if (srcSize <= 3) return ERROR(corruption_detected); litSize = ip[1] + (ip[0]<<8); - litSize += ((ip[-3] >> 3) & 7) << 16; /* mmmmh.... */ + litSize += ((ip[-3] >> 3) & 7) << 16; // mmmmh.... op = oend - litSize; (void)ctx; @@ -1505,9 +1541,7 @@ static size_t ZSTDv01_decodeLiteralsBlock(void* ctx, size_t rleSize = litbp.origSize; if (rleSize>maxDstSize) return ERROR(dstSize_tooSmall); if (!srcSize) return ERROR(srcSize_wrong); - if (rleSize > 0) { - memset(oend - rleSize, *ip, rleSize); - } + memset(oend - rleSize, *ip, rleSize); *litStart = oend - rleSize; *litSize = rleSize; ip++; @@ -1721,26 +1755,20 @@ static size_t ZSTD_execSequence(BYTE* op, static const int dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */ static const int dec64table[] = {8, 8, 8, 7, 8, 9,10,11}; /* subtracted */ const BYTE* const ostart = op; - BYTE* const oLitEnd = op + sequence.litLength; const size_t litLength = sequence.litLength; BYTE* const endMatch = op + litLength + sequence.matchLength; /* risk : address space overflow (32-bits) */ const BYTE* const litEnd = *litPtr + litLength; - /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (sequence.offset > (U32)(oLitEnd - base)) return ERROR(corruption_detected); - + /* check */ if (endMatch > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (litEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ - if (sequence.matchLength > (size_t)(*litPtr-op)) return ERROR(dstSize_tooSmall); /* overwrite literal segment */ + if (litEnd > litLimit) return ERROR(corruption_detected); + if (sequence.matchLength > (size_t)(*litPtr-op)) return ERROR(dstSize_tooSmall); /* overwrite literal segment */ /* copy Literals */ - ZSTD_memmove(op, *litPtr, sequence.litLength); /* note : v0.1 seems to allow scenarios where output or input are close to end of buffer */ - + if (((size_t)(*litPtr - op) < 8) || ((size_t)(oend-litEnd) < 8) || (op+litLength > oend-8)) + memmove(op, *litPtr, litLength); /* overwrite risk */ + else + ZSTD_wildcopy(op, *litPtr, litLength); op += litLength; *litPtr = litEnd; /* update for next sequence */ @@ -1873,10 +1901,8 @@ static size_t ZSTD_decompressSequences( { size_t lastLLSize = litEnd - litPtr; if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - if (op != litPtr) memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } + if (op != litPtr) memmove(op, litPtr, lastLLSize); + op += lastLLSize; } } @@ -2124,5 +2150,3 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi } } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v01.h b/vendor/github.com/DataDog/zstd/zstd_v01.h index 29c71432..245f9dd3 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v01.h +++ b/vendor/github.com/DataDog/zstd/zstd_v01.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -93,5 +92,3 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi #endif #endif /* ZSTD_V01_H_28739879432 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v02.c b/vendor/github.com/DataDog/zstd/zstd_v02.c index cc33658d..c8783799 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v02.c +++ b/vendor/github.com/DataDog/zstd/zstd_v02.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -29,7 +28,7 @@ low-level memory access routines Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -90,11 +89,7 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -116,6 +111,27 @@ extern "C" { /**************************************************************** * Memory I/O *****************************************************************/ +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets generating assembly depending on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; } MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; } @@ -126,6 +142,33 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) return one.c[0]; } +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + MEM_STATIC U16 MEM_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -146,6 +189,9 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } +#endif // MEM_FORCE_MEMORY_ACCESS + + MEM_STATIC U16 MEM_readLE16(const void* memPtr) { if (MEM_isLittleEndian()) @@ -222,7 +268,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) header file (to include) Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -303,8 +349,9 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BIT_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -386,7 +433,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_lookBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -406,7 +453,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) } /*!BIT_readBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -463,7 +510,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) Error codes and messages Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -562,7 +609,7 @@ typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be mor header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -706,7 +753,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -775,7 +822,7 @@ static size_t HUF_decompress4X6 (void* dst, size_t dstSize, const void* cSrc, si Header File Copyright (C) 2014-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -835,7 +882,7 @@ typedef struct ZSTD_CCtx_s ZSTD_CCtx; /* incomplete type */ Header File for static linking only Copyright (C) 2014-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -899,7 +946,7 @@ typedef struct ZSTD_DCtx_s ZSTD_DCtx; FSE : Finite State Entropy coder Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1403,7 +1450,7 @@ static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, siz Huff0 : Huffman coder, part of New Generation Entropy library Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2562,7 +2609,7 @@ static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_ zstd - standard compression library Copyright (C) 2014-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2789,9 +2836,7 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - if (srcSize > 0) { - memcpy(dst, src, srcSize); - } + memcpy(dst, src, srcSize); return srcSize; } @@ -3067,19 +3112,12 @@ static size_t ZSTD_execSequence(BYTE* op, const BYTE* const litEnd = *litPtr + sequence.litLength; /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use the pointer check */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - if (sequence.offset > (U32)(oLitEnd - base)) return ERROR(corruption_detected); - + if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ if (litEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ /* copy Literals */ - ZSTD_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ + ZSTD_wildcopy(op, *litPtr, sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = litEnd; /* update for next sequence */ @@ -3191,10 +3229,8 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - if (op != litPtr) memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } + if (op != litPtr) memmove(op, litPtr, lastLLSize); + op += lastLLSize; } } @@ -3476,5 +3512,3 @@ size_t ZSTDv02_decompressContinue(ZSTDv02_Dctx* dctx, void* dst, size_t maxDstSi { return ZSTD_decompressContinue((ZSTD_DCtx*)dctx, dst, maxDstSize, src, srcSize); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v02.h b/vendor/github.com/DataDog/zstd/zstd_v02.h index 71d79cac..9d7d8d9b 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v02.h +++ b/vendor/github.com/DataDog/zstd/zstd_v02.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -92,5 +91,3 @@ size_t ZSTDv02_decompressContinue(ZSTDv02_Dctx* dctx, void* dst, size_t maxDstSi #endif #endif /* ZSTD_V02_H_4174539423 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v03.c b/vendor/github.com/DataDog/zstd/zstd_v03.c index af98cac7..162bd630 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v03.c +++ b/vendor/github.com/DataDog/zstd/zstd_v03.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -30,7 +29,7 @@ low-level memory access routines Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -91,11 +90,7 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -117,6 +112,27 @@ extern "C" { /**************************************************************** * Memory I/O *****************************************************************/ +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets generating assembly depending on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; } MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; } @@ -127,6 +143,33 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) return one.c[0]; } +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + MEM_STATIC U16 MEM_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -147,6 +190,10 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } + +#endif // MEM_FORCE_MEMORY_ACCESS + + MEM_STATIC U16 MEM_readLE16(const void* memPtr) { if (MEM_isLittleEndian()) @@ -223,7 +270,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) header file (to include) Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -305,8 +352,9 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BIT_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -387,7 +435,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_lookBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -407,7 +455,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) } /*!BIT_readBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -464,7 +512,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) Error codes and messages Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -563,7 +611,7 @@ typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be mor header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -707,7 +755,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -775,7 +823,7 @@ static size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, si Header File Copyright (C) 2014-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -835,7 +883,7 @@ typedef struct ZSTD_CCtx_s ZSTD_CCtx; /* incomplete type */ Header File for static linking only Copyright (C) 2014-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -899,7 +947,7 @@ typedef struct ZSTD_DCtx_s ZSTD_DCtx; FSE : Finite State Entropy coder Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1403,7 +1451,7 @@ static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, siz Huff0 : Huffman coder, part of New Generation Entropy library Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2200,7 +2248,7 @@ static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_ zstd - standard compression library Copyright (C) 2014-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2429,9 +2477,7 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - if (srcSize > 0) { - memcpy(dst, src, srcSize); - } + memcpy(dst, src, srcSize); return srcSize; } @@ -2707,24 +2753,18 @@ static size_t ZSTD_execSequence(BYTE* op, const BYTE* const litEnd = *litPtr + sequence.litLength; /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - if (sequence.offset > (U32)(oLitEnd - base)) return ERROR(corruption_detected); - + if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ if (litEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ /* copy Literals */ - ZSTD_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ + ZSTD_wildcopy(op, *litPtr, sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = litEnd; /* update for next sequence */ /* copy Match */ - { const BYTE* match = op - sequence.offset; + { + const BYTE* match = op - sequence.offset; /* check */ if (sequence.offset > (size_t)op) return ERROR(corruption_detected); /* address space overflow test (this test seems kept by clang optimizer) */ @@ -2830,10 +2870,8 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - if (op != litPtr) memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } + if (op != litPtr) memmove(op, litPtr, lastLLSize); + op += lastLLSize; } } @@ -3116,5 +3154,3 @@ size_t ZSTDv03_decompressContinue(ZSTDv03_Dctx* dctx, void* dst, size_t maxDstSi { return ZSTD_decompressContinue((ZSTD_DCtx*)dctx, dst, maxDstSize, src, srcSize); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v03.h b/vendor/github.com/DataDog/zstd/zstd_v03.h index ec3d8971..efd8c2b9 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v03.h +++ b/vendor/github.com/DataDog/zstd/zstd_v03.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -92,5 +91,3 @@ size_t ZSTDv03_decompressContinue(ZSTDv03_Dctx* dctx, void* dst, size_t maxDstSi #endif #endif /* ZSTD_V03_H_298734209782 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v04.c b/vendor/github.com/DataDog/zstd/zstd_v04.c index b353ddc3..4dec3081 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v04.c +++ b/vendor/github.com/DataDog/zstd/zstd_v04.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -53,11 +52,7 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -88,6 +83,27 @@ extern "C" { /**************************************************************** * Memory I/O *****************************************************************/ +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets generating assembly depending on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; } MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; } @@ -98,6 +114,33 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) return one.c[0]; } +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + MEM_STATIC U16 MEM_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -118,6 +161,9 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } +#endif // MEM_FORCE_MEMORY_ACCESS + + MEM_STATIC U16 MEM_readLE16(const void* memPtr) { if (MEM_isLittleEndian()) @@ -495,7 +541,7 @@ If there is an error, the function will return an error code, which can be teste header file (to include) Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -577,8 +623,9 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BIT_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -653,7 +700,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_lookBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -673,7 +720,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) } /*!BIT_readBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -734,7 +781,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -883,7 +930,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) FSE : Finite State Entropy coder Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1389,7 +1436,7 @@ static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, siz header file Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1467,7 +1514,7 @@ static unsigned HUF_isError(size_t code); /* tells if a return value i header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1554,7 +1601,7 @@ static size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const Huff0 : Huffman coder, part of New Generation Entropy library Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2354,7 +2401,7 @@ static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_ zstd - decompression module fo v0.4 legacy format Copyright (C) 2015-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2556,9 +2603,7 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - if (srcSize > 0) { - memcpy(dst, src, srcSize); - } + memcpy(dst, src, srcSize); return srcSize; } @@ -2829,19 +2874,13 @@ static size_t ZSTD_execSequence(BYTE* op, const BYTE* const litEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; - /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - + /* check */ + if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (litEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ + if (litEnd > litLimit) return ERROR(corruption_detected); /* risk read beyond lit buffer */ /* copy Literals */ - ZSTD_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ + ZSTD_wildcopy(op, *litPtr, sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = litEnd; /* update for next sequence */ @@ -2969,10 +3008,8 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - if (op != litPtr) memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } + if (op != litPtr) memcpy(op, litPtr, lastLLSize); + op += lastLLSize; } } @@ -3242,7 +3279,7 @@ static void ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* dict, s Buffered version of Zstd compression library Copyright (C) 2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -3370,9 +3407,7 @@ static size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* zbc, const void* src, s static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { size_t length = MIN(maxDstSize, srcSize); - if (length > 0) { - memcpy(dst, src, length); - } + memcpy(dst, src, length); return length; } @@ -3604,5 +3639,3 @@ size_t ZBUFFv04_decompressContinue(ZBUFFv04_DCtx* dctx, void* dst, size_t* maxDs ZSTD_DCtx* ZSTDv04_createDCtx(void) { return ZSTD_createDCtx(); } size_t ZSTDv04_freeDCtx(ZSTD_DCtx* dctx) { return ZSTD_freeDCtx(dctx); } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v04.h b/vendor/github.com/DataDog/zstd/zstd_v04.h index b904be0c..bb5f3b7d 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v04.h +++ b/vendor/github.com/DataDog/zstd/zstd_v04.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -141,5 +140,3 @@ size_t ZBUFFv04_recommendedDOutSize(void); #endif #endif /* ZSTD_V04_H_91868324769238 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v05.c b/vendor/github.com/DataDog/zstd/zstd_v05.c index a91166a0..570e0ff8 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v05.c +++ b/vendor/github.com/DataDog/zstd/zstd_v05.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,7 +19,7 @@ low-level memory access routines Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -81,11 +80,7 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -107,6 +102,27 @@ extern "C" { /*-************************************************************** * Memory I/O *****************************************************************/ +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets depending on alignment. + * In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; } MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; } @@ -117,6 +133,37 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) return one.c[0]; } +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard, by lying on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + MEM_STATIC U16 MEM_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -147,6 +194,9 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) memcpy(memPtr, &value, sizeof(value)); } +#endif /* MEM_FORCE_MEMORY_ACCESS */ + + MEM_STATIC U16 MEM_readLE16(const void* memPtr) { if (MEM_isLittleEndian()) @@ -211,7 +261,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) Header File for static linking only Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -235,7 +285,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd + - zstd homepage : http://www.zstd.net */ #ifndef ZSTD_STATIC_H #define ZSTD_STATIC_H @@ -347,7 +397,7 @@ size_t ZSTDv05_decompressBlock(ZSTDv05_DCtx* dctx, void* dst, size_t dstCapacity Header File for include Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -434,7 +484,7 @@ static const size_t ZSTDv05_frameHeaderSize_min = 5; #define FSEv05_ENCODING_DYNAMIC 3 -#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 +#define HufLog 12 #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ @@ -502,7 +552,7 @@ typedef struct { header file Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -621,7 +671,7 @@ size_t FSEv05_decompress_usingDTable(void* dst, size_t dstCapacity, const void* header file (to include) Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -702,8 +752,9 @@ MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BITv05_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -775,7 +826,7 @@ MEM_STATIC size_t BITv05_lookBits(BITv05_DStream_t* bitD, U32 nbBits) } /*! BITv05_lookBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BITv05_lookBitsFast(BITv05_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -795,7 +846,7 @@ MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, unsigned nbBits) } /*!BITv05_readBitsFast : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits) { size_t value = BITv05_lookBitsFast(bitD, nbBits); @@ -850,7 +901,7 @@ MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* DStream) header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1000,7 +1051,7 @@ MEM_STATIC unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr) FSEv05 : Finite State Entropy coder Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1486,7 +1537,7 @@ size_t FSEv05_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t header file Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1559,7 +1610,7 @@ const char* HUFv05_getErrorName(size_t code); /* provides error code string (u header file, for static linking only Copyright (C) 2013-2016, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1651,7 +1702,7 @@ size_t HUFv05_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void Huff0 : Huffman coder, part of New Generation Entropy library Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1753,7 +1804,7 @@ static size_t HUFv05_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ + //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ @@ -1828,7 +1879,7 @@ size_t HUFv05_readDTableX2 (U16* DTable, const void* src, size_t srcSize) HUFv05_DEltX2* const dt = (HUFv05_DEltX2*)dtPtr; HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ iSize = HUFv05_readStats(huffWeight, HUFv05_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUFv05_isError(iSize)) return iSize; @@ -2159,7 +2210,7 @@ size_t HUFv05_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize) HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX4) == sizeof(unsigned)); /* if compilation fails here, assertion is false */ if (memLog > HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ iSize = HUFv05_readStats(weightList, HUFv05_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUFv05_isError(iSize)) return iSize; @@ -2488,15 +2539,15 @@ size_t HUFv05_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); - /* return HUFv05_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ - /* return HUFv05_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ - /* return HUFv05_decompress4X6(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams quad-symbols decoding */ + //return HUFv05_decompress4X2(dst, dstSize, cSrc, cSrcSize); /* multi-streams single-symbol decoding */ + //return HUFv05_decompress4X4(dst, dstSize, cSrc, cSrcSize); /* multi-streams double-symbols decoding */ + //return HUFv05_decompress4X6(dst, dstSize, cSrc, cSrcSize); /* multi-streams quad-symbols decoding */ } /* zstd - standard compression library Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2594,7 +2645,7 @@ struct ZSTDv05_DCtx_s FSEv05_DTable LLTable[FSEv05_DTABLE_SIZE_U32(LLFSEv05Log)]; FSEv05_DTable OffTable[FSEv05_DTABLE_SIZE_U32(OffFSEv05Log)]; FSEv05_DTable MLTable[FSEv05_DTABLE_SIZE_U32(MLFSEv05Log)]; - unsigned hufTableX4[HUFv05_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; + unsigned hufTableX4[HUFv05_DTABLE_SIZE(HufLog)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -2622,7 +2673,7 @@ size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; + dctx->hufTableX4[0] = HufLog; dctx->flagStaticTables = 0; return 0; } @@ -2778,7 +2829,7 @@ static size_t ZSTDv05_decodeFrameHeader_Part2(ZSTDv05_DCtx* zc, const void* src, static size_t ZSTDv05_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - const BYTE* const in = (const BYTE*)src; + const BYTE* const in = (const BYTE* const)src; BYTE headerFlags; U32 cSize; @@ -2947,7 +2998,7 @@ static size_t ZSTDv05_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t FSEv05_DTable* DTableLL, FSEv05_DTable* DTableML, FSEv05_DTable* DTableOffb, const void* src, size_t srcSize, U32 flagStaticTable) { - const BYTE* const istart = (const BYTE*)src; + const BYTE* const istart = (const BYTE* const)src; const BYTE* ip = istart; const BYTE* const iend = istart + srcSize; U32 LLtype, Offtype, MLtype; @@ -3183,19 +3234,13 @@ static size_t ZSTDv05_execSequence(BYTE* op, const BYTE* const litEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; - /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - + /* check */ + if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (litEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ + if (litEnd > litLimit) return ERROR(corruption_detected); /* risk read beyond lit buffer */ /* copy Literals */ - ZSTDv05_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ + ZSTDv05_wildcopy(op, *litPtr, sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = litEnd; /* update for next sequence */ @@ -3261,7 +3306,7 @@ static size_t ZSTDv05_decompressSequences( { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; size_t errorCode, dumpsLength=0; @@ -3317,10 +3362,8 @@ static size_t ZSTDv05_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; } return op-ostart; @@ -3374,7 +3417,7 @@ static size_t ZSTDv05_decompress_continueDCtx(ZSTDv05_DCtx* dctx, { const BYTE* ip = (const BYTE*)src; const BYTE* iend = ip + srcSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; size_t remainingSize = srcSize; @@ -3701,7 +3744,7 @@ size_t ZSTDv05_decompressBegin_usingDict(ZSTDv05_DCtx* dctx, const void* dict, s Buffered version of Zstd compression library Copyright (C) 2015-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -3748,9 +3791,7 @@ static size_t ZBUFFv05_blockHeaderSize = 3; static size_t ZBUFFv05_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { size_t length = MIN(maxDstSize, srcSize); - if (length > 0) { - memcpy(dst, src, length); - } + memcpy(dst, src, length); return length; } @@ -3887,7 +3928,7 @@ size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDst *maxDstSizePtr = 0; return headerSize - zbc->hPos; } - /* zbc->stage = ZBUFFv05ds_decodeHeader; break; */ /* useless : stage follows */ + // zbc->stage = ZBUFFv05ds_decodeHeader; break; /* useless : stage follows */ } /* fall-through */ case ZBUFFv05ds_decodeHeader: @@ -3960,7 +4001,7 @@ size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDst if (!decodedSize) { zbc->stage = ZBUFFv05ds_read; break; } /* this was just a header */ zbc->outEnd = zbc->outStart + decodedSize; zbc->stage = ZBUFFv05ds_flush; - /* break; */ /* ZBUFFv05ds_flush follows */ + // break; /* ZBUFFv05ds_flush follows */ } } /* fall-through */ @@ -4003,5 +4044,3 @@ const char* ZBUFFv05_getErrorName(size_t errorCode) { return ERR_getErrorName(er size_t ZBUFFv05_recommendedDInSize(void) { return BLOCKSIZE + ZBUFFv05_blockHeaderSize /* block header size*/ ; } size_t ZBUFFv05_recommendedDOutSize(void) { return BLOCKSIZE; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v05.h b/vendor/github.com/DataDog/zstd/zstd_v05.h index ebb7831e..4a979854 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v05.h +++ b/vendor/github.com/DataDog/zstd/zstd_v05.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -161,5 +160,3 @@ size_t ZBUFFv05_recommendedDOutSize(void); #endif #endif /* ZSTDv0505_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v06.c b/vendor/github.com/DataDog/zstd/zstd_v06.c index 0fd4225f..2a08e8de 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v06.c +++ b/vendor/github.com/DataDog/zstd/zstd_v06.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -24,7 +23,7 @@ low-level memory access routines Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -83,11 +82,7 @@ extern "C" { * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -109,6 +104,27 @@ extern "C" { /*-************************************************************** * Memory I/O *****************************************************************/ +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets depending on alignment. + * In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } @@ -119,6 +135,33 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) return one.c[0]; } +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard, by lying on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + MEM_STATIC U16 MEM_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -139,6 +182,9 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } + +#endif /* MEM_FORCE_MEMORY_ACCESS */ + MEM_STATIC U32 MEM_swap32(U32 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -234,7 +280,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) Header File for static linking only Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -258,7 +304,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd + - zstd homepage : http://www.zstd.net */ #ifndef ZSTDv06_STATIC_H #define ZSTDv06_STATIC_H @@ -365,7 +411,7 @@ ZSTDLIBv06_API size_t ZSTDv06_decompressBlock(ZSTDv06_DCtx* dctx, void* dst, siz Header File for include Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -432,7 +478,7 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 +#define HufLog 12 #define IS_HUF 0 #define IS_PCH 1 @@ -572,7 +618,7 @@ void ZSTDv06_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq); Public Prototypes declaration Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -720,7 +766,7 @@ If there is an error, the function will return an error code, which can be teste header file (to include) Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -810,8 +856,9 @@ MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BITv06_highbit32 ( U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -881,7 +928,7 @@ MEM_STATIC size_t BITv06_initDStream(BITv06_DStream_t* bitD, const void* srcBuff } /*! BITv06_lookBitsFast() : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BITv06_lookBitsFast(const BITv06_DStream_t* bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -901,7 +948,7 @@ MEM_STATIC size_t BITv06_readBits(BITv06_DStream_t* bitD, U32 nbBits) } /*! BITv06_readBitsFast() : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, U32 nbBits) { size_t const value = BITv06_lookBitsFast(bitD, nbBits); @@ -955,7 +1002,7 @@ MEM_STATIC unsigned BITv06_endOfDStream(const BITv06_DStream_t* DStream) header file for static linking (only) Copyright (C) 2013-2015, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1163,7 +1210,7 @@ MEM_STATIC BYTE FSEv06_decodeSymbolFast(FSEv06_DState_t* DStatePtr, BITv06_DStre Common functions of New Generation Entropy library Copyright (C) 2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1308,7 +1355,7 @@ size_t FSEv06_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned FSE : Finite State Entropy decoder Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1632,7 +1679,7 @@ size_t FSEv06_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t header file Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1702,7 +1749,7 @@ size_t HUFv06_compressBound(size_t size); /**< maximum compressed size */ header file, for static linking only Copyright (C) 2013-2016, Yann Collet - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1815,7 +1862,7 @@ MEM_STATIC size_t HUFv06_readStats(BYTE* huffWeight, size_t hwSize, U32* rankSta if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ + //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ @@ -1884,7 +1931,7 @@ MEM_STATIC size_t HUFv06_readStats(BYTE* huffWeight, size_t hwSize, U32* rankSta Huffman decoder, part of New Generation Entropy library Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1967,7 +2014,7 @@ size_t HUFv06_readDTableX2 (U16* DTable, const void* src, size_t srcSize) HUFv06_DEltX2* const dt = (HUFv06_DEltX2*)dtPtr; HUFv06_STATIC_ASSERT(sizeof(HUFv06_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ iSize = HUFv06_readStats(huffWeight, HUFv06_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUFv06_isError(iSize)) return iSize; @@ -2293,7 +2340,7 @@ size_t HUFv06_readDTableX4 (U32* DTable, const void* src, size_t srcSize) HUFv06_STATIC_ASSERT(sizeof(HUFv06_DEltX4) == sizeof(U32)); /* if compilation fails here, assertion is false */ if (memLog > HUFv06_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ iSize = HUFv06_readStats(weightList, HUFv06_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUFv06_isError(iSize)) return iSize; @@ -2617,19 +2664,19 @@ size_t HUFv06_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS { U32 algoNb = 0; if (Dtime[1] < Dtime[0]) algoNb = 1; - /* if (Dtime[2] < Dtime[algoNb]) algoNb = 2; */ /* current speed of HUFv06_decompress4X6 is not good */ + // if (Dtime[2] < Dtime[algoNb]) algoNb = 2; /* current speed of HUFv06_decompress4X6 is not good */ return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); } - /* return HUFv06_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ - /* return HUFv06_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ - /* return HUFv06_decompress4X6(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams quad-symbols decoding */ + //return HUFv06_decompress4X2(dst, dstSize, cSrc, cSrcSize); /* multi-streams single-symbol decoding */ + //return HUFv06_decompress4X4(dst, dstSize, cSrc, cSrcSize); /* multi-streams double-symbols decoding */ + //return HUFv06_decompress4X6(dst, dstSize, cSrc, cSrcSize); /* multi-streams quad-symbols decoding */ } /* Common functions of Zstd compression library Copyright (C) 2015-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2653,7 +2700,7 @@ size_t HUFv06_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd/ + - zstd homepage : http://www.zstd.net/ */ @@ -2683,7 +2730,7 @@ const char* ZBUFFv06_getErrorName(size_t errorCode) { return ERR_getErrorName(er zstd - standard compression library Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2707,7 +2754,7 @@ const char* ZBUFFv06_getErrorName(size_t errorCode) { return ERR_getErrorName(er OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd + - zstd homepage : http://www.zstd.net */ /* *************************************************************** @@ -2759,7 +2806,7 @@ struct ZSTDv06_DCtx_s FSEv06_DTable LLTable[FSEv06_DTABLE_SIZE_U32(LLFSELog)]; FSEv06_DTable OffTable[FSEv06_DTABLE_SIZE_U32(OffFSELog)]; FSEv06_DTable MLTable[FSEv06_DTABLE_SIZE_U32(MLFSELog)]; - unsigned hufTableX4[HUFv06_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; + unsigned hufTableX4[HUFv06_DTABLE_SIZE(HufLog)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -2787,7 +2834,7 @@ size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; + dctx->hufTableX4[0] = HufLog; dctx->flagRepeatTable = 0; return 0; } @@ -2978,7 +3025,7 @@ typedef struct * Provides the size of compressed block from block header `src` */ static size_t ZSTDv06_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - const BYTE* const in = (const BYTE*)src; + const BYTE* const in = (const BYTE* const)src; U32 cSize; if (srcSize < ZSTDv06_blockHeaderSize) return ERROR(srcSize_wrong); @@ -3172,7 +3219,7 @@ static size_t ZSTDv06_decodeSeqHeaders(int* nbSeqPtr, FSEv06_DTable* DTableLL, FSEv06_DTable* DTableML, FSEv06_DTable* DTableOffb, U32 flagRepeatTable, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE*)src; + const BYTE* const istart = (const BYTE* const)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; @@ -3323,19 +3370,13 @@ static size_t ZSTDv06_execSequence(BYTE* op, const BYTE* const iLitEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; - /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - + /* check */ + if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (iLitEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ + if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */ /* copy Literals */ - ZSTDv06_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ + ZSTDv06_wildcopy(op, *litPtr, sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = iLitEnd; /* update for next sequence */ @@ -3400,7 +3441,7 @@ static size_t ZSTDv06_decompressSequences( { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; @@ -3460,10 +3501,8 @@ static size_t ZSTDv06_decompressSequences( { size_t const lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; } return op-ostart; @@ -3516,7 +3555,7 @@ static size_t ZSTDv06_decompressFrame(ZSTDv06_DCtx* dctx, { const BYTE* ip = (const BYTE*)src; const BYTE* const iend = ip + srcSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; BYTE* const oend = ostart + dstCapacity; size_t remainingSize = srcSize; @@ -3848,7 +3887,7 @@ size_t ZSTDv06_decompressBegin_usingDict(ZSTDv06_DCtx* dctx, const void* dict, s Buffered version of Zstd compression library Copyright (C) 2015-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -3872,7 +3911,7 @@ size_t ZSTDv06_decompressBegin_usingDict(ZSTDv06_DCtx* dctx, const void* dict, s OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd/ + - zstd homepage : http://www.zstd.net/ */ @@ -3961,9 +4000,7 @@ size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* zbd) MEM_STATIC size_t ZBUFFv06_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t length = MIN(dstCapacity, srcSize); - if (length > 0) { - memcpy(dst, src, length); - } + memcpy(dst, src, length); return length; } @@ -3994,8 +4031,7 @@ size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* zbd, size_t const toLoad = hSize - zbd->lhSize; /* if hSize!=0, hSize > zbd->lhSize */ if (ZSTDv06_isError(hSize)) return hSize; if (toLoad > (size_t)(iend-ip)) { /* not enough input to load full header */ - if (ip != NULL) - memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip); + memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip); zbd->lhSize += iend-ip; *dstCapacityPtr = 0; return (hSize - zbd->lhSize) + ZSTDv06_blockHeaderSize; /* remaining header bytes + next block header */ @@ -4073,7 +4109,7 @@ size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* zbd, if (!decodedSize) { zbd->stage = ZBUFFds_read; break; } /* this was just a header */ zbd->outEnd = zbd->outStart + decodedSize; zbd->stage = ZBUFFds_flush; - /* break; */ /* ZBUFFds_flush follows */ + // break; /* ZBUFFds_flush follows */ } } /* fall-through */ @@ -4112,5 +4148,3 @@ size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* zbd, ***************************************/ size_t ZBUFFv06_recommendedDInSize(void) { return ZSTDv06_BLOCKSIZE_MAX + ZSTDv06_blockHeaderSize /* block header size*/ ; } size_t ZBUFFv06_recommendedDOutSize(void) { return ZSTDv06_BLOCKSIZE_MAX; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v06.h b/vendor/github.com/DataDog/zstd/zstd_v06.h index f511b101..07818571 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v06.h +++ b/vendor/github.com/DataDog/zstd/zstd_v06.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -171,5 +170,3 @@ ZSTDLIBv06_API size_t ZBUFFv06_recommendedDOutSize(void); #endif #endif /* ZSTDv06_BUFFERED_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v07.c b/vendor/github.com/DataDog/zstd/zstd_v07.c index 60d77e07..a2eeff80 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v07.c +++ b/vendor/github.com/DataDog/zstd/zstd_v07.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -185,7 +184,7 @@ ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockS low-level memory access routines Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -243,11 +242,7 @@ extern "C" { * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -269,6 +264,27 @@ extern "C" { /*-************************************************************** * Memory I/O *****************************************************************/ +/* MEM_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 to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets depending on alignment. + * In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } @@ -279,6 +295,33 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) return one.c[0]; } +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard, by lying on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + MEM_STATIC U16 MEM_read16(const void* memPtr) { U16 val; memcpy(&val, memPtr, sizeof(val)); return val; @@ -299,6 +342,8 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } +#endif /* MEM_FORCE_MEMORY_ACCESS */ + MEM_STATIC U32 MEM_swap32(U32 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -393,7 +438,7 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) header file (to include) Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -481,8 +526,9 @@ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BITv07_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -550,7 +596,7 @@ MEM_STATIC size_t BITv07_initDStream(BITv07_DStream_t* bitD, const void* srcBuff } /*! BITv07_lookBitsFast() : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BITv07_lookBitsFast(const BITv07_DStream_t* bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -570,7 +616,7 @@ MEM_STATIC size_t BITv07_readBits(BITv07_DStream_t* bitD, U32 nbBits) } /*! BITv07_readBitsFast() : -* unsafe version; only works if nbBits >= 1 */ +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, U32 nbBits) { size_t const value = BITv07_lookBitsFast(bitD, nbBits); @@ -624,7 +670,7 @@ MEM_STATIC unsigned BITv07_endOfDStream(const BITv07_DStream_t* DStream) Public Prototypes declaration Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -932,7 +978,7 @@ MEM_STATIC BYTE FSEv07_decodeSymbolFast(FSEv07_DState_t* DStatePtr, BITv07_DStre header file Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1105,7 +1151,7 @@ size_t HUFv07_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void Common functions of New Generation Entropy library Copyright (C) 2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1268,7 +1314,7 @@ size_t HUFv07_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ + //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ @@ -1329,7 +1375,7 @@ size_t HUFv07_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, FSE : Finite State Entropy decoder Copyright (C) 2013-2015, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1653,7 +1699,7 @@ size_t FSEv07_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t Huffman decoder, part of New Generation Entropy library Copyright (C) 2013-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -1738,7 +1784,7 @@ size_t HUFv07_readDTableX2 (HUFv07_DTable* DTable, const void* src, size_t srcSi HUFv07_DEltX2* const dt = (HUFv07_DEltX2*)dtPtr; HUFv07_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUFv07_DTable)); - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ iSize = HUFv07_readStats(huffWeight, HUFv07_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUFv07_isError(iSize)) return iSize; @@ -2102,7 +2148,7 @@ size_t HUFv07_readDTableX4 (HUFv07_DTable* DTable, const void* src, size_t srcSi HUFv07_STATIC_ASSERT(sizeof(HUFv07_DEltX4) == sizeof(HUFv07_DTable)); /* if compilation fails here, assertion is false */ if (maxTableLog > HUFv07_TABLELOG_ABSOLUTEMAX) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ iSize = HUFv07_readStats(weightList, HUFv07_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUFv07_isError(iSize)) return iSize; @@ -2484,8 +2530,8 @@ size_t HUFv07_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); } - /* return HUFv07_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ - /* return HUFv07_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ + //return HUFv07_decompress4X2(dst, dstSize, cSrc, cSrcSize); /* multi-streams single-symbol decoding */ + //return HUFv07_decompress4X4(dst, dstSize, cSrc, cSrcSize); /* multi-streams double-symbols decoding */ } size_t HUFv07_decompress4X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) @@ -2531,7 +2577,7 @@ size_t HUFv07_decompress1X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, Common functions of Zstd compression library Copyright (C) 2015-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2555,7 +2601,7 @@ size_t HUFv07_decompress1X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd/ + - zstd homepage : http://www.zstd.net/ */ @@ -2601,7 +2647,7 @@ static void ZSTDv07_defaultFreeFunction(void* opaque, void* address) Header File for include Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2671,7 +2717,7 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 +#define HufLog 12 typedef enum { lbt_huffman, lbt_repeat, lbt_raw, lbt_rle } litBlockType_t; #define LONGNBSEQ 0x7F00 @@ -2808,7 +2854,7 @@ static const ZSTDv07_customMem defaultCustomMem = { ZSTDv07_defaultAllocFunction zstd - standard compression library Copyright (C) 2014-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -2832,7 +2878,7 @@ static const ZSTDv07_customMem defaultCustomMem = { ZSTDv07_defaultAllocFunction OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd + - zstd homepage : http://www.zstd.net */ /* *************************************************************** @@ -2885,7 +2931,7 @@ struct ZSTDv07_DCtx_s FSEv07_DTable LLTable[FSEv07_DTABLE_SIZE_U32(LLFSELog)]; FSEv07_DTable OffTable[FSEv07_DTABLE_SIZE_U32(OffFSELog)]; FSEv07_DTable MLTable[FSEv07_DTABLE_SIZE_U32(MLFSELog)]; - HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUFv07_decompress4X */ + HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(HufLog)]; /* can accommodate HUFv07_decompress4X */ const void* previousDstEnd; const void* base; const void* vBase; @@ -2921,7 +2967,7 @@ size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTable[0] = (HUFv07_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); + dctx->hufTable[0] = (HUFv07_DTable)((HufLog)*0x1000001); dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; { int i; for (i=0; irep[i] = repStartValue[i]; } @@ -3208,7 +3254,7 @@ typedef struct * Provides the size of compressed block from block header `src` */ static size_t ZSTDv07_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - const BYTE* const in = (const BYTE*)src; + const BYTE* const in = (const BYTE* const)src; U32 cSize; if (srcSize < ZSTDv07_blockHeaderSize) return ERROR(srcSize_wrong); @@ -3226,9 +3272,7 @@ static size_t ZSTDv07_getcBlockSize(const void* src, size_t srcSize, blockProper static size_t ZSTDv07_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall); - if (srcSize > 0) { - memcpy(dst, src, srcSize); - } + memcpy(dst, src, srcSize); return srcSize; } @@ -3403,7 +3447,7 @@ static size_t ZSTDv07_decodeSeqHeaders(int* nbSeqPtr, FSEv07_DTable* DTableLL, FSEv07_DTable* DTableML, FSEv07_DTable* DTableOffb, U32 flagRepeatTable, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE*)src; + const BYTE* const istart = (const BYTE* const)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; @@ -3553,14 +3597,11 @@ size_t ZSTDv07_execSequence(BYTE* op, const BYTE* match = oLitEnd - sequence.offset; /* check */ - assert(oend >= op); - if (sequence.litLength + WILDCOPY_OVERLENGTH > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequenceLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - assert(litLimit >= *litPtr); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected);; + if ((oLitEnd>oend_w) | (oMatchEnd>oend)) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */ + if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */ /* copy Literals */ - ZSTDv07_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ + ZSTDv07_wildcopy(op, *litPtr, sequence.litLength); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ op = oLitEnd; *litPtr = iLitEnd; /* update for next sequence */ @@ -3574,7 +3615,7 @@ size_t ZSTDv07_execSequence(BYTE* op, return sequenceLength; } /* span extDict & currentPrefixSegment */ - { size_t const length1 = (size_t)(dictEnd - match); + { size_t const length1 = dictEnd - match; memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; @@ -3625,7 +3666,7 @@ static size_t ZSTDv07_decompressSequences( { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; @@ -3671,12 +3712,10 @@ static size_t ZSTDv07_decompressSequences( /* last literal segment */ { size_t const lastLLSize = litEnd - litPtr; - /* if (litPtr > litEnd) return ERROR(corruption_detected); */ /* too many literals already used */ + //if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; } return op-ostart; @@ -3737,9 +3776,7 @@ ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockS static size_t ZSTDv07_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length) { if (length > dstCapacity) return ERROR(dstSize_tooSmall); - if (length > 0) { - memset(dst, byte, length); - } + memset(dst, byte, length); return length; } @@ -3752,7 +3789,7 @@ static size_t ZSTDv07_decompressFrame(ZSTDv07_DCtx* dctx, { const BYTE* ip = (const BYTE*)src; const BYTE* const iend = ip + srcSize; - BYTE* const ostart = (BYTE*)dst; + BYTE* const ostart = (BYTE* const)dst; BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; size_t remainingSize = srcSize; @@ -4210,7 +4247,7 @@ ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx, Buffered version of Zstd compression library Copyright (C) 2015-2016, Yann Collet. - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) + BSD 2-Clause License (http://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 @@ -4234,7 +4271,7 @@ ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx, OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd/ + - zstd homepage : http://www.zstd.net/ */ @@ -4341,9 +4378,7 @@ size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* zbd) MEM_STATIC size_t ZBUFFv07_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t const length = MIN(dstCapacity, srcSize); - if (length > 0) { - memcpy(dst, src, length); - } + memcpy(dst, src, length); return length; } @@ -4374,8 +4409,7 @@ size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* zbd, if (hSize != 0) { size_t const toLoad = hSize - zbd->lhSize; /* if hSize!=0, hSize > zbd->lhSize */ if (toLoad > (size_t)(iend-ip)) { /* not enough input to load full header */ - if (ip != NULL) - memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip); + memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip); zbd->lhSize += iend-ip; *dstCapacityPtr = 0; return (hSize - zbd->lhSize) + ZSTDv07_blockHeaderSize; /* remaining header bytes + next block header */ @@ -4497,5 +4531,3 @@ size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* zbd, ***************************************/ size_t ZBUFFv07_recommendedDInSize(void) { return ZSTDv07_BLOCKSIZE_ABSOLUTEMAX + ZSTDv07_blockHeaderSize /* block header size*/ ; } size_t ZBUFFv07_recommendedDOutSize(void) { return ZSTDv07_BLOCKSIZE_ABSOLUTEMAX; } - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstd_v07.h b/vendor/github.com/DataDog/zstd/zstd_v07.h index 385b10c8..a566c1d1 100644 --- a/vendor/github.com/DataDog/zstd/zstd_v07.h +++ b/vendor/github.com/DataDog/zstd/zstd_v07.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -186,5 +185,3 @@ ZSTDLIBv07_API size_t ZBUFFv07_recommendedDOutSize(void); #endif #endif /* ZSTDv07_H_235446 */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/DataDog/zstd/zstdmt_compress.c b/vendor/github.com/DataDog/zstd/zstdmt_compress.c index 215cf8ba..bc3062b5 100644 --- a/vendor/github.com/DataDog/zstd/zstdmt_compress.c +++ b/vendor/github.com/DataDog/zstd/zstdmt_compress.c @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -21,8 +20,8 @@ /* ====== Dependencies ====== */ -#include "allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset, INT_MAX, UINT_MAX */ +#include /* memcpy, memset */ +#include /* INT_MAX, UINT_MAX */ #include "mem.h" /* MEM_STATIC */ #include "pool.h" /* threadpool */ #include "threading.h" /* mutex */ @@ -104,13 +103,14 @@ typedef struct ZSTDMT_bufferPool_s { buffer_t bTable[1]; /* variable size */ } ZSTDMT_bufferPool; -static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned maxNbBuffers, ZSTD_customMem cMem) +static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbWorkers, ZSTD_customMem cMem) { - ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_customCalloc( + unsigned const maxNbBuffers = 2*nbWorkers + 3; + ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc( sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem); if (bufPool==NULL) return NULL; if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) { - ZSTD_customFree(bufPool, cMem); + ZSTD_free(bufPool, cMem); return NULL; } bufPool->bufferSize = 64 KB; @@ -127,10 +127,10 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) if (!bufPool) return; /* compatibility with free on NULL */ for (u=0; utotalBuffers; u++) { DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start); - ZSTD_customFree(bufPool->bTable[u].start, bufPool->cMem); + ZSTD_free(bufPool->bTable[u].start, bufPool->cMem); } ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); - ZSTD_customFree(bufPool, bufPool->cMem); + ZSTD_free(bufPool, bufPool->cMem); } /* only works at initialization, not during compression */ @@ -161,8 +161,9 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const } -static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, unsigned maxNbBuffers) +static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, U32 nbWorkers) { + unsigned const maxNbBuffers = 2*nbWorkers + 3; if (srcBufPool==NULL) return NULL; if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */ return srcBufPool; @@ -171,7 +172,7 @@ static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, size_t const bSize = srcBufPool->bufferSize; /* forward parameters */ ZSTDMT_bufferPool* newBufPool; ZSTDMT_freeBufferPool(srcBufPool); - newBufPool = ZSTDMT_createBufferPool(maxNbBuffers, cMem); + newBufPool = ZSTDMT_createBufferPool(nbWorkers, cMem); if (newBufPool==NULL) return newBufPool; ZSTDMT_setBufferSize(newBufPool, bSize); return newBufPool; @@ -200,13 +201,13 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) } /* size conditions not respected : scratch this buffer, create new one */ DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing"); - ZSTD_customFree(buf.start, bufPool->cMem); + ZSTD_free(buf.start, bufPool->cMem); } ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); /* create new buffer */ DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer"); { buffer_t buffer; - void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); + void* const start = ZSTD_malloc(bSize, bufPool->cMem); buffer.start = start; /* note : start can be NULL if malloc fails ! */ buffer.capacity = (start==NULL) ? 0 : bSize; if (start==NULL) { @@ -228,13 +229,13 @@ static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer) { size_t const bSize = bufPool->bufferSize; if (buffer.capacity < bSize) { - void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); + void* const start = ZSTD_malloc(bSize, bufPool->cMem); buffer_t newBuffer; newBuffer.start = start; newBuffer.capacity = start == NULL ? 0 : bSize; if (start != NULL) { assert(newBuffer.capacity >= buffer.capacity); - ZSTD_memcpy(newBuffer.start, buffer.start, buffer.capacity); + memcpy(newBuffer.start, buffer.start, buffer.capacity); DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize); return newBuffer; } @@ -260,22 +261,14 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); /* Reached bufferPool capacity (should not happen) */ DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing "); - ZSTD_customFree(buf.start, bufPool->cMem); + ZSTD_free(buf.start, bufPool->cMem); } -/* We need 2 output buffers per worker since each dstBuff must be flushed after it is released. - * The 3 additional buffers are as follows: - * 1 buffer for input loading - * 1 buffer for "next input" when submitting current one - * 1 buffer stuck in queue */ -#define BUF_POOL_MAX_NB_BUFFERS(nbWorkers) (2*(nbWorkers) + 3) - -/* After a worker releases its rawSeqStore, it is immediately ready for reuse. - * So we only need one seq buffer per worker. */ -#define SEQ_POOL_MAX_NB_BUFFERS(nbWorkers) (nbWorkers) /* ===== Seq Pool Wrapper ====== */ +static rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0}; + typedef ZSTDMT_bufferPool ZSTDMT_seqPool; static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool) @@ -285,7 +278,7 @@ static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool) static rawSeqStore_t bufferToSeq(buffer_t buffer) { - rawSeqStore_t seq = kNullRawSeqStore; + rawSeqStore_t seq = {NULL, 0, 0, 0}; seq.seq = (rawSeq*)buffer.start; seq.capacity = buffer.capacity / sizeof(rawSeq); return seq; @@ -326,7 +319,7 @@ static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq) static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem) { - ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(SEQ_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); + ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(nbWorkers, cMem); if (seqPool == NULL) return NULL; ZSTDMT_setNbSeq(seqPool, 0); return seqPool; @@ -339,7 +332,7 @@ static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool) static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers) { - return ZSTDMT_expandBufferPool(pool, SEQ_POOL_MAX_NB_BUFFERS(nbWorkers)); + return ZSTDMT_expandBufferPool(pool, nbWorkers); } @@ -361,7 +354,7 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) for (cid=0; cidtotalCCtx; cid++) ZSTD_freeCCtx(pool->cctx[cid]); /* note : compatible with free on NULL */ ZSTD_pthread_mutex_destroy(&pool->poolMutex); - ZSTD_customFree(pool, pool->cMem); + ZSTD_free(pool, pool->cMem); } /* ZSTDMT_createCCtxPool() : @@ -369,12 +362,12 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers, ZSTD_customMem cMem) { - ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_customCalloc( + ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc( sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem); assert(nbWorkers > 0); if (!cctxPool) return NULL; if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) { - ZSTD_customFree(cctxPool, cMem); + ZSTD_free(cctxPool, cMem); return NULL; } cctxPool->cMem = cMem; @@ -468,72 +461,52 @@ typedef struct { ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */ } serialState_t; -static int -ZSTDMT_serialState_reset(serialState_t* serialState, - ZSTDMT_seqPool* seqPool, - ZSTD_CCtx_params params, - size_t jobSize, - const void* dict, size_t const dictSize, - ZSTD_dictContentType_e dictContentType) +static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params, size_t jobSize) { /* Adjust parameters */ - if (params.ldmParams.enableLdm == ZSTD_ps_enable) { + if (params.ldmParams.enableLdm) { DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10); ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); assert(params.ldmParams.hashRateLog < 32); + serialState->ldmState.hashPower = + ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); } else { - ZSTD_memset(¶ms.ldmParams, 0, sizeof(params.ldmParams)); + memset(¶ms.ldmParams, 0, sizeof(params.ldmParams)); } serialState->nextJobID = 0; if (params.fParams.checksumFlag) XXH64_reset(&serialState->xxhState, 0); - if (params.ldmParams.enableLdm == ZSTD_ps_enable) { + if (params.ldmParams.enableLdm) { ZSTD_customMem cMem = params.customMem; unsigned const hashLog = params.ldmParams.hashLog; size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t); unsigned const bucketLog = params.ldmParams.hashLog - params.ldmParams.bucketSizeLog; + size_t const bucketSize = (size_t)1 << bucketLog; unsigned const prevBucketLog = serialState->params.ldmParams.hashLog - serialState->params.ldmParams.bucketSizeLog; - size_t const numBuckets = (size_t)1 << bucketLog; /* Size the seq pool tables */ ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize)); /* Reset the window */ - ZSTD_window_init(&serialState->ldmState.window); + ZSTD_window_clear(&serialState->ldmState.window); + serialState->ldmWindow = serialState->ldmState.window; /* Resize tables and output space if necessary. */ if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) { - ZSTD_customFree(serialState->ldmState.hashTable, cMem); - serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(hashSize, cMem); + ZSTD_free(serialState->ldmState.hashTable, cMem); + serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_malloc(hashSize, cMem); } if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) { - ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); - serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem); + ZSTD_free(serialState->ldmState.bucketOffsets, cMem); + serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_malloc(bucketSize, cMem); } if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets) return 1; /* Zero the tables */ - ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize); - ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets); - - /* Update window state and fill hash table with dict */ - serialState->ldmState.loadedDictEnd = 0; - if (dictSize > 0) { - if (dictContentType == ZSTD_dct_rawContent) { - BYTE const* const dictEnd = (const BYTE*)dict + dictSize; - ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0); - ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, ¶ms.ldmParams); - serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base); - } else { - /* don't even load anything */ - } - } - - /* Initialize serialState's copy of ldmWindow. */ - serialState->ldmWindow = serialState->ldmState.window; + memset(serialState->ldmState.hashTable, 0, hashSize); + memset(serialState->ldmState.bucketOffsets, 0, bucketSize); } - serialState->params = params; serialState->params.jobSize = (U32)jobSize; return 0; @@ -542,7 +515,7 @@ ZSTDMT_serialState_reset(serialState_t* serialState, static int ZSTDMT_serialState_init(serialState_t* serialState) { int initError = 0; - ZSTD_memset(serialState, 0, sizeof(*serialState)); + memset(serialState, 0, sizeof(*serialState)); initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL); initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL); initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL); @@ -557,8 +530,8 @@ static void ZSTDMT_serialState_free(serialState_t* serialState) ZSTD_pthread_cond_destroy(&serialState->cond); ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex); ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond); - ZSTD_customFree(serialState->ldmState.hashTable, cMem); - ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); + ZSTD_free(serialState->ldmState.hashTable, cMem); + ZSTD_free(serialState->ldmState.bucketOffsets, cMem); } static void ZSTDMT_serialState_update(serialState_t* serialState, @@ -574,12 +547,12 @@ static void ZSTDMT_serialState_update(serialState_t* serialState, /* A future job may error and skip our job */ if (serialState->nextJobID == jobID) { /* It is now our turn, do any processing necessary */ - if (serialState->params.ldmParams.enableLdm == ZSTD_ps_enable) { + if (serialState->params.ldmParams.enableLdm) { size_t error; assert(seqStore.seq != NULL && seqStore.pos == 0 && seqStore.size == 0 && seqStore.capacity > 0); assert(src.size <= serialState->params.jobSize); - ZSTD_window_update(&serialState->ldmState.window, src.start, src.size, /* forceNonContiguous */ 0); + ZSTD_window_update(&serialState->ldmState.window, src.start, src.size); error = ZSTD_ldm_generateSequences( &serialState->ldmState, &seqStore, &serialState->params.ldmParams, src.start, src.size); @@ -604,7 +577,7 @@ static void ZSTDMT_serialState_update(serialState_t* serialState, if (seqStore.size > 0) { size_t const err = ZSTD_referenceExternalSequences( jobCCtx, seqStore.seq, seqStore.size); - assert(serialState->params.ldmParams.enableLdm == ZSTD_ps_enable); + assert(serialState->params.ldmParams.enableLdm); assert(!ZSTD_isError(err)); (void)err; } @@ -682,7 +655,7 @@ static void ZSTDMT_compressionJob(void* jobDescription) if (dstBuff.start==NULL) JOB_ERROR(ERROR(memory_allocation)); job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */ } - if (jobParams.ldmParams.enableLdm == ZSTD_ps_enable && rawSeqStore.seq == NULL) + if (jobParams.ldmParams.enableLdm && rawSeqStore.seq == NULL) JOB_ERROR(ERROR(memory_allocation)); /* Don't compute the checksum for chunks, since we compute it externally, @@ -690,9 +663,7 @@ static void ZSTDMT_compressionJob(void* jobDescription) */ if (job->jobID != 0) jobParams.fParams.checksumFlag = 0; /* Don't run LDM for the chunks, since we handle it externally */ - jobParams.ldmParams.enableLdm = ZSTD_ps_disable; - /* Correct nbWorkers to 0. */ - jobParams.nbWorkers = 0; + jobParams.ldmParams.enableLdm = 0; /* init */ @@ -705,10 +676,6 @@ static void ZSTDMT_compressionJob(void* jobDescription) { size_t const forceWindowError = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob); if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError); } - if (!job->firstJob) { - size_t const err = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_deterministicRefPrefix, 0); - if (ZSTD_isError(err)) JOB_ERROR(err); - } { size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */ ZSTD_dtlm_fast, @@ -721,7 +688,7 @@ static void ZSTDMT_compressionJob(void* jobDescription) ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID); if (!job->firstJob) { /* flush and overwrite frame header when it's not first job */ - size_t const hSize = ZSTD_compressContinue_public(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0); + size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0); if (ZSTD_isError(hSize)) JOB_ERROR(hSize); DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize); ZSTD_invalidateRepCodes(cctx); @@ -739,7 +706,7 @@ static void ZSTDMT_compressionJob(void* jobDescription) DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks); assert(job->cSize == 0); for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) { - size_t const cSize = ZSTD_compressContinue_public(cctx, op, oend-op, ip, chunkSize); + size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, chunkSize); if (ZSTD_isError(cSize)) JOB_ERROR(cSize); ip += chunkSize; op += cSize; assert(op < oend); @@ -759,18 +726,11 @@ static void ZSTDMT_compressionJob(void* jobDescription) size_t const lastBlockSize1 = job->src.size & (chunkSize-1); size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1; size_t const cSize = (job->lastJob) ? - ZSTD_compressEnd_public(cctx, op, oend-op, ip, lastBlockSize) : - ZSTD_compressContinue_public(cctx, op, oend-op, ip, lastBlockSize); + ZSTD_compressEnd (cctx, op, oend-op, ip, lastBlockSize) : + ZSTD_compressContinue(cctx, op, oend-op, ip, lastBlockSize); if (ZSTD_isError(cSize)) JOB_ERROR(cSize); lastCBlockSize = cSize; } } - if (!job->firstJob) { - /* Double check that we don't have an ext-dict, because then our - * repcode invalidation doesn't work. - */ - assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); - } - ZSTD_CCtx_trace(cctx, 0); _endJob: ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize); @@ -817,15 +777,6 @@ typedef struct { static const roundBuff_t kNullRoundBuff = {NULL, 0, 0}; #define RSYNC_LENGTH 32 -/* Don't create chunks smaller than the zstd block size. - * This stops us from regressing compression ratio too much, - * and ensures our output fits in ZSTD_compressBound(). - * - * If this is shrunk < ZSTD_BLOCKSIZELOG_MIN then - * ZSTD_COMPRESSBOUND() will need to be updated. - */ -#define RSYNC_MIN_BLOCK_LOG ZSTD_BLOCKSIZELOG_MAX -#define RSYNC_MIN_BLOCK_SIZE (1<params, nbWorkers); mtctx->cMem = cMem; mtctx->allJobsCompleted = 1; - if (pool != NULL) { - mtctx->factory = pool; - mtctx->providedFactory = 1; - } - else { - mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem); - mtctx->providedFactory = 0; - } + mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem); mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem); assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0); /* ensure nbJobs is a power of 2 */ mtctx->jobIDMask = nbJobs - 1; - mtctx->bufPool = ZSTDMT_createBufferPool(BUF_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); + mtctx->bufPool = ZSTDMT_createBufferPool(nbWorkers, cMem); mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem); mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem); initError = ZSTDMT_serialState_init(&mtctx->serial); @@ -959,18 +903,22 @@ MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers, return mtctx; } -ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool) +ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem) { #ifdef ZSTD_MULTITHREAD - return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem, pool); + return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem); #else (void)nbWorkers; (void)cMem; - (void)pool; return NULL; #endif } +ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers) +{ + return ZSTDMT_createCCtx_advanced(nbWorkers, ZSTD_defaultCMem); +} + /* ZSTDMT_releaseAllJobResources() : * note : ensure all workers are killed first ! */ @@ -987,7 +935,7 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); /* Clear the job description, but keep the mutex/cond */ - ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); + memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); mtctx->jobs[jobID].job_mutex = mutex; mtctx->jobs[jobID].job_cond = cond; } @@ -1014,8 +962,7 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx) size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) { if (mtctx==NULL) return 0; /* compatible with free on NULL */ - if (!mtctx->providedFactory) - POOL_free(mtctx->factory); /* stop and free worker threads */ + POOL_free(mtctx->factory); /* stop and free worker threads */ ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */ ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem); ZSTDMT_freeBufferPool(mtctx->bufPool); @@ -1024,8 +971,8 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) ZSTDMT_serialState_free(&mtctx->serial); ZSTD_freeCDict(mtctx->cdictLocal); if (mtctx->roundBuff.buffer) - ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); - ZSTD_customFree(mtctx, mtctx->cMem); + ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem); + ZSTD_free(mtctx, mtctx->cMem); return 0; } @@ -1042,14 +989,73 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) + mtctx->roundBuff.capacity; } +/* Internal only */ +size_t +ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, + ZSTDMT_parameter parameter, + int value) +{ + DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter"); + switch(parameter) + { + case ZSTDMT_p_jobSize : + DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %i", value); + return ZSTD_CCtxParams_setParameter(params, ZSTD_c_jobSize, value); + case ZSTDMT_p_overlapLog : + DEBUGLOG(4, "ZSTDMT_p_overlapLog : %i", value); + return ZSTD_CCtxParams_setParameter(params, ZSTD_c_overlapLog, value); + case ZSTDMT_p_rsyncable : + DEBUGLOG(4, "ZSTD_p_rsyncable : %i", value); + return ZSTD_CCtxParams_setParameter(params, ZSTD_c_rsyncable, value); + default : + return ERROR(parameter_unsupported); + } +} + +size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value) +{ + DEBUGLOG(4, "ZSTDMT_setMTCtxParameter"); + return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value); +} + +size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value) +{ + switch (parameter) { + case ZSTDMT_p_jobSize: + return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_jobSize, value); + case ZSTDMT_p_overlapLog: + return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_overlapLog, value); + case ZSTDMT_p_rsyncable: + return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_rsyncable, value); + default: + return ERROR(parameter_unsupported); + } +} + +/* Sets parameters relevant to the compression job, + * initializing others to default values. */ +static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(const ZSTD_CCtx_params* params) +{ + ZSTD_CCtx_params jobParams = *params; + /* Clear parameters related to multithreading */ + jobParams.forceWindow = 0; + jobParams.nbWorkers = 0; + jobParams.jobSize = 0; + jobParams.overlapLog = 0; + jobParams.rsyncable = 0; + memset(&jobParams.ldmParams, 0, sizeof(ldmParams_t)); + memset(&jobParams.customMem, 0, sizeof(ZSTD_customMem)); + return jobParams; +} + /* ZSTDMT_resize() : * @return : error code if fails, 0 on success */ static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers) { if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation); - FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbWorkers) , ""); - mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, BUF_POOL_MAX_NB_BUFFERS(nbWorkers)); + FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbWorkers) ); + mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, nbWorkers); if (mtctx->bufPool == NULL) return ERROR(memory_allocation); mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers); if (mtctx->cctxPool == NULL) return ERROR(memory_allocation); @@ -1070,7 +1076,7 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)", compressionLevel); mtctx->params.compressionLevel = compressionLevel; - { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, 0, 0); cParams.windowLog = saved_wlog; mtctx->params.cParams = cParams; } @@ -1154,11 +1160,11 @@ size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx) static unsigned ZSTDMT_computeTargetJobLog(const ZSTD_CCtx_params* params) { unsigned jobLog; - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + if (params->ldmParams.enableLdm) { /* In Long Range Mode, the windowLog is typically oversized. * In which case, it's preferable to determine the jobSize - * based on cycleLog instead. */ - jobLog = MAX(21, ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy) + 3); + * based on chainLog instead. */ + jobLog = MAX(21, params->cParams.chainLog + 4); } else { jobLog = MAX(20, params->cParams.windowLog + 2); } @@ -1198,7 +1204,7 @@ static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params) int const overlapRLog = 9 - ZSTDMT_overlapLog(params->overlapLog, params->cParams.strategy); int ovLog = (overlapRLog >= 8) ? 0 : (params->cParams.windowLog - overlapRLog); assert(0 <= overlapRLog && overlapRLog <= 8); - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + if (params->ldmParams.enableLdm) { /* In Long Range Mode, the windowLog is typically oversized. * In which case, it's preferable to determine the jobSize * based on chainLog instead. @@ -1212,6 +1218,172 @@ static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params) return (ovLog==0) ? 0 : (size_t)1 << ovLog; } +static unsigned +ZSTDMT_computeNbJobs(const ZSTD_CCtx_params* params, size_t srcSize, unsigned nbWorkers) +{ + assert(nbWorkers>0); + { size_t const jobSizeTarget = (size_t)1 << ZSTDMT_computeTargetJobLog(params); + size_t const jobMaxSize = jobSizeTarget << 2; + size_t const passSizeMax = jobMaxSize * nbWorkers; + unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1; + unsigned const nbJobsLarge = multiplier * nbWorkers; + unsigned const nbJobsMax = (unsigned)(srcSize / jobSizeTarget) + 1; + unsigned const nbJobsSmall = MIN(nbJobsMax, nbWorkers); + return (multiplier>1) ? nbJobsLarge : nbJobsSmall; +} } + +/* ZSTDMT_compress_advanced_internal() : + * This is a blocking function : it will only give back control to caller after finishing its compression job. + */ +static size_t ZSTDMT_compress_advanced_internal( + ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params) +{ + ZSTD_CCtx_params const jobParams = ZSTDMT_initJobCCtxParams(¶ms); + size_t const overlapSize = ZSTDMT_computeOverlapSize(¶ms); + unsigned const nbJobs = ZSTDMT_computeNbJobs(¶ms, srcSize, params.nbWorkers); + size_t const proposedJobSize = (srcSize + (nbJobs-1)) / nbJobs; + size_t const avgJobSize = (((proposedJobSize-1) & 0x1FFFF) < 0x7FFF) ? proposedJobSize + 0xFFFF : proposedJobSize; /* avoid too small last block */ + const char* const srcStart = (const char*)src; + size_t remainingSrcSize = srcSize; + unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbJobs : (unsigned)(dstCapacity / ZSTD_compressBound(avgJobSize)); /* presumes avgJobSize >= 256 KB, which should be the case */ + size_t frameStartPos = 0, dstBufferPos = 0; + assert(jobParams.nbWorkers == 0); + assert(mtctx->cctxPool->totalCCtx == params.nbWorkers); + + params.jobSize = (U32)avgJobSize; + DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbJobs=%2u (rawSize=%u bytes; fixedSize=%u) ", + nbJobs, (U32)proposedJobSize, (U32)avgJobSize); + + if ((nbJobs==1) | (params.nbWorkers<=1)) { /* fallback to single-thread mode : this is a blocking invocation anyway */ + ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; + DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: fallback to single-thread mode"); + if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, &jobParams); + } + + assert(avgJobSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */ + ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) ); + if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, avgJobSize)) + return ERROR(memory_allocation); + + FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbJobs) ); /* only expands if necessary */ + + { unsigned u; + for (u=0; ujobs[u].prefix.start = srcStart + frameStartPos - dictSize; + mtctx->jobs[u].prefix.size = dictSize; + mtctx->jobs[u].src.start = srcStart + frameStartPos; + mtctx->jobs[u].src.size = jobSize; assert(jobSize > 0); /* avoid job.src.size == 0 */ + mtctx->jobs[u].consumed = 0; + mtctx->jobs[u].cSize = 0; + mtctx->jobs[u].cdict = (u==0) ? cdict : NULL; + mtctx->jobs[u].fullFrameSize = srcSize; + mtctx->jobs[u].params = jobParams; + /* do not calculate checksum within sections, but write it in header for first section */ + mtctx->jobs[u].dstBuff = dstBuffer; + mtctx->jobs[u].cctxPool = mtctx->cctxPool; + mtctx->jobs[u].bufPool = mtctx->bufPool; + mtctx->jobs[u].seqPool = mtctx->seqPool; + mtctx->jobs[u].serial = &mtctx->serial; + mtctx->jobs[u].jobID = u; + mtctx->jobs[u].firstJob = (u==0); + mtctx->jobs[u].lastJob = (u==nbJobs-1); + + DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)jobSize); + DEBUG_PRINTHEX(6, mtctx->jobs[u].prefix.start, 12); + POOL_add(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[u]); + + frameStartPos += jobSize; + dstBufferPos += dstBufferCapacity; + remainingSrcSize -= jobSize; + } } + + /* collect result */ + { size_t error = 0, dstPos = 0; + unsigned jobID; + for (jobID=0; jobIDjobs[jobID].job_mutex); + while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) { + DEBUGLOG(5, "waiting for jobCompleted signal from job %u", jobID); + ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex); + } + ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex); + DEBUGLOG(5, "ready to write job %u ", jobID); + + { size_t const cSize = mtctx->jobs[jobID].cSize; + if (ZSTD_isError(cSize)) error = cSize; + if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall); + if (jobID) { /* note : job 0 is written directly at dst, which is correct position */ + if (!error) + memmove((char*)dst + dstPos, mtctx->jobs[jobID].dstBuff.start, cSize); /* may overlap when job compressed within dst */ + if (jobID >= compressWithinDst) { /* job compressed into its own buffer, which must be released */ + DEBUGLOG(5, "releasing buffer %u>=%u", jobID, compressWithinDst); + ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); + } } + mtctx->jobs[jobID].dstBuff = g_nullBuffer; + mtctx->jobs[jobID].cSize = 0; + dstPos += cSize ; + } + } /* for (jobID=0; jobIDserial.xxhState); + if (dstPos + 4 > dstCapacity) { + error = ERROR(dstSize_tooSmall); + } else { + DEBUGLOG(4, "writing checksum : %08X \n", checksum); + MEM_writeLE32((char*)dst + dstPos, checksum); + dstPos += 4; + } } + + if (!error) DEBUGLOG(4, "compressed size : %u ", (U32)dstPos); + return error ? error : dstPos; + } +} + +size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_parameters params, + int overlapLog) +{ + ZSTD_CCtx_params cctxParams = mtctx->params; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + assert(ZSTD_OVERLAPLOG_MIN <= overlapLog && overlapLog <= ZSTD_OVERLAPLOG_MAX); + cctxParams.overlapLog = overlapLog; + return ZSTDMT_compress_advanced_internal(mtctx, + dst, dstCapacity, + src, srcSize, + cdict, cctxParams); +} + + +size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel) +{ + ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0); + int const overlapLog = ZSTDMT_overlapLog_default(params.cParams.strategy); + params.fParams.contentSizeFlag = 1; + return ZSTDMT_compress_advanced(mtctx, dst, dstCapacity, src, srcSize, NULL, params, overlapLog); +} + + /* ====================================== */ /* ======= Streaming API ======= */ /* ====================================== */ @@ -1231,11 +1403,21 @@ size_t ZSTDMT_initCStream_internal( /* init */ if (params.nbWorkers != mtctx->params.nbWorkers) - FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) , ""); + FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) ); if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN; if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = (size_t)ZSTDMT_JOBSIZE_MAX; + mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */ + if (mtctx->singleBlockingThread) { + ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(¶ms); + DEBUGLOG(5, "ZSTDMT_initCStream_internal: switch to single blocking thread mode"); + assert(singleThreadParams.nbWorkers == 0); + return ZSTD_initCStream_internal(mtctx->cctxPool->cctx[0], + dict, dictSize, cdict, + &singleThreadParams, pledgedSrcSize); + } + DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers); if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */ @@ -1269,11 +1451,9 @@ size_t ZSTDMT_initCStream_internal( if (params.rsyncable) { /* Aim for the targetsectionSize as the average job size. */ - U32 const jobSizeKB = (U32)(mtctx->targetSectionSize >> 10); - U32 const rsyncBits = (assert(jobSizeKB >= 1), ZSTD_highbit32(jobSizeKB) + 10); - /* We refuse to create jobs < RSYNC_MIN_BLOCK_SIZE bytes, so make sure our - * expected job size is at least 4x larger. */ - assert(rsyncBits >= RSYNC_MIN_BLOCK_LOG + 2); + U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20); + U32 const rsyncBits = ZSTD_highbit32(jobSizeMB) + 20; + assert(jobSizeMB >= 1); DEBUGLOG(4, "rsyncLog = %u", rsyncBits); mtctx->rsync.hash = 0; mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1; @@ -1285,7 +1465,7 @@ size_t ZSTDMT_initCStream_internal( ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize)); { /* If ldm is enabled we need windowSize space. */ - size_t const windowSize = mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable ? (1U << mtctx->params.cParams.windowLog) : 0; + size_t const windowSize = mtctx->params.ldmParams.enableLdm ? (1U << mtctx->params.cParams.windowLog) : 0; /* Two buffers of slack, plus extra space for the overlap * This is the minimum slack that LDM works with. One extra because * flush might waste up to targetSectionSize-1 bytes. Another extra @@ -1300,8 +1480,8 @@ size_t ZSTDMT_initCStream_internal( size_t const capacity = MAX(windowSize, sectionsSize) + slackSize; if (mtctx->roundBuff.capacity < capacity) { if (mtctx->roundBuff.buffer) - ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); - mtctx->roundBuff.buffer = (BYTE*)ZSTD_customMalloc(capacity, mtctx->cMem); + ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem); + mtctx->roundBuff.buffer = (BYTE*)ZSTD_malloc(capacity, mtctx->cMem); if (mtctx->roundBuff.buffer == NULL) { mtctx->roundBuff.capacity = 0; return ERROR(memory_allocation); @@ -1320,12 +1500,58 @@ size_t ZSTDMT_initCStream_internal( mtctx->allJobsCompleted = 0; mtctx->consumed = 0; mtctx->produced = 0; - if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize, - dict, dictSize, dictContentType)) + if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize)) return ERROR(memory_allocation); return 0; } +size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, + const void* dict, size_t dictSize, + ZSTD_parameters params, + unsigned long long pledgedSrcSize) +{ + ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */ + DEBUGLOG(4, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize); + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dct_auto, NULL, + cctxParams, pledgedSrcSize); +} + +size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize) +{ + ZSTD_CCtx_params cctxParams = mtctx->params; + if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ + cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict); + cctxParams.fParams = fParams; + return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dct_auto, cdict, + cctxParams, pledgedSrcSize); +} + + +/* ZSTDMT_resetCStream() : + * pledgedSrcSize can be zero == unknown (for the time being) + * prefer using ZSTD_CONTENTSIZE_UNKNOWN, + * as `0` might mean "empty" in the future */ +size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize) +{ + if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; + return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, 0, mtctx->params, + pledgedSrcSize); +} + +size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel) { + ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0); + ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */ + DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel); + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN); +} + /* ZSTDMT_writeLastEmptyBlock() * Write a single empty block with an end-of-frame to finish a frame. @@ -1488,11 +1714,9 @@ static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, u assert(mtctx->doneJobID < mtctx->nextJobID); assert(cSize >= mtctx->jobs[wJobID].dstFlushed); assert(mtctx->jobs[wJobID].dstBuff.start != NULL); - if (toFlush > 0) { - ZSTD_memcpy((char*)output->dst + output->pos, - (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed, - toFlush); - } + memcpy((char*)output->dst + output->pos, + (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed, + toFlush); output->pos += toFlush; mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */ @@ -1560,21 +1784,17 @@ static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx) static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range) { BYTE const* const bufferStart = (BYTE const*)buffer.start; + BYTE const* const bufferEnd = bufferStart + buffer.capacity; BYTE const* const rangeStart = (BYTE const*)range.start; + BYTE const* const rangeEnd = rangeStart + range.size; if (rangeStart == NULL || bufferStart == NULL) return 0; + /* Empty ranges cannot overlap */ + if (bufferStart == bufferEnd || rangeStart == rangeEnd) + return 0; - { - BYTE const* const bufferEnd = bufferStart + buffer.capacity; - BYTE const* const rangeEnd = rangeStart + range.size; - - /* Empty ranges cannot overlap */ - if (bufferStart == bufferEnd || rangeStart == rangeEnd) - return 0; - - return bufferStart < rangeEnd && rangeStart < bufferEnd; - } + return bufferStart < rangeEnd && rangeStart < bufferEnd; } static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window) @@ -1601,7 +1821,7 @@ static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window) static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer) { - if (mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable) { + if (mtctx->params.ldmParams.enableLdm) { ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex; DEBUGLOG(5, "ZSTDMT_waitForLdmComplete"); DEBUGLOG(5, "source [0x%zx, 0x%zx)", @@ -1647,7 +1867,7 @@ static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx) return 0; } ZSTDMT_waitForLdmComplete(mtctx, buffer); - ZSTD_memmove(start, mtctx->inBuff.prefix.start, prefixSize); + memmove(start, mtctx->inBuff.prefix.start, prefixSize); mtctx->inBuff.prefix.start = start; mtctx->roundBuff.pos = prefixSize; } @@ -1704,11 +1924,6 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) if (!mtctx->params.rsyncable) /* Rsync is disabled. */ return syncPoint; - if (mtctx->inBuff.filled + input.size - input.pos < RSYNC_MIN_BLOCK_SIZE) - /* We don't emit synchronization points if it would produce too small blocks. - * We don't have enough input to find a synchronization point, so don't look. - */ - return syncPoint; if (mtctx->inBuff.filled + syncPoint.toLoad < RSYNC_LENGTH) /* Not enough to compute the hash. * We will miss any synchronization points in this RSYNC_LENGTH byte @@ -1719,41 +1934,23 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) */ return syncPoint; /* Initialize the loop variables. */ - if (mtctx->inBuff.filled < RSYNC_MIN_BLOCK_SIZE) { - /* We don't need to scan the first RSYNC_MIN_BLOCK_SIZE positions - * because they can't possibly be a sync point. So we can start - * part way through the input buffer. - */ - pos = RSYNC_MIN_BLOCK_SIZE - mtctx->inBuff.filled; - if (pos >= RSYNC_LENGTH) { - prev = istart + pos - RSYNC_LENGTH; - hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); - } else { - assert(mtctx->inBuff.filled >= RSYNC_LENGTH); - prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; - hash = ZSTD_rollingHash_compute(prev + pos, (RSYNC_LENGTH - pos)); - hash = ZSTD_rollingHash_append(hash, istart, pos); - } - } else { - /* We have enough bytes buffered to initialize the hash, - * and have processed enough bytes to find a sync point. + if (mtctx->inBuff.filled >= RSYNC_LENGTH) { + /* We have enough bytes buffered to initialize the hash. * Start scanning at the beginning of the input. */ - assert(mtctx->inBuff.filled >= RSYNC_MIN_BLOCK_SIZE); - assert(RSYNC_MIN_BLOCK_SIZE >= RSYNC_LENGTH); pos = 0; prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); - if ((hash & hitMask) == hitMask) { - /* We're already at a sync point so don't load any more until - * we're able to flush this sync point. - * This likely happened because the job table was full so we - * couldn't add our job. - */ - syncPoint.toLoad = 0; - syncPoint.flush = 1; - return syncPoint; - } + } else { + /* We don't have enough bytes buffered to initialize the hash, but + * we know we have at least RSYNC_LENGTH bytes total. + * Start scanning after the first RSYNC_LENGTH bytes less the bytes + * already buffered. + */ + pos = RSYNC_LENGTH - mtctx->inBuff.filled; + prev = (BYTE const*)mtctx->inBuff.buffer.start - pos; + hash = ZSTD_rollingHash_compute(mtctx->inBuff.buffer.start, mtctx->inBuff.filled); + hash = ZSTD_rollingHash_append(hash, istart, pos); } /* Starting with the hash of the previous RSYNC_LENGTH bytes, roll * through the input. If we hit a synchronization point, then cut the @@ -1763,24 +1960,16 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) * then a block will be emitted anyways, but this is okay, since if we * are already synchronized we will remain synchronized. */ - assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); for (; pos < syncPoint.toLoad; ++pos) { BYTE const toRemove = pos < RSYNC_LENGTH ? prev[pos] : istart[pos - RSYNC_LENGTH]; - /* This assert is very expensive, and Debian compiles with asserts enabled. - * So disable it for now. We can get similar coverage by checking it at the - * beginning & end of the loop. - * assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); - */ + /* if (pos >= RSYNC_LENGTH) assert(ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); */ hash = ZSTD_rollingHash_rotate(hash, toRemove, istart[pos], primePower); - assert(mtctx->inBuff.filled + pos >= RSYNC_MIN_BLOCK_SIZE); if ((hash & hitMask) == hitMask) { syncPoint.toLoad = pos + 1; syncPoint.flush = 1; - ++pos; /* for assert */ break; } } - assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); return syncPoint; } @@ -1806,11 +1995,34 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, assert(output->pos <= output->size); assert(input->pos <= input->size); + if (mtctx->singleBlockingThread) { /* delegate to single-thread (synchronous) */ + return ZSTD_compressStream2(mtctx->cctxPool->cctx[0], output, input, endOp); + } + if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { /* current frame being ended. Only flush/end are allowed */ return ERROR(stage_wrong); } + /* single-pass shortcut (note : synchronous-mode) */ + if ( (!mtctx->params.rsyncable) /* rsyncable mode is disabled */ + && (mtctx->nextJobID == 0) /* just started */ + && (mtctx->inBuff.filled == 0) /* nothing buffered */ + && (!mtctx->jobReady) /* no job already created */ + && (endOp == ZSTD_e_end) /* end order */ + && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough space in dst */ + size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx, + (char*)output->dst + output->pos, output->size - output->pos, + (const char*)input->src + input->pos, input->size - input->pos, + mtctx->cdict, mtctx->params); + if (ZSTD_isError(cSize)) return cSize; + input->pos = input->size; + output->pos += cSize; + mtctx->allJobsCompleted = 1; + mtctx->frameEnded = 1; + return 0; + } + /* fill input buffer */ if ( (!mtctx->jobReady) && (input->size > input->pos) ) { /* support NULL input */ @@ -1833,21 +2045,13 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize); DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u", (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize); - ZSTD_memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad); + memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad); input->pos += syncPoint.toLoad; mtctx->inBuff.filled += syncPoint.toLoad; forwardInputProgress = syncPoint.toLoad>0; } - } - if ((input->pos < input->size) && (endOp == ZSTD_e_end)) { - /* Can't end yet because the input is not fully consumed. - * We are in one of these cases: - * - mtctx->inBuff is NULL & empty: we couldn't get an input buffer so don't create a new job. - * - We filled the input buffer: flush this job but don't end the frame. - * - We hit a synchronization point: flush this job but don't end the frame. - */ - assert(mtctx->inBuff.filled == 0 || mtctx->inBuff.filled == mtctx->targetSectionSize || mtctx->params.rsyncable); - endOp = ZSTD_e_flush; + if ((input->pos < input->size) && (endOp == ZSTD_e_end)) + endOp = ZSTD_e_flush; /* can't end now : not all input consumed */ } if ( (mtctx->jobReady) @@ -1856,7 +2060,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, || ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) { /* must finish the frame with a zero-size block */ size_t const jobSize = mtctx->inBuff.filled; assert(mtctx->inBuff.filled <= mtctx->targetSectionSize); - FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) , ""); + FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) ); } /* check for potential compressed data ready to be flushed */ @@ -1867,4 +2071,46 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, } } -#endif /* USE_EXTERNAL_ZSTD */ + +size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +{ + FORWARD_IF_ERROR( ZSTDMT_compressStream_generic(mtctx, output, input, ZSTD_e_continue) ); + + /* recommended next input size : fill current input buffer */ + return mtctx->targetSectionSize - mtctx->inBuff.filled; /* note : could be zero when input buffer is fully filled and no more availability to create new job */ +} + + +static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_EndDirective endFrame) +{ + size_t const srcSize = mtctx->inBuff.filled; + DEBUGLOG(5, "ZSTDMT_flushStream_internal"); + + if ( mtctx->jobReady /* one job ready for a worker to pick up */ + || (srcSize > 0) /* still some data within input buffer */ + || ((endFrame==ZSTD_e_end) && !mtctx->frameEnded)) { /* need a last 0-size block to end frame */ + DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job (%u bytes, end:%u)", + (U32)srcSize, (U32)endFrame); + FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) ); + } + + /* check if there is any data available to flush */ + return ZSTDMT_flushProduced(mtctx, output, 1 /* blockToFlush */, endFrame); +} + + +size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output) +{ + DEBUGLOG(5, "ZSTDMT_flushStream"); + if (mtctx->singleBlockingThread) + return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output); + return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_flush); +} + +size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output) +{ + DEBUGLOG(4, "ZSTDMT_endStream"); + if (mtctx->singleBlockingThread) + return ZSTD_endStream(mtctx->cctxPool->cctx[0], output); + return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_end); +} diff --git a/vendor/github.com/DataDog/zstd/zstdmt_compress.h b/vendor/github.com/DataDog/zstd/zstdmt_compress.h index 3485e0de..12a52608 100644 --- a/vendor/github.com/DataDog/zstd/zstdmt_compress.h +++ b/vendor/github.com/DataDog/zstd/zstdmt_compress.h @@ -1,6 +1,5 @@ -#ifndef USE_EXTERNAL_ZSTD /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,60 +19,113 @@ /* Note : This is an internal API. * These APIs used to be exposed with ZSTDLIB_API, * because it used to be the only way to invoke MT compression. - * Now, you must use ZSTD_compress2 and ZSTD_compressStream2() instead. + * Now, it's recommended to use ZSTD_compress2 and ZSTD_compressStream2() + * instead. + * + * If you depend on these APIs and can't switch, then define + * ZSTD_LEGACY_MULTITHREADED_API when making the dynamic library. + * However, we may completely remove these functions in a future + * release, so please switch soon. * * This API requires ZSTD_MULTITHREAD to be defined during compilation, * otherwise ZSTDMT_createCCtx*() will fail. */ +#ifdef ZSTD_LEGACY_MULTITHREADED_API +# define ZSTDMT_API ZSTDLIB_API +#else +# define ZSTDMT_API +#endif + /* === Dependencies === */ -#include "zstd_deps.h" /* size_t */ +#include /* size_t */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */ #include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ /* === Constants === */ -#ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */ -# define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256) +#ifndef ZSTDMT_NBWORKERS_MAX +# define ZSTDMT_NBWORKERS_MAX 200 #endif -#ifndef ZSTDMT_JOBSIZE_MIN /* a different value can be selected at compile time */ -# define ZSTDMT_JOBSIZE_MIN (512 KB) +#ifndef ZSTDMT_JOBSIZE_MIN +# define ZSTDMT_JOBSIZE_MIN (1 MB) #endif #define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30) #define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB)) -/* ======================================================== - * === Private interface, for use by ZSTD_compress.c === - * === Not exposed in libzstd. Never invoke directly === - * ======================================================== */ - /* === Memory management === */ typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx; /* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ -ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, - ZSTD_customMem cMem, - ZSTD_threadPool *pool); -size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); +ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers); +/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ +ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, + ZSTD_customMem cMem); +ZSTDMT_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); + +ZSTDMT_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); + + +/* === Simple one-pass compression function === */ + +ZSTDMT_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + -size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); /* === Streaming functions === */ -size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); +ZSTDMT_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel); +ZSTDMT_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */ + +ZSTDMT_API size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); +ZSTDMT_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input); + +ZSTDMT_API size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */ +ZSTDMT_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */ + + +/* === Advanced functions and parameters === */ + +ZSTDMT_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_parameters params, + int overlapLog); + +ZSTDMT_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, + const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */ + ZSTD_parameters params, + unsigned long long pledgedSrcSize); /* pledgedSrcSize is optional and can be zero == unknown */ + +ZSTDMT_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fparams, + unsigned long long pledgedSrcSize); /* note : zero means empty */ + +/* ZSTDMT_parameter : + * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */ +typedef enum { + ZSTDMT_p_jobSize, /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */ + ZSTDMT_p_overlapLog, /* Each job may reload a part of previous job to enhance compression ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window. This is a "sticky" parameter : its value will be re-used on next compression job */ + ZSTDMT_p_rsyncable /* Enables rsyncable mode. */ +} ZSTDMT_parameter; + +/* ZSTDMT_setMTCtxParameter() : + * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter. + * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__ + * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) */ +ZSTDMT_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value); + +/* ZSTDMT_getMTCtxParameter() : + * Query the ZSTDMT_CCtx for a parameter value. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) */ +ZSTDMT_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value); -/*! ZSTDMT_initCStream_internal() : - * Private use only. Init streaming operation. - * expects params to be valid. - * must receive dict, or cdict, or none, but not both. - * mtctx can be freshly constructed or reused from a prior compression. - * If mtctx is reused, memory allocations from the prior compression may not be freed, - * even if they are not needed for the current compression. - * @return : 0, or an error code */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* mtctx, - const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); /*! ZSTDMT_compressStream_generic() : * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream() @@ -82,10 +134,16 @@ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* mtctx, * 0 if fully flushed * or an error code * note : needs to be init using any ZSTD_initCStream*() variant */ -size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, - ZSTD_outBuffer* output, - ZSTD_inBuffer* input, - ZSTD_EndDirective endOp); +ZSTDMT_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + + +/* ======================================================== + * === Private interface, for use by ZSTD_compress.c === + * === Not exposed in libzstd. Never invoke directly === + * ======================================================== */ /*! ZSTDMT_toFlushNow() * Tell how many bytes are ready to be flushed immediately. @@ -95,6 +153,15 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, * therefore flushing is limited by speed of oldest job. */ size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx); +/*! ZSTDMT_CCtxParam_setMTCtxParameter() + * like ZSTDMT_setMTCtxParameter(), but into a ZSTD_CCtx_Params */ +size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, int value); + +/*! ZSTDMT_CCtxParam_setNbWorkers() + * Set nbWorkers, and clamp it. + * Also reset jobSize and overlapLog */ +size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers); + /*! ZSTDMT_updateCParams_whileCompressing() : * Updates only a selected set of compression parameters, to remain compatible with current frame. * New parameters will be applied to next compression job. */ @@ -107,10 +174,19 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx); +/*! ZSTDMT_initCStream_internal() : + * Private use only. Init streaming operation. + * expects params to be valid. + * must receive dict, or cdict, or none, but not both. + * @return : 0, or an error code */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, + const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); + + #if defined (__cplusplus) } #endif #endif /* ZSTDMT_COMPRESS_H */ - -#endif /* USE_EXTERNAL_ZSTD */ diff --git a/vendor/github.com/yusufpapurcu/wmi/LICENSE b/vendor/github.com/StackExchange/wmi/LICENSE similarity index 100% rename from vendor/github.com/yusufpapurcu/wmi/LICENSE rename to vendor/github.com/StackExchange/wmi/LICENSE diff --git a/vendor/github.com/StackExchange/wmi/README.md b/vendor/github.com/StackExchange/wmi/README.md new file mode 100644 index 00000000..c4a432d6 --- /dev/null +++ b/vendor/github.com/StackExchange/wmi/README.md @@ -0,0 +1,13 @@ +wmi +=== + +Package wmi provides a WQL interface to Windows WMI. + +Note: It interfaces with WMI on the local machine, therefore it only runs on Windows. + +--- + +NOTE: This project is no longer being actively maintained. If you would like +to become its new owner, please contact tlimoncelli at stack over flow dot com. + +--- diff --git a/vendor/github.com/yusufpapurcu/wmi/swbemservices.go b/vendor/github.com/StackExchange/wmi/swbemservices.go similarity index 99% rename from vendor/github.com/yusufpapurcu/wmi/swbemservices.go rename to vendor/github.com/StackExchange/wmi/swbemservices.go index a250c846..3ff87563 100644 --- a/vendor/github.com/yusufpapurcu/wmi/swbemservices.go +++ b/vendor/github.com/StackExchange/wmi/swbemservices.go @@ -1,4 +1,3 @@ -//go:build windows // +build windows package wmi diff --git a/vendor/github.com/yusufpapurcu/wmi/wmi.go b/vendor/github.com/StackExchange/wmi/wmi.go similarity index 98% rename from vendor/github.com/yusufpapurcu/wmi/wmi.go rename to vendor/github.com/StackExchange/wmi/wmi.go index 03f386ed..b4bb4f09 100644 --- a/vendor/github.com/yusufpapurcu/wmi/wmi.go +++ b/vendor/github.com/StackExchange/wmi/wmi.go @@ -1,4 +1,3 @@ -//go:build windows // +build windows /* @@ -21,6 +20,7 @@ Example code to print names of running processes: println(i, v.Name) } } + */ package wmi @@ -338,6 +338,11 @@ func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismat f := v.Field(i) of := f isPtr := f.Kind() == reflect.Ptr + if isPtr { + ptr := reflect.New(f.Type().Elem()) + f.Set(ptr) + f = f.Elem() + } n := v.Type().Field(i).Name if n[0] < 'A' || n[0] > 'Z' { continue @@ -362,12 +367,6 @@ func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismat } defer prop.Clear() - if isPtr && !(c.PtrNil && prop.VT == 0x1) { - ptr := reflect.New(f.Type().Elem()) - f.Set(ptr) - f = f.Elem() - } - if prop.VT == 0x1 { //VT_NULL continue } @@ -456,18 +455,6 @@ func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismat Reason: "not a Float32", } } - case float64: - switch f.Kind() { - case reflect.Float32, reflect.Float64: - f.SetFloat(val) - default: - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "not a Float64", - } - } - default: if f.Kind() == reflect.Slice { switch f.Type().Elem().Kind() { diff --git a/vendor/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md index fe7bca65..848234e2 100644 --- a/vendor/github.com/bits-and-blooms/bitset/README.md +++ b/vendor/github.com/bits-and-blooms/bitset/README.md @@ -127,13 +127,6 @@ E.g., The memory usage of a bitset using `N` bits is at least `N/8` bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). -The `roaring` library allows you to go back and forth between compressed Roaring bitmaps and the conventional bitset instances: -```Go - mybitset := roaringbitmap.ToBitSet() - newroaringbitmap := roaring.FromBitSet(mybitset) -``` - - ## Implementation Note Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go index 9f38ed3a..43a0dacf 100644 --- a/vendor/github.com/bits-and-blooms/bitset/bitset.go +++ b/vendor/github.com/bits-and-blooms/bitset/bitset.go @@ -94,17 +94,17 @@ func (b *BitSet) SetBitsetFrom(buf []uint64) { b.set = buf } -// From is a constructor used to create a BitSet from an array of words +// From is a constructor used to create a BitSet from an array of integers func From(buf []uint64) *BitSet { return FromWithLength(uint(len(buf))*64, buf) } -// FromWithLength constructs from an array of words and length. +// FromWithLength constructs from an array of integers and length. func FromWithLength(len uint, set []uint64) *BitSet { return &BitSet{len, set} } -// Bytes returns the bitset as array of words +// Bytes returns the bitset as array of integers func (b *BitSet) Bytes() []uint64 { return b.set } @@ -247,13 +247,8 @@ func (b *BitSet) FlipRange(start, end uint) *BitSet { var startWord uint = start >> log2WordSize var endWord uint = end >> log2WordSize b.set[startWord] ^= ^(^uint64(0) << wordsIndex(start)) - if endWord > 0 { - // bounds check elimination - data := b.set - _ = data[endWord-1] - for i := startWord; i < endWord; i++ { - data[i] = ^data[i] - } + for i := startWord; i < endWord; i++ { + b.set[i] = ^b.set[i] } if end&(wordSize-1) != 0 { b.set[endWord] ^= ^uint64(0) >> wordsIndex(-end) @@ -432,16 +427,12 @@ func (b *BitSet) NextSet(i uint) (uint, bool) { if w != 0 { return i + trailingZeroes64(w), true } - x++ - // bounds check elimination in the loop - if x < 0 { - return 0, false - } + x = x + 1 for x < len(b.set) { if b.set[x] != 0 { return uint(x)*wordSize + trailingZeroes64(b.set[x]), true } - x++ + x = x + 1 } return 0, false @@ -525,16 +516,10 @@ func (b *BitSet) NextClear(i uint) (uint, bool) { return index, true } x++ - // bounds check elimination in the loop - if x < 0 { - return 0, false - } for x < len(b.set) { - if b.set[x] != allBits { - index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) - if index < b.length { - return index, true - } + index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) + if b.set[x] != allBits && index < b.length { + return index, true } x++ } @@ -551,18 +536,6 @@ func (b *BitSet) ClearAll() *BitSet { return b } -// SetAll sets the entire BitSet -func (b *BitSet) SetAll() *BitSet { - if b != nil && b.set != nil { - for i := range b.set { - b.set[i] = allBits - } - - b.cleanLastWord() - } - return b -} - // wordCount returns the number of words used in a bit set func (b *BitSet) wordCount() int { return wordsNeededUnbound(b.length) @@ -642,12 +615,6 @@ func (b *BitSet) Equal(c *BitSet) bool { return true } wn := b.wordCount() - // bounds check elimination - if wn <= 0 { - return true - } - _ = b.set[wn-1] - _ = c.set[wn-1] for p := 0; p < wn; p++ { if c.set[p] != b.set[p] { return false @@ -668,9 +635,9 @@ func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { panicIfNull(b) panicIfNull(compare) result = b.Clone() // clone b (in case b is bigger than compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) } for i := 0; i < l; i++ { result.set[i] = b.set[i] &^ compare.set[i] @@ -682,9 +649,9 @@ func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) } cnt := uint64(0) cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) @@ -697,19 +664,12 @@ func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceDifference(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) } - if l <= 0 { - return - } - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] for i := 0; i < l; i++ { - data[i] &^= cmpData[i] + b.set[i] &^= compare.set[i] } } @@ -752,24 +712,15 @@ func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceIntersection(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - if l > 0 { - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - - for i := 0; i < l; i++ { - data[i] &= cmpData[i] - } + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) } - if l >= 0 { - for i := l; i < len(b.set); i++ { - b.set[i] = 0 - } + for i := 0; i < l; i++ { + b.set[i] &= compare.set[i] + } + for i := l; i < len(b.set); i++ { + b.set[i] = 0 } if compare.length > 0 { if compare.length-1 >= b.length { @@ -809,22 +760,15 @@ func (b *BitSet) UnionCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceUnion(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) } if compare.length > 0 && compare.length-1 >= b.length { b.extendSet(compare.length - 1) } - if l > 0 { - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - - for i := 0; i < l; i++ { - data[i] |= cmpData[i] - } + for i := 0; i < l; i++ { + b.set[i] |= compare.set[i] } if len(compare.set) > l { for i := l; i < len(compare.set); i++ { @@ -864,21 +808,15 @@ func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) } if compare.length > 0 && compare.length-1 >= b.length { b.extendSet(compare.length - 1) } - if l > 0 { - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - for i := 0; i < l; i++ { - data[i] ^= cmpData[i] - } + for i := 0; i < l; i++ { + b.set[i] ^= compare.set[i] } if len(compare.set) > l { for i := l; i < len(compare.set); i++ { @@ -939,16 +877,12 @@ func (b *BitSet) Any() bool { // IsSuperSet returns true if this is a superset of the other set func (b *BitSet) IsSuperSet(other *BitSet) bool { - l := other.wordCount() - if b.wordCount() < l { - l = b.wordCount() - } - for i, word := range other.set[:l] { - if b.set[i]&word != word { + for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) { + if !b.Test(i) { return false } } - return popcntSlice(other.set[l:]) == 0 + return true } // IsStrictSuperSet returns true if this is a strict superset of the other set @@ -956,8 +890,7 @@ func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { return b.Count() > other.Count() && b.IsSuperSet(other) } -// DumpAsBits dumps a bit set as a string of bits. Following the usual convention in Go, -// the least significant bits are printed last (index 0 is at the end of the string). +// DumpAsBits dumps a bit set as a string of bits func (b *BitSet) DumpAsBits() string { if b.set == nil { return "." @@ -1148,37 +1081,3 @@ func (b *BitSet) UnmarshalJSON(data []byte) error { _, err = b.ReadFrom(bytes.NewReader(buf)) return err } - -// Rank returns the nunber of set bits up to and including the index -// that are set in the bitset. -// See https://en.wikipedia.org/wiki/Ranking#Ranking_in_statistics -func (b *BitSet) Rank(index uint) uint { - if index >= b.length { - return b.Count() - } - leftover := (index + 1) & 63 - answer := uint(popcntSlice(b.set[:(index+1)>>6])) - if leftover != 0 { - answer += uint(popcount(b.set[(index+1)>>6] << (64 - leftover))) - } - return answer -} - -// Select returns the index of the jth set bit, where j is the argument. -// The caller is responsible to ensure that 0 <= j < Count(): when j is -// out of range, the function returns the length of the bitset (b.length). -// -// Note that this function differs in convention from the Rank function which -// returns 1 when ranking the smallest value. We follow the conventional -// textbook definition of Select and Rank. -func (b *BitSet) Select(index uint) uint { - leftover := index - for idx, word := range b.set { - w := uint(popcount(word)) - if w > leftover { - return uint(idx)*64 + select64(word, leftover) - } - leftover -= w - } - return b.length -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go index 7855c04b..9a3766a0 100644 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go @@ -15,10 +15,6 @@ func popcntSlice(s []uint64) uint64 { func popcntMaskSlice(s, m []uint64) uint64 { var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } for i := range s { cnt += bits.OnesCount64(s[i] &^ m[i]) } @@ -27,10 +23,6 @@ func popcntMaskSlice(s, m []uint64) uint64 { func popcntAndSlice(s, m []uint64) uint64 { var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } for i := range s { cnt += bits.OnesCount64(s[i] & m[i]) } @@ -39,10 +31,6 @@ func popcntAndSlice(s, m []uint64) uint64 { func popcntOrSlice(s, m []uint64) uint64 { var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } for i := range s { cnt += bits.OnesCount64(s[i] | m[i]) } @@ -51,10 +39,6 @@ func popcntOrSlice(s, m []uint64) uint64 { func popcntXorSlice(s, m []uint64) uint64 { var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } for i := range s { cnt += bits.OnesCount64(s[i] ^ m[i]) } diff --git a/vendor/github.com/bits-and-blooms/bitset/select.go b/vendor/github.com/bits-and-blooms/bitset/select.go deleted file mode 100644 index f15e74a2..00000000 --- a/vendor/github.com/bits-and-blooms/bitset/select.go +++ /dev/null @@ -1,45 +0,0 @@ -package bitset - -func select64(w uint64, j uint) uint { - seen := 0 - // Divide 64bit - part := w & 0xFFFFFFFF - n := uint(popcount(part)) - if n <= j { - part = w >> 32 - seen += 32 - j -= n - } - ww := part - - // Divide 32bit - part = ww & 0xFFFF - - n = uint(popcount(part)) - if n <= j { - part = ww >> 16 - seen += 16 - j -= n - } - ww = part - - // Divide 16bit - part = ww & 0xFF - n = uint(popcount(part)) - if n <= j { - part = ww >> 8 - seen += 8 - j -= n - } - ww = part - - // Lookup in final byte - counter := 0 - for ; counter < 8; counter++ { - j -= uint((ww >> counter) & 1) - if j+1 == 0 { - break - } - } - return uint(seen + counter) -} diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE b/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE index 46dcd395..23190bab 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2013-2023 The btcsuite developers +Copyright (c) 2013-2022 The btcsuite developers Copyright (c) 2015-2016 The Decred developers Permission to use, copy, modify, and distribute this software for any diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/README.md b/vendor/github.com/btcsuite/btcd/btcec/v2/README.md index 53391773..cbf63dd0 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/README.md +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/README.md @@ -10,7 +10,7 @@ Bitcoin (secp256k1 only for now). It is designed so that it may be used with the standard crypto/ecdsa packages provided with go. A comprehensive suite of test is provided to ensure proper functionality. Package btcec was originally based on work from ThePiachu which is licensed under the same terms as Go, but it has -significantly diverged since then. The btcsuite developers original is licensed +signficantly diverged since then. The btcsuite developers original is licensed under the liberal ISC license. Although this package was primarily written for btcd, it has intentionally been diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go b/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go index f85baba8..efde8d6a 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go @@ -39,18 +39,3 @@ type CurveParams = secp.CurveParams func Params() *CurveParams { return secp.Params() } - -// Generator returns the public key at the Generator Point. -func Generator() *PublicKey { - var ( - result JacobianPoint - k secp.ModNScalar - ) - - k.SetInt(1) - ScalarBaseMultNonConst(&k, &result) - - result.ToAffine() - - return NewPublicKey(&result.X, &result.Y) -} diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go b/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go index 70a9229f..5224e35c 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go @@ -4,8 +4,6 @@ package btcec import ( - "fmt" - secp "github.com/decred/dcrd/dcrec/secp256k1/v4" ) @@ -13,9 +11,6 @@ import ( // Jacobian projective coordinates and thus represents a point on the curve. type JacobianPoint = secp.JacobianPoint -// infinityPoint is the jacobian representation of the point at infinity. -var infinityPoint JacobianPoint - // MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z // coordinates. func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint { @@ -66,50 +61,3 @@ func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { secp.ScalarMultNonConst(k, point, result) } - -// ParseJacobian parses a byte slice point as a secp.Publickey and returns the -// pubkey as a JacobianPoint. If the nonce is a zero slice, the infinityPoint -// is returned. -func ParseJacobian(point []byte) (JacobianPoint, error) { - var result JacobianPoint - - if len(point) != 33 { - str := fmt.Sprintf("invalid nonce: invalid length: %v", - len(point)) - return JacobianPoint{}, makeError(secp.ErrPubKeyInvalidLen, str) - } - - if point[0] == 0x00 { - return infinityPoint, nil - } - - noncePk, err := secp.ParsePubKey(point) - if err != nil { - return JacobianPoint{}, err - } - noncePk.AsJacobian(&result) - - return result, nil -} - -// JacobianToByteSlice converts the passed JacobianPoint to a Pubkey -// and serializes that to a byte slice. If the JacobianPoint is the infinity -// point, a zero slice is returned. -func JacobianToByteSlice(point JacobianPoint) []byte { - if point.X == infinityPoint.X && point.Y == infinityPoint.Y { - return make([]byte, 33) - } - - point.ToAffine() - - return NewPublicKey( - &point.X, &point.Y, - ).SerializeCompressed() -} - -// GeneratorJacobian sets the passed JacobianPoint to the Generator Point. -func GeneratorJacobian(jacobian *JacobianPoint) { - var k ModNScalar - k.SetInt(1) - ScalarBaseMultNonConst(&k, jacobian) -} diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go b/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go index 11c6267c..092e4ceb 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go @@ -37,20 +37,10 @@ var ( oneInitializer = []byte{0x01} ) -const ( - // MinSigLen is the minimum length of a DER encoded signature and is when both R - // and S are 1 byte each. - // 0x30 + <1-byte> + 0x02 + 0x01 + + 0x2 + 0x01 + - MinSigLen = 8 - - // MaxSigLen is the maximum length of a DER encoded signature and is - // when both R and S are 33 bytes each. It is 33 bytes because a - // 256-bit integer requires 32 bytes and an additional leading null byte - // might be required if the high bit is set in the value. - // - // 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes> - MaxSigLen = 72 -) +// MinSigLen is the minimum length of a DER encoded signature and is when both R +// and S are 1 byte each. +// 0x30 + <1-byte> + 0x02 + 0x01 + + 0x2 + 0x01 + +const MinSigLen = 8 // canonicalPadding checks whether a big-endian encoded integer could // possibly be misinterpreted as a negative number (even though OpenSSL @@ -78,15 +68,9 @@ func parseSig(sigStr []byte, der bool) (*Signature, error) { // 0x30 <0x02> 0x2 // . - // The signature must adhere to the minimum and maximum allowed length. - totalSigLen := len(sigStr) - if totalSigLen < MinSigLen { + if len(sigStr) < MinSigLen { return nil, errors.New("malformed signature: too short") } - if der && totalSigLen > MaxSigLen { - return nil, errors.New("malformed signature: too long") - } - // 0x30 index := 0 if sigStr[index] != 0x30 { @@ -212,7 +196,7 @@ func parseSig(sigStr []byte, der bool) (*Signature, error) { } // ParseSignature parses a signature in BER format for the curve type `curve' -// into a Signature type, performing some basic sanity checks. If parsing +// into a Signature type, perfoming some basic sanity checks. If parsing // according to the more strict DER format is needed, use ParseDERSignature. func ParseSignature(sigStr []byte) (*Signature, error) { return parseSig(sigStr, false) diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/error.go b/vendor/github.com/btcsuite/btcd/btcec/v2/error.go index df6ec678..81ca2b04 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/error.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/error.go @@ -17,8 +17,3 @@ type Error = secp.Error // errors.As, so the caller can directly check against an error kind when // determining the reason for an error. type ErrorKind = secp.ErrorKind - -// makeError creates an secp.Error given a set of arguments. -func makeError(kind ErrorKind, desc string) Error { - return Error{Err: kind, Description: desc} -} diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go b/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go index 939b0c17..b18b2c1d 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go @@ -11,7 +11,7 @@ import ( // arithmetic over the secp256k1 group order. This means all arithmetic is // performed modulo: // -// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 // // It only implements the arithmetic needed for elliptic curve operations, // however, the operations that are not implemented can typically be worked diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go b/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go index d0dbd8d9..4efa806c 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go @@ -9,7 +9,7 @@ import ( ) // PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing -// things with the private key without having to directly import the ecdsa +// things with the the private key without having to directly import the ecdsa // package. type PrivateKey = secp.PrivateKey diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go b/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go index 2c3a5ccb..7968ed04 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go +++ b/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go @@ -10,8 +10,6 @@ import ( // These constants define the lengths of serialized public keys. const ( - // PubKeyBytesLenCompressed is the bytes length of a serialized compressed - // public key. PubKeyBytesLenCompressed = 33 ) @@ -21,7 +19,7 @@ const ( pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord ) -// IsCompressedPubKey returns true the passed serialized public key has +// IsCompressedPubKey returns true the the passed serialized public key has // been encoded in compressed format, and false otherwise. func IsCompressedPubKey(pubKey []byte) bool { // The public key is only compressed if it is the correct length and @@ -51,38 +49,3 @@ type PublicKey = secp.PublicKey func NewPublicKey(x, y *FieldVal) *PublicKey { return secp.NewPublicKey(x, y) } - -// SerializedKey is a type for representing a public key in its compressed -// serialized form. -// -// NOTE: This type is useful when using public keys as keys in maps. -type SerializedKey [PubKeyBytesLenCompressed]byte - -// ToPubKey returns the public key parsed from the serialized key. -func (s SerializedKey) ToPubKey() (*PublicKey, error) { - return ParsePubKey(s[:]) -} - -// SchnorrSerialized returns the Schnorr serialized, x-only 32-byte -// representation of the serialized key. -func (s SerializedKey) SchnorrSerialized() [32]byte { - var serializedSchnorr [32]byte - copy(serializedSchnorr[:], s[1:]) - return serializedSchnorr -} - -// CopyBytes returns a copy of the underlying array as a byte slice. -func (s SerializedKey) CopyBytes() []byte { - c := make([]byte, PubKeyBytesLenCompressed) - copy(c, s[:]) - - return c -} - -// ToSerialized serializes a public key into its compressed form. -func ToSerialized(pubKey *PublicKey) SerializedKey { - var serialized SerializedKey - copy(serialized[:], pubKey.SerializeCompressed()) - - return serialized -} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE index fdf6d882..d2d1dd93 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE @@ -1,7 +1,7 @@ ISC License Copyright (c) 2013-2017 The btcsuite developers -Copyright (c) 2015-2024 The Decred developers +Copyright (c) 2015-2020 The Decred developers Copyright (c) 2017 The Lightning Network Developers Permission to use, copy, modify, and distribute this software for any diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go index bb0b41fd..ca4be121 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go @@ -1,5 +1,5 @@ // Copyright (c) 2015 The btcsuite developers -// Copyright (c) 2015-2022 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -8,11 +8,4 @@ package secp256k1 // Auto-generated file (see genprecomps.go) // DO NOT EDIT -var compressedBytePoints = "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" - -// Set accessor to a real function. -func init() { - compressedBytePointsFn = func() string { - return compressedBytePoints - } -} +var compressedBytePoints = "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" diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go index 41005007..e8620608 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2024 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Copyright 2013-2014 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -7,7 +7,7 @@ package secp256k1 import ( "encoding/hex" - "math/bits" + "math/big" ) // References: @@ -18,9 +18,6 @@ import ( // // [BRID]: On Binary Representations of Integers with Digits -1, 0, 1 // (Prodinger, Helmut) -// -// [STWS]: Secure-TWS: Authenticating Node to Multi-user Communication in -// Shared Sensor Networks (Oliveira, Leonardo B. et al) // All group operations are performed using Jacobian coordinates. For a given // (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1) @@ -42,59 +39,29 @@ func hexToFieldVal(s string) *FieldVal { return &f } -// hexToModNScalar converts the passed hex string into a ModNScalar and will -// panic if there is an error. This is only provided for the hard-coded -// constants so errors in the source code can be detected. It will only (and -// must only) be called with hard-coded values. -func hexToModNScalar(s string) *ModNScalar { - var isNegative bool - if len(s) > 0 && s[0] == '-' { - isNegative = true - s = s[1:] - } - if len(s)%2 != 0 { - s = "0" + s - } - b, err := hex.DecodeString(s) - if err != nil { - panic("invalid hex in source file: " + s) - } - var scalar ModNScalar - if overflow := scalar.SetByteSlice(b); overflow { - panic("hex in source file overflows mod N scalar: " + s) - } - if isNegative { - scalar.Negate() - } - return &scalar -} - var ( - // The following constants are used to accelerate scalar point - // multiplication through the use of the endomorphism: - // - // φ(Q) ⟼ λ*Q = (β*Q.x mod p, Q.y) - // - // See the code in the deriveEndomorphismParams function in genprecomps.go - // for details on their derivation. - // - // Additionally, see the scalar multiplication function in this file for - // details on how they are used. - endoNegLambda = hexToModNScalar("-5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72") - endoBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee") - endoNegB1 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c3") - endoNegB2 = hexToModNScalar("-3086d221a7d46bcde86c90e49284eb15") - endoZ1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f") - endoZ2 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c4221208ac9df506c6") - - // Alternatively, the following parameters are valid as well, however, - // benchmarks show them to be about 2% slower in practice. - // endoNegLambda = hexToModNScalar("-ac9c52b33fa3cf1f5ad9e3fd77ed9ba4a880b9fc8ec739c2e0cfc810b51283ce") - // endoBeta = hexToFieldVal("851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40") - // endoNegB1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb15") - // endoNegB2 = hexToModNScalar("-114ca50f7a8e2f3f657c1108d9d44cfd8") - // endoZ1 = hexToModNScalar("114ca50f7a8e2f3f657c1108d9d44cfd95fbc92c10fddd145") - // endoZ2 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f") + // Next 6 constants are from Hal Finney's bitcointalk.org post: + // https://bitcointalk.org/index.php?topic=3238.msg45565#msg45565 + // May he rest in peace. + // + // They have also been independently derived from the code in the + // EndomorphismVectors function in genstatics.go. + endomorphismLambda = fromHex("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72") + endomorphismBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee") + endomorphismA1 = fromHex("3086d221a7d46bcde86c90e49284eb15") + endomorphismB1 = fromHex("-e4437ed6010e88286f547fa90abfe4c3") + endomorphismA2 = fromHex("114ca50f7a8e2f3f657c1108d9d44cfd8") + endomorphismB2 = fromHex("3086d221a7d46bcde86c90e49284eb15") + + // Alternatively, the following parameters are valid as well, however, they + // seem to be about 8% slower in practice. + // + // endomorphismLambda = fromHex("AC9C52B33FA3CF1F5AD9E3FD77ED9BA4A880B9FC8EC739C2E0CFC810B51283CE") + // endomorphismBeta = hexToFieldVal("851695D49A83F8EF919BB86153CBCB16630FB68AED0A766A3EC693D68E6AFA40") + // endomorphismA1 = fromHex("E4437ED6010E88286F547FA90ABFE4C3") + // endomorphismB1 = fromHex("-3086D221A7D46BCDE86C90E49284EB15") + // endomorphismA2 = fromHex("3086D221A7D46BCDE86C90E49284EB15") + // endomorphismB2 = fromHex("114CA50F7A8E2F3F657C1108D9D44CFD8") ) // JacobianPoint is an element of the group formed by the secp256k1 curve in @@ -211,7 +178,7 @@ func addZ1AndZ2EqualsOne(p1, p2, result *JacobianPoint) { y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4) z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6) - // Normalize the resulting field values as needed. + // Normalize the resulting field values to a magnitude of 1 as needed. x3.Normalize() y3.Normalize() z3.Normalize() @@ -229,7 +196,7 @@ func addZ1EqualsZ2(p1, p2, result *JacobianPoint) { // the equation into intermediate elements which are used to minimize // the number of field multiplications using a slightly modified version // of the method shown at: - // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-zadd-2007-m + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl // // In particular it performs the calculations using the following: // A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B @@ -275,13 +242,13 @@ func addZ1EqualsZ2(p1, p2, result *JacobianPoint) { e.Mul2(x1, &b) // E = X1*B (mag: 1) negE.Set(&e).Negate(1) // negE = -E (mag: 2) f.Mul2(x2, &b) // F = X2*B (mag: 1) - x3.Add2(&e, &f).Negate(2).Add(&d) // X3 = D-E-F (mag: 4) - negX3.Set(x3).Negate(4) // negX3 = -X3 (mag: 5) - y3.Set(y1).Mul(f.Add(&negE)).Negate(1) // Y3 = -(Y1*(F-E)) (mag: 2) - y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 3) + x3.Add2(&e, &f).Negate(3).Add(&d) // X3 = D-E-F (mag: 5) + negX3.Set(x3).Negate(5).Normalize() // negX3 = -X3 (mag: 1) + y3.Set(y1).Mul(f.Add(&negE)).Negate(3) // Y3 = -(Y1*(F-E)) (mag: 4) + y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 5) z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1) - // Normalize the resulting field values as needed. + // Normalize the resulting field values to a magnitude of 1 as needed. x3.Normalize() y3.Normalize() z3.Normalize() @@ -363,7 +330,7 @@ func addZ2EqualsOne(p1, p2, result *JacobianPoint) { z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1) z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4) - // Normalize the resulting field values as needed. + // Normalize the resulting field values to a magnitude of 1 as needed. x3.Normalize() y3.Normalize() z3.Normalize() @@ -430,7 +397,7 @@ func addGeneric(p1, p2, result *JacobianPoint) { var negU1, negS1, negX3 FieldVal negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2) h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3) - i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 1) + i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 2) j.Mul2(&h, &i) // J = H*I (mag: 1) negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2) r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6) @@ -445,7 +412,7 @@ func addGeneric(p1, p2, result *JacobianPoint) { z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4) z3.Mul(&h) // Z3 = Z3*H (mag: 1) - // Normalize the resulting field values as needed. + // Normalize the resulting field values to a magnitude of 1 as needed. x3.Normalize() y3.Normalize() z3.Normalize() @@ -457,7 +424,7 @@ func addGeneric(p1, p2, result *JacobianPoint) { // NOTE: The points must be normalized for this function to return the correct // result. The resulting point will be normalized. func AddNonConst(p1, p2, result *JacobianPoint) { - // The point at infinity is the identity according to the group law for + // A point at infinity is the identity according to the group law for // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. if (p1.X.IsZero() && p1.Y.IsZero()) || p1.Z.IsZero() { result.Set(p2) @@ -541,7 +508,7 @@ func doubleZ1EqualsOne(p, result *JacobianPoint) { y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) - // Normalize the resulting field values as needed. + // Normalize the field values back to a magnitude of 1. x3.Normalize() y3.Normalize() z3.Normalize() @@ -595,7 +562,7 @@ func doubleGeneric(p, result *JacobianPoint) { y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) - // Normalize the resulting field values as needed. + // Normalize the field values back to a magnitude of 1. x3.Normalize() y3.Normalize() z3.Normalize() @@ -607,7 +574,7 @@ func doubleGeneric(p, result *JacobianPoint) { // NOTE: The point must be normalized for this function to return the correct // result. The resulting point will be normalized. func DoubleNonConst(p, result *JacobianPoint) { - // Doubling the point at infinity is still infinity. + // Doubling a point at infinity is still infinity. if p.Y.IsZero() || p.Z.IsZero() { result.X.SetInt(0) result.Y.SetInt(0) @@ -629,283 +596,47 @@ func DoubleNonConst(p, result *JacobianPoint) { doubleGeneric(p, result) } -// mulAdd64 multiplies the two passed base 2^64 digits together, adds the given -// value to the result, and returns the 128-bit result via a (hi, lo) tuple -// where the upper half of the bits are returned in hi and the lower half in lo. -func mulAdd64(digit1, digit2, m uint64) (hi, lo uint64) { - // Note the carry on the final add is safe to discard because the maximum - // possible value is: - // (2^64 - 1)(2^64 - 1) + (2^64 - 1) = 2^128 - 2^64 - // and: - // 2^128 - 2^64 < 2^128. - var c uint64 - hi, lo = bits.Mul64(digit1, digit2) - lo, c = bits.Add64(lo, m, 0) - hi, _ = bits.Add64(hi, 0, c) - return hi, lo -} - -// mulAdd64Carry multiplies the two passed base 2^64 digits together, adds both -// the given value and carry to the result, and returns the 128-bit result via a -// (hi, lo) tuple where the upper half of the bits are returned in hi and the -// lower half in lo. -func mulAdd64Carry(digit1, digit2, m, c uint64) (hi, lo uint64) { - // Note the carry on the high order add is safe to discard because the - // maximum possible value is: - // (2^64 - 1)(2^64 - 1) + 2*(2^64 - 1) = 2^128 - 1 - // and: - // 2^128 - 1 < 2^128. - var c2 uint64 - hi, lo = mulAdd64(digit1, digit2, m) - lo, c2 = bits.Add64(lo, c, 0) - hi, _ = bits.Add64(hi, 0, c2) - return hi, lo -} - -// mul512Rsh320Round computes the full 512-bit product of the two given scalars, -// right shifts the result by 320 bits, rounds to the nearest integer, and -// returns the result in constant time. +// splitK returns a balanced length-two representation of k and their signs. +// This is algorithm 3.74 from [GECC]. // -// Note that despite the inputs and output being mod n scalars, the 512-bit -// product is NOT reduced mod N prior to the right shift. This is intentional -// because it is used for replacing division with multiplication and thus the -// intermediate results must be done via a field extension to a larger field. -func mul512Rsh320Round(n1, n2 *ModNScalar) ModNScalar { - // Convert n1 and n2 to base 2^64 digits. - n1Digit0 := uint64(n1.n[0]) | uint64(n1.n[1])<<32 - n1Digit1 := uint64(n1.n[2]) | uint64(n1.n[3])<<32 - n1Digit2 := uint64(n1.n[4]) | uint64(n1.n[5])<<32 - n1Digit3 := uint64(n1.n[6]) | uint64(n1.n[7])<<32 - n2Digit0 := uint64(n2.n[0]) | uint64(n2.n[1])<<32 - n2Digit1 := uint64(n2.n[2]) | uint64(n2.n[3])<<32 - n2Digit2 := uint64(n2.n[4]) | uint64(n2.n[5])<<32 - n2Digit3 := uint64(n2.n[6]) | uint64(n2.n[7])<<32 - - // Compute the full 512-bit product n1*n2. - var r0, r1, r2, r3, r4, r5, r6, r7, c uint64 - - // Terms resulting from the product of the first digit of the second number - // by all digits of the first number. - // - // Note that r0 is ignored because it is not needed to compute the higher - // terms and it is shifted out below anyway. - c, _ = bits.Mul64(n2Digit0, n1Digit0) - c, r1 = mulAdd64(n2Digit0, n1Digit1, c) - c, r2 = mulAdd64(n2Digit0, n1Digit2, c) - r4, r3 = mulAdd64(n2Digit0, n1Digit3, c) - - // Terms resulting from the product of the second digit of the second number - // by all digits of the first number. - // - // Note that r1 is ignored because it is no longer needed to compute the - // higher terms and it is shifted out below anyway. - c, _ = mulAdd64(n2Digit1, n1Digit0, r1) - c, r2 = mulAdd64Carry(n2Digit1, n1Digit1, r2, c) - c, r3 = mulAdd64Carry(n2Digit1, n1Digit2, r3, c) - r5, r4 = mulAdd64Carry(n2Digit1, n1Digit3, r4, c) - - // Terms resulting from the product of the third digit of the second number - // by all digits of the first number. - // - // Note that r2 is ignored because it is no longer needed to compute the - // higher terms and it is shifted out below anyway. - c, _ = mulAdd64(n2Digit2, n1Digit0, r2) - c, r3 = mulAdd64Carry(n2Digit2, n1Digit1, r3, c) - c, r4 = mulAdd64Carry(n2Digit2, n1Digit2, r4, c) - r6, r5 = mulAdd64Carry(n2Digit2, n1Digit3, r5, c) - - // Terms resulting from the product of the fourth digit of the second number - // by all digits of the first number. - // - // Note that r3 is ignored because it is no longer needed to compute the - // higher terms and it is shifted out below anyway. - c, _ = mulAdd64(n2Digit3, n1Digit0, r3) - c, r4 = mulAdd64Carry(n2Digit3, n1Digit1, r4, c) - c, r5 = mulAdd64Carry(n2Digit3, n1Digit2, r5, c) - r7, r6 = mulAdd64Carry(n2Digit3, n1Digit3, r6, c) - - // At this point the upper 256 bits of the full 512-bit product n1*n2 are in - // r4..r7 (recall the low order results were discarded as noted above). - // - // Right shift the result 320 bits. Note that the MSB of r4 determines - // whether or not to round because it is the final bit that is shifted out. - // - // Also, notice that r3..r7 would also ordinarily be set to 0 as well for - // the full shift, but that is skipped since they are no longer used as - // their values are known to be zero. - roundBit := r4 >> 63 - r2, r1, r0 = r7, r6, r5 - - // Conditionally add 1 depending on the round bit in constant time. - r0, c = bits.Add64(r0, roundBit, 0) - r1, c = bits.Add64(r1, 0, c) - r2, r3 = bits.Add64(r2, 0, c) - - // Finally, convert the result to a mod n scalar. - // - // No modular reduction is needed because the result is guaranteed to be - // less than the group order given the group order is > 2^255 and the - // maximum possible value of the result is 2^192. - var result ModNScalar - result.n[0] = uint32(r0) - result.n[1] = uint32(r0 >> 32) - result.n[2] = uint32(r1) - result.n[3] = uint32(r1 >> 32) - result.n[4] = uint32(r2) - result.n[5] = uint32(r2 >> 32) - result.n[6] = uint32(r3) - result.n[7] = uint32(r3 >> 32) - return result -} - -// splitK returns two scalars (k1 and k2) that are a balanced length-two -// representation of the provided scalar such that k ≡ k1 + k2*λ (mod N), where -// N is the secp256k1 group order. -func splitK(k *ModNScalar) (ModNScalar, ModNScalar) { - // The ultimate goal is to decompose k into two scalars that are around - // half the bit length of k such that the following equation is satisfied: - // - // k1 + k2*λ ≡ k (mod n) - // - // The strategy used here is based on algorithm 3.74 from [GECC] with a few - // modifications to make use of the more efficient mod n scalar type, avoid - // some costly long divisions, and minimize the number of calculations. - // - // Start by defining a function that takes a vector v = ∈ ℤ⨯ℤ: - // - // f(v) = a + bλ (mod n) - // - // Then, find two vectors, v1 = , and v2 = in ℤ⨯ℤ such that: - // 1) v1 and v2 are linearly independent - // 2) f(v1) = f(v2) = 0 - // 3) v1 and v2 have small Euclidean norm - // - // The vectors that satisfy these properties are found via the Euclidean - // algorithm and are precomputed since both n and λ are fixed values for the - // secp256k1 curve. See genprecomps.go for derivation details. - // - // Next, consider k as a vector in ℚ⨯ℚ and by linear algebra write: - // - // = g1*v1 + g2*v2, where g1, g2 ∈ ℚ - // - // Note that, per above, the components of vector v1 are a1 and b1 while the - // components of vector v2 are a2 and b2. Given the vectors v1 and v2 were - // generated such that a1*b2 - a2*b1 = n, solving the equation for g1 and g2 - // yields: - // - // g1 = b2*k / n - // g2 = -b1*k / n - // - // Observe: - // = g1*v1 + g2*v2 - // = (b2*k/n)* + (-b1*k/n)* | substitute - // = + <-a2*b1*k/n, -b2*b1*k/n> | scalar mul - // = | vector add - // = <[a1*b2*k - a2*b1*k]/n, 0> | simplify - // = | factor out k - // = | substitute - // = | simplify - // - // Now, consider an integer-valued vector v: - // - // v = c1*v1 + c2*v2, where c1, c2 ∈ ℤ (mod n) - // - // Since vectors v1 and v2 are linearly independent and were generated such - // that f(v1) = f(v2) = 0, all possible scalars c1 and c2 also produce a - // vector v such that f(v) = 0. - // - // In other words, c1 and c2 can be any integers and the resulting - // decomposition will still satisfy the required equation. However, since - // the goal is to produce a balanced decomposition that provides a - // performance advantage by minimizing max(k1, k2), c1 and c2 need to be - // integers close to g1 and g2, respectively, so the resulting vector v is - // an integer-valued vector that is close to . - // - // Finally, consider the vector u: - // - // u = - v - // - // It follows that f(u) = k and thus the two components of vector u satisfy - // the required equation: - // - // k1 + k2*λ ≡ k (mod n) - // - // Choosing c1 and c2: - // ------------------- - // - // As mentioned above, c1 and c2 need to be integers close to g1 and g2, - // respectively. The algorithm in [GECC] chooses the following values: - // - // c1 = round(g1) = round(b2*k / n) - // c2 = round(g2) = round(-b1*k / n) - // - // However, as section 3.4.2 of [STWS] notes, the aforementioned approach - // requires costly long divisions that can be avoided by precomputing - // rounded estimates as follows: - // - // t = bitlen(n) + 1 - // z1 = round(2^t * b2 / n) - // z2 = round(2^t * -b1 / n) - // - // Then, use those precomputed estimates to perform a multiplication by k - // along with a floored division by 2^t, which is a simple right shift by t: - // - // c1 = floor(k * z1 / 2^t) = (k * z1) >> t - // c2 = floor(k * z2 / 2^t) = (k * z2) >> t - // - // Finally, round up if last bit discarded in the right shift by t is set by - // adding 1. - // - // As a further optimization, rather than setting t = bitlen(n) + 1 = 257 as - // stated by [STWS], this implementation uses a higher precision estimate of - // t = bitlen(n) + 64 = 320 because it allows simplification of the shifts - // in the internal calculations that are done via uint64s and also allows - // the use of floor in the precomputations. - // - // Thus, the calculations this implementation uses are: - // - // z1 = floor(b2<<320 / n) | precomputed - // z2 = floor((-b1)<<320) / n) | precomputed - // c1 = ((k * z1) >> 320) + (((k * z1) >> 319) & 1) - // c2 = ((k * z2) >> 320) + (((k * z2) >> 319) & 1) - // - // Putting it all together: - // ------------------------ - // - // Calculate the following vectors using the values discussed above: - // - // v = c1*v1 + c2*v2 - // u = - v - // - // The two components of the resulting vector v are: - // va = c1*a1 + c2*a2 - // vb = c1*b1 + c2*b2 - // - // Thus, the two components of the resulting vector u are: - // k1 = k - va - // k2 = 0 - vb = -vb - // - // As some final optimizations: - // - // 1) Note that k1 + k2*λ ≡ k (mod n) means that k1 ≡ k - k2*λ (mod n). - // Therefore, the computation of va can be avoided to save two - // field multiplications and a field addition. - // - // 2) Since k1 = k - k2*λ = k + k2*(-λ), an additional field negation is - // saved by storing and using the negative version of λ. - // - // 3) Since k2 = -vb = -(c1*b1 + c2*b2) = c1*(-b1) + c2*(-b2), one more - // field negation is saved by storing and using the negative versions of - // b1 and b2. - // - // k2 = c1*(-b1) + c2*(-b2) - // k1 = k + k2*(-λ) - var k1, k2 ModNScalar - c1 := mul512Rsh320Round(k, endoZ1) - c2 := mul512Rsh320Round(k, endoZ2) - k2.Add2(c1.Mul(endoNegB1), c2.Mul(endoNegB2)) - k1.Mul2(&k2, endoNegLambda).Add(k) - return k1, k2 +// One thing of note about this algorithm is that no matter what c1 and c2 are, +// the final equation of k = k1 + k2 * lambda (mod n) will hold. This is +// provable mathematically due to how a1/b1/a2/b2 are computed. +// +// c1 and c2 are chosen to minimize the max(k1,k2). +func splitK(k []byte) ([]byte, []byte, int, int) { + // All math here is done with big.Int, which is slow. + // At some point, it might be useful to write something similar to + // FieldVal but for N instead of P as the prime field if this ends up + // being a bottleneck. + bigIntK := new(big.Int) + c1, c2 := new(big.Int), new(big.Int) + tmp1, tmp2 := new(big.Int), new(big.Int) + k1, k2 := new(big.Int), new(big.Int) + + bigIntK.SetBytes(k) + // c1 = round(b2 * k / n) from step 4. + // Rounding isn't really necessary and costs too much, hence skipped + c1.Mul(endomorphismB2, bigIntK) + c1.Div(c1, curveParams.N) + // c2 = round(b1 * k / n) from step 4 (sign reversed to optimize one step) + // Rounding isn't really necessary and costs too much, hence skipped + c2.Mul(endomorphismB1, bigIntK) + c2.Div(c2, curveParams.N) + // k1 = k - c1 * a1 - c2 * a2 from step 5 (note c2's sign is reversed) + tmp1.Mul(c1, endomorphismA1) + tmp2.Mul(c2, endomorphismA2) + k1.Sub(bigIntK, tmp1) + k1.Add(k1, tmp2) + // k2 = - c1 * b1 - c2 * b2 from step 5 (note c2's sign is reversed) + tmp1.Mul(c1, endomorphismB1) + tmp2.Mul(c2, endomorphismB2) + k2.Sub(tmp2, tmp1) + + // Note Bytes() throws out the sign of k1 and k2. This matters + // since k1 and/or k2 can be negative. Hence, we pass that + // back separately. + return k1.Bytes(), k2.Bytes(), k1.Sign(), k2.Sign() } // nafScalar represents a positive integer up to a maximum value of 2^256 - 1 @@ -1044,132 +775,70 @@ func naf(k []byte) nafScalar { return result } -// ScalarMultNonConst multiplies k*P where k is a scalar modulo the curve order -// and P is a point in Jacobian projective coordinates and stores the result in -// the provided Jacobian point. +// ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the +// curve order and P is a point in Jacobian projective coordinates and stores +// the result in the provided Jacobian point. // // NOTE: The point must be normalized for this function to return the correct // result. The resulting point will be normalized. func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { - // ------------------------------------------------------------------------- - // This makes use of the following efficiently-computable endomorphism to - // accelerate the computation: - // - // φ(P) ⟼ λ*P = (β*P.x mod p, P.y) - // - // In other words, there is a special scalar λ that every point on the - // elliptic curve can be multiplied by that will result in the same point as - // performing a single field multiplication of the point's X coordinate by - // the special value β. - // - // This is useful because scalar point multiplication is significantly more - // expensive than a single field multiplication given the former involves a - // series of point doublings and additions which themselves consist of a - // combination of several field multiplications, squarings, and additions. - // - // So, the idea behind making use of the endomorphism is thus to decompose - // the scalar into two scalars that are each about half the bit length of - // the original scalar such that: - // - // k ≡ k1 + k2*λ (mod n) - // - // This in turn allows the scalar point multiplication to be performed as a - // sum of two smaller half-length multiplications as follows: - // - // k*P = (k1 + k2*λ)*P - // = k1*P + k2*λ*P - // = k1*P + k2*φ(P) - // - // Thus, a speedup is achieved so long as it's faster to decompose the - // scalar, compute φ(P), and perform a simultaneous multiply of the - // half-length point multiplications than it is to compute a full width - // point multiplication. - // - // In practice, benchmarks show the current implementation provides a - // speedup of around 30-35% versus not using the endomorphism. - // - // See section 3.5 in [GECC] for a more rigorous treatment. - // ------------------------------------------------------------------------- + // Decompose K into k1 and k2 in order to halve the number of EC ops. + // See Algorithm 3.74 in [GECC]. + kBytes := k.Bytes() + k1, k2, signK1, signK2 := splitK(kBytes[:]) + zeroArray32(&kBytes) - // Per above, the main equation here to remember is: - // k*P = k1*P + k2*φ(P) - // - // p1 below is P in the equation while p2 is φ(P) in the equation. + // The main equation here to remember is: + // k * P = k1 * P + k2 * ϕ(P) // - // NOTE: φ(x,y) = (β*x,y). The Jacobian z coordinates are the same, so this - // math goes through. - // - // Also, calculate -p1 and -p2 for use in the NAF optimization. + // P1 below is P in the equation, P2 below is ϕ(P) in the equation p1, p1Neg := new(JacobianPoint), new(JacobianPoint) p1.Set(point) p1Neg.Set(p1) p1Neg.Y.Negate(1).Normalize() + + // NOTE: ϕ(x,y) = (βx,y). The Jacobian z coordinates are the same, so this + // math goes through. p2, p2Neg := new(JacobianPoint), new(JacobianPoint) p2.Set(p1) - p2.X.Mul(endoBeta).Normalize() + p2.X.Mul(endomorphismBeta).Normalize() p2Neg.Set(p2) p2Neg.Y.Negate(1).Normalize() - // Decompose k into k1 and k2 such that k = k1 + k2*λ (mod n) where k1 and - // k2 are around half the bit length of k in order to halve the number of EC - // operations. - // - // Notice that this also flips the sign of the scalars and points as needed - // to minimize the bit lengths of the scalars k1 and k2. - // - // This is done because the scalars are operating modulo the group order - // which means that when they would otherwise be a small negative magnitude - // they will instead be a large positive magnitude. Since the goal is for - // the scalars to have a small magnitude to achieve a performance boost, use - // their negation when they are greater than the half order of the group and - // flip the positive and negative values of the corresponding point that - // will be multiplied by to compensate. - // - // In other words, transform the calc when k1 is over the half order to: - // k1*P = -k1*-P - // - // Similarly, transform the calc when k2 is over the half order to: - // k2*φ(P) = -k2*-φ(P) - k1, k2 := splitK(k) - if k1.IsOverHalfOrder() { - k1.Negate() + // Flip the positive and negative values of the points as needed + // depending on the signs of k1 and k2. As mentioned in the equation + // above, each of k1 and k2 are multiplied by the respective point. + // Since -k * P is the same thing as k * -P, and the group law for + // elliptic curves states that P(x, y) = -P(x, -y), it's faster and + // simplifies the code to just make the point negative. + if signK1 == -1 { p1, p1Neg = p1Neg, p1 } - if k2.IsOverHalfOrder() { - k2.Negate() + if signK2 == -1 { p2, p2Neg = p2Neg, p2 } - // Convert k1 and k2 into their NAF representations since NAF has a lot more - // zeros overall on average which minimizes the number of required point - // additions in exchange for a mix of fewer point additions and subtractions - // at the cost of one additional point doubling. - // - // This is an excellent tradeoff because subtraction of points has the same - // computational complexity as addition of points and point doubling is - // faster than both. + // NAF versions of k1 and k2 should have a lot more zeros. // - // Concretely, on average, 1/2 of all bits will be non-zero with the normal - // binary representation whereas only 1/3rd of the bits will be non-zero - // with NAF. - // - // The Pos version of the bytes contain the +1s and the Neg versions contain - // the -1s. - k1Bytes, k2Bytes := k1.Bytes(), k2.Bytes() - k1NAF, k2NAF := naf(k1Bytes[:]), naf(k2Bytes[:]) + // The Pos version of the bytes contain the +1s and the Neg versions + // contain the -1s. + k1NAF, k2NAF := naf(k1), naf(k2) k1PosNAF, k1NegNAF := k1NAF.Pos(), k1NAF.Neg() k2PosNAF, k2NegNAF := k2NAF.Pos(), k2NAF.Neg() k1Len, k2Len := len(k1PosNAF), len(k2PosNAF) - // Add left-to-right using the NAF optimization. See algorithm 3.77 from - // [GECC]. - // - // Point Q = ∞ (point at infinity). - var q JacobianPoint m := k1Len if m < k2Len { m = k2Len } + + // Point Q = ∞ (point at infinity). + var q JacobianPoint + + // Add left-to-right using the NAF optimization. See algorithm 3.77 + // from [GECC]. This should be faster overall since there will be a lot + // more instances of 0, hence reducing the number of Jacobian additions + // at the cost of 1 possible extra doubling. for i := 0; i < m; i++ { // Since k1 and k2 are potentially different lengths and the calculation // is being done left to right, pad the front of the shorter one with @@ -1181,8 +850,7 @@ func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { if i >= m-k2Len { k2BytePos, k2ByteNeg = k2PosNAF[i-(m-k2Len)], k2NegNAF[i-(m-k2Len)] } - - for mask := uint8(1 << 7); mask > 0; mask >>= 1 { + for bit, mask := 7, uint8(1<<7); bit >= 0; bit, mask = bit-1, mask>>1 { // Q = 2 * Q DoubleNonConst(&q, &q) @@ -1215,47 +883,31 @@ func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { result.Set(&q) } -// ScalarBaseMultNonConst multiplies k*G where k is a scalar modulo the curve -// order and G is the base point of the group and stores the result in the -// provided Jacobian point. +// ScalarBaseMultNonConst multiplies k*G where G is the base point of the group +// and k is a big endian integer. The result is stored in Jacobian coordinates +// (x1, y1, z1). // // NOTE: The resulting point will be normalized. func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { - scalarBaseMultNonConst(k, result) -} - -// jacobianG is the secp256k1 base point converted to Jacobian coordinates and -// is defined here to avoid repeatedly converting it. -var jacobianG = func() JacobianPoint { - var G JacobianPoint - bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &G) - return G -}() - -// scalarBaseMultNonConstSlow computes k*G through ScalarMultNonConst. -func scalarBaseMultNonConstSlow(k *ModNScalar, result *JacobianPoint) { - ScalarMultNonConst(k, &jacobianG, result) -} - -// scalarBaseMultNonConstFast computes k*G through the precomputed lookup -// tables. -func scalarBaseMultNonConstFast(k *ModNScalar, result *JacobianPoint) { bytePoints := s256BytePoints() - // Start with the point at infinity. - result.X.Zero() - result.Y.Zero() - result.Z.Zero() - - // bytePoints has all 256 byte points for each 8-bit window. The strategy - // is to add up the byte points. This is best understood by expressing k in - // base-256 which it already sort of is. Each "digit" in the 8-bit window - // can be looked up using bytePoints and added together. - kb := k.Bytes() - for i := 0; i < len(kb); i++ { - pt := &bytePoints[i][kb[i]] - AddNonConst(result, pt, result) + // Point Q = ∞ (point at infinity). + var q JacobianPoint + + // curve.bytePoints has all 256 byte points for each 8-bit window. The + // strategy is to add up the byte points. This is best understood by + // expressing k in base-256 which it already sort of is. Each "digit" in + // the 8-bit window can be looked up using bytePoints and added together. + var pt JacobianPoint + for i, byteVal := range k.Bytes() { + p := bytePoints[i][byteVal] + pt.X.Set(&p[0]) + pt.Y.Set(&p[1]) + pt.Z.SetInt(1) + AddNonConst(&q, &pt, &q) } + + result.Set(&q) } // isOnCurve returns whether or not the affine point (x,y) is on the curve. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go deleted file mode 100644 index 16288318..00000000 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2024 The Decred developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -//go:build tinygo - -package secp256k1 - -// This file contains the variants suitable for -// memory or storage constrained environments. - -func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { - scalarBaseMultNonConstSlow(k, result) -} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go deleted file mode 100644 index cf84f770..00000000 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2024 The Decred developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -//go:build !tinygo - -package secp256k1 - -// This file contains the variants that don't fit in -// memory or storage constrained environments. - -func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { - scalarBaseMultNonConstFast(k, result) -} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go index ac01e234..91a670e5 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go @@ -1,11 +1,10 @@ // Copyright (c) 2013-2014 The btcsuite developers -// Copyright (c) 2015-2022 The Decred developers +// Copyright (c) 2015-2019 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. /* -Package secp256k1 implements optimized secp256k1 elliptic curve operations in -pure Go. +Package secp256k1 implements optimized secp256k1 elliptic curve operations. This package provides an optimized pure Go implementation of elliptic curve cryptography operations over the secp256k1 curve as well as data structures and @@ -19,22 +18,22 @@ packages for more details about those aspects. An overview of the features provided by this package are as follows: - - Private key generation, serialization, and parsing - - Public key generation, serialization and parsing per ANSI X9.62-1998 - - Parses uncompressed, compressed, and hybrid public keys - - Serializes uncompressed and compressed public keys - - Specialized types for performing optimized and constant time field operations - - FieldVal type for working modulo the secp256k1 field prime - - ModNScalar type for working modulo the secp256k1 group order - - Elliptic curve operations in Jacobian projective coordinates - - Point addition - - Point doubling - - Scalar multiplication with an arbitrary point - - Scalar multiplication with the base point (group generator) - - Point decompression from a given x coordinate - - Nonce generation via RFC6979 with support for extra data and version - information that can be used to prevent nonce reuse between signing - algorithms + - Private key generation, serialization, and parsing + - Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys + - Specialized types for performing optimized and constant time field operations + - FieldVal type for working modulo the secp256k1 field prime + - ModNScalar type for working modulo the secp256k1 group order + - Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) + - Point decompression from a given x coordinate + - Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing + algorithms It also provides an implementation of the Go standard library crypto/elliptic Curve interface via the S256 function so that it may be used with other packages @@ -50,7 +49,7 @@ use optimized secp256k1 elliptic curve cryptography. Finally, a comprehensive suite of tests is provided to provide a high level of quality assurance. -# Use of secp256k1 in Decred +Use of secp256k1 in Decred At the time of this writing, the primary public key cryptography in widespread use on the Decred network used to secure coins is based on elliptic curves diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go index 96869a3c..ebbdfc54 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go @@ -1,5 +1,5 @@ // Copyright (c) 2015 The btcsuite developers -// Copyright (c) 2015-2023 The Decred developers +// Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -9,7 +9,7 @@ package secp256k1 // public key using Diffie-Hellman key exchange (ECDH) (RFC 5903). // RFC5903 Section 9 states we should only return x. // -// It is recommended to securely hash the result before using as a cryptographic +// It is recommended to securily hash the result before using as a cryptographic // key. func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte { var point, result JacobianPoint diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/doc.go index 18d12c52..14f38ef3 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/doc.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/doc.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2023 The Decred developers +// Copyright (c) 2020 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -21,7 +21,7 @@ hash combination. A comprehensive suite of tests is provided to ensure proper functionality. -# ECDSA use in Decred +ECDSA use in Decred At the time of this writing, ECDSA signatures are heavily used for proving coin ownership in Decred as the vast majority of transactions consist of what is @@ -30,13 +30,13 @@ private key only known to the recipient of the coins along with an encumbrance that requires an ECDSA signature that proves the new owner possesses the private key without actually revealing it. -# Errors +Errors -The errors returned by this package are of type ecdsa.Error and fully support -the standard library errors.Is and errors.As functions. This allows the caller -to programmatically determine the specific error by examining the ErrorKind -field of the type asserted ecdsa.Error while still providing rich error messages -with contextual information. See ErrorKind in the package documentation for a -full list. +Errors returned by this package are of type ecdsa.Error and fully support the +standard library errors.Is and errors.As functions. This allows the caller to +programmatically determine the specific error by examining the ErrorKind field +of the type asserted ecdsa.Error while still providing rich error messages with +contextual information. See ErrorKind in the package documentation for a full +list. */ package ecdsa diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/error.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/error.go index 6136ece3..45f82525 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/error.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/error.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 The Decred developers +// Copyright (c) 2020 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -85,24 +85,6 @@ const ( // ErrSigSTooBig is returned when a signature has S with a value that is // greater than or equal to the group order. ErrSigSTooBig = ErrorKind("ErrSigSTooBig") - - // ErrSigInvalidLen is returned when a signature that should be a compact - // signature is not the required length. - ErrSigInvalidLen = ErrorKind("ErrSigInvalidLen") - - // ErrSigInvalidRecoveryCode is returned when a signature that should be a - // compact signature has an invalid value for the public key recovery code. - ErrSigInvalidRecoveryCode = ErrorKind("ErrSigInvalidRecoveryCode") - - // ErrSigOverflowsPrime is returned when a signature that should be a - // compact signature has the overflow bit set but adding the order to it - // would overflow the underlying field prime. - ErrSigOverflowsPrime = ErrorKind("ErrSigOverflowsPrime") - - // ErrPointNotOnCurve is returned when attempting to recover a public key - // from a compact signature results in a point that is not on the elliptic - // curve. - ErrPointNotOnCurve = ErrorKind("ErrPointNotOnCurve") ) // Error satisfies the error interface and prints human-readable errors. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/signature.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/signature.go index dfee489e..50f1721a 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/signature.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa/signature.go @@ -1,11 +1,12 @@ // Copyright (c) 2013-2014 The btcsuite developers -// Copyright (c) 2015-2022 The Decred developers +// Copyright (c) 2015-2020 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package ecdsa import ( + "errors" "fmt" "github.com/decred/dcrd/dcrec/secp256k1/v4" @@ -29,10 +30,10 @@ var ( // orderAsFieldVal is the order of the secp256k1 curve group stored as a // field value. It is provided here to avoid the need to create it multiple // times. - orderAsFieldVal = func() secp256k1.FieldVal { + orderAsFieldVal = func() *secp256k1.FieldVal { var f secp256k1.FieldVal f.SetByteSlice(secp256k1.Params().N.Bytes()) - return f + return &f }() ) @@ -59,16 +60,6 @@ func NewSignature(r, s *secp256k1.ModNScalar) *Signature { return &Signature{*r, *s} } -// R returns the r value of the signature. -func (sig *Signature) R() secp256k1.ModNScalar { - return sig.r -} - -// S returns the s value of the signature. -func (sig *Signature) S() secp256k1.ModNScalar { - return sig.s -} - // Serialize returns the ECDSA signature in the Distinguished Encoding Rules // (DER) format per section 10 of [ISO/IEC 8825-1] and such that the S component // of the signature is less than or equal to the half order of the group. @@ -292,7 +283,7 @@ func (sig *Signature) Verify(hash []byte, pubKey *secp256k1.PublicKey) bool { // Step 10. // // Verified if (R + N) * z == X.x (mod P) - sigRModP.Add(&orderAsFieldVal) + sigRModP.Add(orderAsFieldVal) result.Mul2(&sigRModP, z).Normalize() return result.Equals(&X.X) } @@ -544,130 +535,8 @@ func ParseDERSignature(sig []byte) (*Signature, error) { return NewSignature(&r, &s), nil } -// sign generates an ECDSA signature over the secp256k1 curve for the provided -// hash (which should be the result of hashing a larger message) using the given -// nonce and private key and returns it along with an additional public key -// recovery code and success indicator. Upon success, the produced signature is -// deterministic (same message, nonce, and key yield the same signature) and -// canonical in accordance with BIP0062. -// -// Note that signRFC6979 makes use of this function as it is the primary ECDSA -// signing logic. It differs in that it accepts a nonce to use when signing and -// may not successfully produce a valid signature for the given nonce. It is -// primarily separated for testing purposes. -func sign(privKey, nonce *secp256k1.ModNScalar, hash []byte) (*Signature, byte, bool) { - // The algorithm for producing an ECDSA signature is given as algorithm 4.29 - // in [GECC]. - // - // The following is a paraphrased version for reference: - // - // G = curve generator - // N = curve order - // d = private key - // m = message - // r, s = signature - // - // 1. Select random nonce k in [1, N-1] - // 2. Compute kG - // 3. r = kG.x mod N (kG.x is the x coordinate of the point kG) - // Repeat from step 1 if r = 0 - // 4. e = H(m) - // 5. s = k^-1(e + dr) mod N - // Repeat from step 1 if s = 0 - // 6. Return (r,s) - // - // This is slightly modified here to conform to RFC6979 and BIP 62 as - // follows: - // - // A. Instead of selecting a random nonce in step 1, use RFC6979 to generate - // a deterministic nonce in [1, N-1] parameterized by the private key, - // message being signed, and an iteration count for the repeat cases - // B. Negate s calculated in step 5 if it is > N/2 - // This is done because both s and its negation are valid signatures - // modulo the curve order N, so it forces a consistent choice to reduce - // signature malleability - - // NOTE: Step 1 is performed by the caller. - // - // Step 2. - // - // Compute kG - // - // Note that the point must be in affine coordinates. - k := nonce - var kG secp256k1.JacobianPoint - secp256k1.ScalarBaseMultNonConst(k, &kG) - kG.ToAffine() - - // Step 3. - // - // r = kG.x mod N - // Repeat from step 1 if r = 0 - r, overflow := fieldToModNScalar(&kG.X) - if r.IsZero() { - return nil, 0, false - } - - // Since the secp256k1 curve has a cofactor of 1, when recovering a - // public key from an ECDSA signature over it, there are four possible - // candidates corresponding to the following cases: - // - // 1) The X coord of the random point is < N and its Y coord even - // 2) The X coord of the random point is < N and its Y coord is odd - // 3) The X coord of the random point is >= N and its Y coord is even - // 4) The X coord of the random point is >= N and its Y coord is odd - // - // Rather than forcing the recovery procedure to check all possible - // cases, this creates a recovery code that uniquely identifies which of - // the cases apply by making use of 2 bits. Bit 0 identifies the - // oddness case and Bit 1 identifies the overflow case (aka when the X - // coord >= N). - // - // It is also worth noting that making use of Hasse's theorem shows - // there are around log_2((p-n)/p) ~= -127.65 ~= 1 in 2^127 points where - // the X coordinate is >= N. It is not possible to calculate these - // points since that would require breaking the ECDLP, but, in practice - // this strongly implies with extremely high probability that there are - // only a few actual points for which this case is true. - pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.Y.IsOddBit()) - - // Step 4. - // - // e = H(m) - // - // Note that this actually sets e = H(m) mod N which is correct since - // it is only used in step 5 which itself is mod N. - var e secp256k1.ModNScalar - e.SetByteSlice(hash) - - // Step 5 with modification B. - // - // s = k^-1(e + dr) mod N - // Repeat from step 1 if s = 0 - // s = -s if s > N/2 - kinv := new(secp256k1.ModNScalar).InverseValNonConst(k) - s := new(secp256k1.ModNScalar).Mul2(privKey, &r).Add(&e).Mul(kinv) - if s.IsZero() { - return nil, 0, false - } - if s.IsOverHalfOrder() { - s.Negate() - - // Negating s corresponds to the random point that would have been - // generated by -k (mod N), which necessarily has the opposite - // oddness since N is prime, thus flip the pubkey recovery code - // oddness bit accordingly. - pubKeyRecoveryCode ^= 0x01 - } - - // Step 6. - // - // Return (r,s) - return NewSignature(&r, s), pubKeyRecoveryCode, true -} - // signRFC6979 generates a deterministic ECDSA signature according to RFC 6979 -// and BIP0062 and returns it along with an additional public key recovery code +// and BIP 62 and returns it along with an additional public key recovery code // for efficiently recovering the public key from the signature. func signRFC6979(privKey *secp256k1.PrivateKey, hash []byte) (*Signature, byte) { // The algorithm for producing an ECDSA signature is given as algorithm 4.29 @@ -712,14 +581,82 @@ func signRFC6979(privKey *secp256k1.PrivateKey, hash []byte) (*Signature, byte) // private key, message being signed, and iteration count. k := secp256k1.NonceRFC6979(privKeyBytes[:], hash, nil, nil, iteration) - // Steps 2-6. - sig, pubKeyRecoveryCode, success := sign(privKeyScalar, k, hash) + // Step 2. + // + // Compute kG + // + // Note that the point must be in affine coordinates. + var kG secp256k1.JacobianPoint + secp256k1.ScalarBaseMultNonConst(k, &kG) + kG.ToAffine() + + // Step 3. + // + // r = kG.x mod N + // Repeat from step 1 if r = 0 + r, overflow := fieldToModNScalar(&kG.X) + if r.IsZero() { + k.Zero() + continue + } + + // Since the secp256k1 curve has a cofactor of 1, when recovering a + // public key from an ECDSA signature over it, there are four possible + // candidates corresponding to the following cases: + // + // 1) The X coord of the random point is < N and its Y coord even + // 2) The X coord of the random point is < N and its Y coord is odd + // 3) The X coord of the random point is >= N and its Y coord is even + // 4) The X coord of the random point is >= N and its Y coord is odd + // + // Rather than forcing the recovery procedure to check all possible + // cases, this creates a recovery code that uniquely identifies which of + // the cases apply by making use of 2 bits. Bit 0 identifies the + // oddness case and Bit 1 identifies the overflow case (aka when the X + // coord >= N). + // + // It is also worth noting that making use of Hasse's theorem shows + // there are around log_2((p-n)/p) ~= -127.65 ~= 1 in 2^127 points where + // the X coordinate is >= N. It is not possible to calculate these + // points since that would require breaking the ECDLP, but, in practice + // this strongly implies with extremely high probability that there are + // only a few actual points for which this case is true. + pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.Y.IsOddBit()) + + // Step 4. + // + // e = H(m) + // + // Note that this actually sets e = H(m) mod N which is correct since + // it is only used in step 5 which itself is mod N. + var e secp256k1.ModNScalar + e.SetByteSlice(hash) + + // Step 5 with modification B. + // + // s = k^-1(e + dr) mod N + // Repeat from step 1 if s = 0 + // s = -s if s > N/2 + kInv := new(secp256k1.ModNScalar).InverseValNonConst(k) k.Zero() - if !success { + s := new(secp256k1.ModNScalar).Mul2(privKeyScalar, &r).Add(&e).Mul(kInv) + if s.IsZero() { continue } + if s.IsOverHalfOrder() { + s.Negate() + + // Negating s corresponds to the random point that would have been + // generated by -k (mod N), which necessarily has the opposite + // oddness since N is prime, thus flip the pubkey recovery code + // oddness bit accordingly. + pubKeyRecoveryCode ^= 0x01 + } - return sig, pubKeyRecoveryCode + // Step 6. + // + // Return (r,s) + return NewSignature(&r, s), pubKeyRecoveryCode } } @@ -832,7 +769,7 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) // The method described by section 4.1.6 of [SEC1] to determine which one is // the correct one involves calculating each possibility as a candidate // public key and comparing the candidate to the authentic public key. It - // also hints that it is possible to generate the signature in a such a + // also hints that is is possible to generate the signature in a such a // way that only one of the candidate public keys is viable. // // A more efficient approach that is specific to the secp256k1 curve is used @@ -860,9 +797,7 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) // A compact signature consists of a recovery byte followed by the R and // S components serialized as 32-byte big-endian values. if len(signature) != compactSigSize { - str := fmt.Sprintf("malformed signature: wrong size: %d != %d", - len(signature), compactSigSize) - return nil, false, signatureError(ErrSigInvalidLen, str) + return nil, false, errors.New("invalid compact signature size") } // Parse and validate the compact signature recovery code. @@ -872,10 +807,7 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) ) sigRecoveryCode := signature[0] if sigRecoveryCode < minValidCode || sigRecoveryCode > maxValidCode { - str := fmt.Sprintf("invalid signature: public key recovery code %d is "+ - "not in the valid range [%d, %d]", sigRecoveryCode, minValidCode, - maxValidCode) - return nil, false, signatureError(ErrSigInvalidRecoveryCode, str) + return nil, false, errors.New("invalid compact signature recovery code") } sigRecoveryCode -= compactSigMagicOffset wasCompressed := sigRecoveryCode&compactSigCompPubKey != 0 @@ -888,20 +820,16 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) // Fail if r and s are not in [1, N-1]. var r, s secp256k1.ModNScalar if overflow := r.SetByteSlice(signature[1:33]); overflow { - str := "invalid signature: R >= group order" - return nil, false, signatureError(ErrSigRTooBig, str) + return nil, false, errors.New("signature R is >= curve order") } if r.IsZero() { - str := "invalid signature: R is 0" - return nil, false, signatureError(ErrSigRIsZero, str) + return nil, false, errors.New("signature R is 0") } if overflow := s.SetByteSlice(signature[33:]); overflow { - str := "invalid signature: S >= group order" - return nil, false, signatureError(ErrSigSTooBig, str) + return nil, false, errors.New("signature S is >= curve order") } if s.IsZero() { - str := "invalid signature: S is 0" - return nil, false, signatureError(ErrSigSIsZero, str) + return nil, false, errors.New("signature S is 0") } // Step 2. @@ -922,14 +850,13 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) // would exceed the field prime since R originally came from the X // coordinate of a random point on the curve. if fieldR.IsGtOrEqPrimeMinusOrder() { - str := "invalid signature: signature R + N >= P" - return nil, false, signatureError(ErrSigOverflowsPrime, str) + return nil, false, errors.New("signature R + N >= P") } // Step 3.2. // // r = r + N (mod P) - fieldR.Add(&orderAsFieldVal) + fieldR.Add(orderAsFieldVal) } // Step 4. @@ -944,16 +871,15 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) oddY := pubKeyRecoveryCode&pubKeyRecoveryCodeOddnessBit != 0 var y secp256k1.FieldVal if valid := secp256k1.DecompressY(&fieldR, oddY, &y); !valid { - str := "invalid signature: not for a valid curve point" - return nil, false, signatureError(ErrPointNotOnCurve, str) + return nil, false, errors.New("signature is not for a valid curve point") } // Step 5. // // X = (r, y) var X secp256k1.JacobianPoint - X.X.Set(fieldR.Normalize()) - X.Y.Set(y.Normalize()) + X.X.Set(&fieldR) + X.Y.Set(&y) X.Z.SetInt(1) // Step 6. @@ -989,8 +915,7 @@ func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) // Either the signature or the pubkey recovery code must be invalid if the // recovered pubkey is the point at infinity. if (Q.X.IsZero() && Q.Y.IsZero()) || Q.Z.IsZero() { - str := "invalid signature: recovered pubkey is the point at infinity" - return nil, false, signatureError(ErrPointNotOnCurve, str) + return nil, false, errors.New("recovered pubkey is the point at infinity") } // Notice that the public key is in affine coordinates. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go index 42022646..a271ff6b 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 The Decred developers +// Copyright 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -102,7 +102,7 @@ func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool { // // This is part of the elliptic.Curve interface implementation. func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { - // The point at infinity is the identity according to the group law for + // A point at infinity is the identity according to the group law for // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. if x1.Sign() == 0 && y1.Sign() == 0 { return x2, y2 @@ -249,7 +249,7 @@ var secp256k1 = &KoblitzCurve{ }, } -// S256 returns an elliptic.Curve which implements secp256k1. +// S256 returns a Curve which implements secp256k1. func S256() *KoblitzCurve { return secp256k1 } diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go index 494b209b..43e27a91 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go @@ -1,6 +1,6 @@ // Copyright (c) 2013-2014 The btcsuite developers -// Copyright (c) 2015-2023 The Decred developers -// Copyright (c) 2013-2023 Dave Collins +// Copyright (c) 2015-2021 The Decred developers +// Copyright (c) 2013-2021 Dave Collins // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -103,8 +103,7 @@ const ( // FieldVal implements optimized fixed-precision arithmetic over the // secp256k1 finite field. This means all arithmetic is performed modulo -// -// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. +// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. // // WARNING: Since it is so important for the field arithmetic to be extremely // fast for high performance crypto, this type does not perform any validation @@ -173,9 +172,9 @@ type FieldVal struct { // String returns the field value as a normalized human-readable hex string. // -// Preconditions: None -// Output Normalized: Field is not modified -- same as input value -// Output Max Magnitude: Field is not modified -- same as input value +// Preconditions: None +// Output Normalized: Field is not modified -- same as input value +// Output Max Magnitude: Field is not modified -- same as input value func (f FieldVal) String() string { // f is a copy, so it's safe to normalize it without mutating the original. f.Normalize() @@ -186,9 +185,9 @@ func (f FieldVal) String() string { // value is already set to zero. This function can be useful to clear an // existing field value for reuse. // -// Preconditions: None -// Output Normalized: Yes -// Output Max Magnitude: 1 +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 func (f *FieldVal) Zero() { f.n[0] = 0 f.n[1] = 0 @@ -209,9 +208,9 @@ func (f *FieldVal) Zero() { // f := new(FieldVal).Set(f2).Add(1) so that f = f2 + 1 where f2 is not // modified. // -// Preconditions: None -// Output Normalized: Same as input value -// Output Max Magnitude: Same as input value +// Preconditions: None +// Output Normalized: Same as input value +// Output Max Magnitude: Same as input value func (f *FieldVal) Set(val *FieldVal) *FieldVal { *f = *val return f @@ -224,9 +223,9 @@ func (f *FieldVal) Set(val *FieldVal) *FieldVal { // The field value is returned to support chaining. This enables syntax such // as f := new(FieldVal).SetInt(2).Mul(f2) so that f = 2 * f2. // -// Preconditions: None -// Output Normalized: Yes -// Output Max Magnitude: 1 +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 func (f *FieldVal) SetInt(ui uint16) *FieldVal { f.Zero() f.n[0] = uint32(ui) @@ -243,9 +242,9 @@ func (f *FieldVal) SetInt(ui uint16) *FieldVal { // from a bool to numeric value in constant time and many constant-time // operations require a numeric value. // -// Preconditions: None -// Output Normalized: Yes if no overflow, no otherwise -// Output Max Magnitude: 1 +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 func (f *FieldVal) SetBytes(b *[32]byte) uint32 { // Pack the 256 total bits across the 10 uint32 words with a max of // 26-bits per word. This could be done with a couple of for loops, @@ -312,9 +311,9 @@ func (f *FieldVal) SetBytes(b *[32]byte) uint32 { // or it if is acceptable to use this function with the described truncation and // overflow behavior. // -// Preconditions: None -// Output Normalized: Yes if no overflow, no otherwise -// Output Max Magnitude: 1 +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 func (f *FieldVal) SetByteSlice(b []byte) bool { var b32 [32]byte b = b[:constantTimeMin(uint32(len(b)), 32)] @@ -329,9 +328,9 @@ func (f *FieldVal) SetByteSlice(b []byte) bool { // performs fast modular reduction over the secp256k1 prime by making use of the // special form of the prime in constant time. // -// Preconditions: None -// Output Normalized: Yes -// Output Max Magnitude: 1 +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 func (f *FieldVal) Normalize() *FieldVal { // The field representation leaves 6 bits of overflow in each word so // intermediate calculations can be performed without needing to @@ -435,16 +434,16 @@ func (f *FieldVal) Normalize() *FieldVal { // PutBytesUnchecked unpacks the field value to a 32-byte big-endian value // directly into the passed byte slice in constant time. The target slice must -// have at least 32 bytes available or it will panic. +// must have at least 32 bytes available or it will panic. // // There is a similar function, PutBytes, which unpacks the field value into a // 32-byte array directly. This version is provided since it can be useful // to write directly into part of a larger buffer without needing a separate // allocation. // -// Preconditions: -// - The field value MUST be normalized -// - The target slice MUST have at least 32 bytes available +// Preconditions: +// - The field value MUST be normalized +// - The target slice MUST have at least 32 bytes available func (f *FieldVal) PutBytesUnchecked(b []byte) { // Unpack the 256 total bits from the 10 uint32 words with a max of // 26-bits per word. This could be done with a couple of for loops, @@ -496,8 +495,8 @@ func (f *FieldVal) PutBytesUnchecked(b []byte) { // array and returns that which can sometimes be more ergonomic in applications // that aren't concerned about an additional copy. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) PutBytes(b *[32]byte) { f.PutBytesUnchecked(b[:]) } @@ -509,8 +508,8 @@ func (f *FieldVal) PutBytes(b *[32]byte) { // allowing the caller to reuse a buffer or write directly into part of a larger // buffer. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) Bytes() *[32]byte { b := new([32]byte) f.PutBytesUnchecked(b[:]) @@ -525,8 +524,8 @@ func (f *FieldVal) Bytes() *[32]byte { // operations require a numeric value. See IsZero for the version that returns // a bool. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsZeroBit() uint32 { // The value can only be zero if no bits are set in any of the words. // This is a constant time implementation. @@ -539,8 +538,8 @@ func (f *FieldVal) IsZeroBit() uint32 { // IsZero returns whether or not the field value is equal to zero in constant // time. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsZero() bool { // The value can only be zero if no bits are set in any of the words. // This is a constant time implementation. @@ -558,8 +557,8 @@ func (f *FieldVal) IsZero() bool { // operations require a numeric value. See IsOne for the version that returns a // bool. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsOneBit() uint32 { // The value can only be one if the single lowest significant bit is set in // the first word and no other bits are set in any of the other words. @@ -573,8 +572,8 @@ func (f *FieldVal) IsOneBit() uint32 { // IsOne returns whether or not the field value is equal to one in constant // time. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsOne() bool { // The value can only be one if the single lowest significant bit is set in // the first word and no other bits are set in any of the other words. @@ -593,8 +592,8 @@ func (f *FieldVal) IsOne() bool { // operations require a numeric value. See IsOdd for the version that returns a // bool. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsOddBit() uint32 { // Only odd numbers have the bottom bit set. return f.n[0] & 1 @@ -603,8 +602,8 @@ func (f *FieldVal) IsOddBit() uint32 { // IsOdd returns whether or not the field value is an odd number in constant // time. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsOdd() bool { // Only odd numbers have the bottom bit set. return f.n[0]&1 == 1 @@ -613,8 +612,8 @@ func (f *FieldVal) IsOdd() bool { // Equals returns whether or not the two field values are the same in constant // time. // -// Preconditions: -// - Both field values being compared MUST be normalized +// Preconditions: +// - Both field values being compared MUST be normalized func (f *FieldVal) Equals(val *FieldVal) bool { // Xor only sets bits when they are different, so the two field values // can only be the same if no bits are set after xoring each word. @@ -634,10 +633,10 @@ func (f *FieldVal) Equals(val *FieldVal) bool { // The field value is returned to support chaining. This enables syntax like: // f.NegateVal(f2).AddInt(1) so that f = -f2 + 1. // -// Preconditions: -// - The max magnitude MUST be 63 -// Output Normalized: No -// Output Max Magnitude: Input magnitude + 1 +// Preconditions: +// - The max magnitude MUST be 63 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 func (f *FieldVal) NegateVal(val *FieldVal, magnitude uint32) *FieldVal { // Negation in the field is just the prime minus the value. However, // in order to allow negation against a field value without having to @@ -678,10 +677,10 @@ func (f *FieldVal) NegateVal(val *FieldVal, magnitude uint32) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f.Negate().AddInt(1) so that f = -f + 1. // -// Preconditions: -// - The max magnitude MUST be 63 -// Output Normalized: No -// Output Max Magnitude: Input magnitude + 1 +// Preconditions: +// - The max magnitude MUST be 63 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 func (f *FieldVal) Negate(magnitude uint32) *FieldVal { return f.NegateVal(f, magnitude) } @@ -693,10 +692,10 @@ func (f *FieldVal) Negate(magnitude uint32) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f.AddInt(1).Add(f2) so that f = f + 1 + f2. // -// Preconditions: -// - The field value MUST have a max magnitude of 63 -// Output Normalized: No -// Output Max Magnitude: Existing field magnitude + 1 +// Preconditions: +// - The field value MUST have a max magnitude of 63 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude + 1 func (f *FieldVal) AddInt(ui uint16) *FieldVal { // Since the field representation intentionally provides overflow bits, // it's ok to use carryless addition as the carry bit is safely part of @@ -712,10 +711,10 @@ func (f *FieldVal) AddInt(ui uint16) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f.Add(f2).AddInt(1) so that f = f + f2 + 1. // -// Preconditions: -// - The sum of the magnitudes of the two field values MUST be a max of 64 -// Output Normalized: No -// Output Max Magnitude: Sum of the magnitude of the two individual field values +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 64 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two individual field values func (f *FieldVal) Add(val *FieldVal) *FieldVal { // Since the field representation intentionally provides overflow bits, // it's ok to use carryless addition as the carry bit is safely part of @@ -741,10 +740,10 @@ func (f *FieldVal) Add(val *FieldVal) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f3.Add2(f, f2).AddInt(1) so that f3 = f + f2 + 1. // -// Preconditions: -// - The sum of the magnitudes of the two field values MUST be a max of 64 -// Output Normalized: No -// Output Max Magnitude: Sum of the magnitude of the two field values +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 64 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two field values func (f *FieldVal) Add2(val *FieldVal, val2 *FieldVal) *FieldVal { // Since the field representation intentionally provides overflow bits, // it's ok to use carryless addition as the carry bit is safely part of @@ -773,10 +772,10 @@ func (f *FieldVal) Add2(val *FieldVal, val2 *FieldVal) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f.MulInt(2).Add(f2) so that f = 2 * f + f2. // -// Preconditions: -// - The field value magnitude multiplied by given val MUST be a max of 64 -// Output Normalized: No -// Output Max Magnitude: Existing field magnitude times the provided integer val +// Preconditions: +// - The field value magnitude multiplied by given val MUST be a max of 64 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude times the provided integer val func (f *FieldVal) MulInt(val uint8) *FieldVal { // Since each word of the field representation can hold up to // 32 - fieldBase extra bits which will be normalized out, it's safe @@ -808,26 +807,27 @@ func (f *FieldVal) MulInt(val uint8) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f.Mul(f2).AddInt(1) so that f = (f * f2) + 1. // -// Preconditions: -// - Both field values MUST have a max magnitude of 8 -// Output Normalized: No -// Output Max Magnitude: 1 +// Preconditions: +// - Both field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 func (f *FieldVal) Mul(val *FieldVal) *FieldVal { return f.Mul2(f, val) } -// Mul2 multiplies the passed two field values together and stores the result in -// f in constant time. Note that this function can overflow if multiplying any -// of the individual words exceeds a max uint32. In practice, this means the -// magnitude of either value involved in the multiplication must be a max of 8. +// Mul2 multiplies the passed two field values together and stores the result +// result in f in constant time. Note that this function can overflow if +// multiplying any of the individual words exceeds a max uint32. In practice, +// this means the magnitude of either value involved in the multiplication must +// be a max of 8. // // The field value is returned to support chaining. This enables syntax like: // f3.Mul2(f, f2).AddInt(1) so that f3 = (f * f2) + 1. // -// Preconditions: -// - Both input field values MUST have a max magnitude of 8 -// Output Normalized: No -// Output Max Magnitude: 1 +// Preconditions: +// - Both input field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 func (f *FieldVal) Mul2(val *FieldVal, val2 *FieldVal) *FieldVal { // This could be done with a couple of for loops and an array to store // the intermediate terms, but this unrolled version is significantly @@ -1101,10 +1101,10 @@ func (f *FieldVal) Mul2(val *FieldVal, val2 *FieldVal) *FieldVal { // field must be a max of 8 to prevent overflow. The magnitude of the result // will be 1. // -// Preconditions: -// - The input field value MUST have a max magnitude of 8 -// Output Normalized: No -// Output Max Magnitude: 1 +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 func (f *FieldVal) SquareRootVal(val *FieldVal) bool { // This uses the Tonelli-Shanks method for calculating the square root of // the value when it exists. The key principles of the method follow. @@ -1156,7 +1156,7 @@ func (f *FieldVal) SquareRootVal(val *FieldVal) bool { // 10111111 11111111 11111111 00001100 // // Notice that can be broken up into three windows of consecutive 1s (in - // order of least to most significant) as: + // order of least to most signifcant) as: // // 6-bit window with two bits set (bits 4, 5, 6, 7 unset) // 23-bit window with 22 bits set (bit 30 unset) @@ -1262,10 +1262,10 @@ func (f *FieldVal) SquareRootVal(val *FieldVal) bool { // The field value is returned to support chaining. This enables syntax like: // f.Square().Mul(f2) so that f = f^2 * f2. // -// Preconditions: -// - The field value MUST have a max magnitude of 8 -// Output Normalized: No -// Output Max Magnitude: 1 +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 func (f *FieldVal) Square() *FieldVal { return f.SquareVal(f) } @@ -1278,10 +1278,10 @@ func (f *FieldVal) Square() *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f3.SquareVal(f).Mul(f) so that f3 = f^2 * f = f^3. // -// Preconditions: -// - The input field value MUST have a max magnitude of 8 -// Output Normalized: No -// Output Max Magnitude: 1 +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 func (f *FieldVal) SquareVal(val *FieldVal) *FieldVal { // This could be done with a couple of for loops and an array to store // the intermediate terms, but this unrolled version is significantly @@ -1503,14 +1503,14 @@ func (f *FieldVal) SquareVal(val *FieldVal) *FieldVal { // The field value is returned to support chaining. This enables syntax like: // f.Inverse().Mul(f2) so that f = f^-1 * f2. // -// Preconditions: -// - The field value MUST have a max magnitude of 8 -// Output Normalized: No -// Output Max Magnitude: 1 +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 func (f *FieldVal) Inverse() *FieldVal { // Fermat's little theorem states that for a nonzero number a and prime - // p, a^(p-1) ≡ 1 (mod p). Since the multiplicative inverse is - // a*b ≡ 1 (mod p), it follows that b ≡ a*a^(p-2) ≡ a^(p-1) ≡ 1 (mod p). + // prime p, a^(p-1) = 1 (mod p). Since the multiplicative inverse is + // a*b = 1 (mod p), it follows that b = a*a^(p-2) = a^(p-1) = 1 (mod p). // Thus, a^(p-2) is the multiplicative inverse. // // In order to efficiently compute a^(p-2), p-2 needs to be split into @@ -1614,8 +1614,8 @@ func (f *FieldVal) Inverse() *FieldVal { // IsGtOrEqPrimeMinusOrder returns whether or not the field value exceeds the // group order divided by 2 in constant time. // -// Preconditions: -// - The field value MUST be normalized +// Preconditions: +// - The field value MUST be normalized func (f *FieldVal) IsGtOrEqPrimeMinusOrder() bool { // The secp256k1 prime is equivalent to 2^256 - 4294968273 and the group // order is 2^256 - 432420386565659656852420866394968145599. Thus, diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/genstatics.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/genstatics.go new file mode 100644 index 00000000..fa613deb --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/genstatics.go @@ -0,0 +1,196 @@ +// Copyright (c) 2014-2015 The btcsuite developers +// Copyright (c) 2015-2021 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +// This file is ignored during the regular build due to the following build tag. +// This build tag is set during go generate. +//go:build gensecp256k1 +// +build gensecp256k1 + +package secp256k1 + +// References: +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) + +import ( + "encoding/binary" + "math/big" +) + +// compressedBytePoints are dummy points used so the code which generates the +// real values can compile. +var compressedBytePoints = "" + +// SerializedBytePoints returns a serialized byte slice which contains all of +// the possible points per 8-bit window. This is used to when generating +// compressedbytepoints.go. +func SerializedBytePoints() []byte { + // Calculate G^(2^i) for i in 0..255. These are used to avoid recomputing + // them for each digit of the 8-bit windows. + doublingPoints := make([]JacobianPoint, curveParams.BitSize) + var q JacobianPoint + bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &q) + for i := 0; i < curveParams.BitSize; i++ { + // Q = 2*Q. + doublingPoints[i] = q + DoubleNonConst(&q, &q) + } + + // Separate the bits into byte-sized windows. + curveByteSize := curveParams.BitSize / 8 + serialized := make([]byte, curveByteSize*256*2*10*4) + offset := 0 + for byteNum := 0; byteNum < curveByteSize; byteNum++ { + // Grab the 8 bits that make up this byte from doubling points. + startingBit := 8 * (curveByteSize - byteNum - 1) + windowPoints := doublingPoints[startingBit : startingBit+8] + + // Compute all points in this window, convert them to affine, and + // serialize them. + for i := 0; i < 256; i++ { + var point JacobianPoint + for bit := 0; bit < 8; bit++ { + if i>>uint(bit)&1 == 1 { + AddNonConst(&point, &windowPoints[bit], &point) + } + } + point.ToAffine() + + for i := 0; i < len(point.X.n); i++ { + binary.LittleEndian.PutUint32(serialized[offset:], point.X.n[i]) + offset += 4 + } + for i := 0; i < len(point.Y.n); i++ { + binary.LittleEndian.PutUint32(serialized[offset:], point.Y.n[i]) + offset += 4 + } + } + } + + return serialized +} + +// sqrt returns the square root of the provided big integer using Newton's +// method. It's only compiled and used during generation of pre-computed +// values, so speed is not a huge concern. +func sqrt(n *big.Int) *big.Int { + // Initial guess = 2^(log_2(n)/2) + guess := big.NewInt(2) + guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil) + + // Now refine using Newton's method. + big2 := big.NewInt(2) + prevGuess := big.NewInt(0) + for { + prevGuess.Set(guess) + guess.Add(guess, new(big.Int).Div(n, guess)) + guess.Div(guess, big2) + if guess.Cmp(prevGuess) == 0 { + break + } + } + return guess +} + +// EndomorphismVectors runs the first 3 steps of algorithm 3.74 from [GECC] to +// generate the linearly independent vectors needed to generate a balanced +// length-two representation of a multiplier such that k = k1 + k2λ (mod N) and +// returns them. Since the values will always be the same given the fact that N +// and λ are fixed, the final results can be accelerated by storing the +// precomputed values. +func EndomorphismVectors() (a1, b1, a2, b2 *big.Int) { + bigMinus1 := big.NewInt(-1) + + // This section uses an extended Euclidean algorithm to generate a + // sequence of equations: + // s[i] * N + t[i] * λ = r[i] + + nSqrt := sqrt(curveParams.N) + u, v := new(big.Int).Set(curveParams.N), new(big.Int).Set(endomorphismLambda) + x1, y1 := big.NewInt(1), big.NewInt(0) + x2, y2 := big.NewInt(0), big.NewInt(1) + q, r := new(big.Int), new(big.Int) + qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int) + s, t := new(big.Int), new(big.Int) + ri, ti := new(big.Int), new(big.Int) + a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int) + found, oneMore := false, false + for u.Sign() != 0 { + // q = v/u + q.Div(v, u) + + // r = v - q*u + qu.Mul(q, u) + r.Sub(v, qu) + + // s = x2 - q*x1 + qx1.Mul(q, x1) + s.Sub(x2, qx1) + + // t = y2 - q*y1 + qy1.Mul(q, y1) + t.Sub(y2, qy1) + + // v = u, u = r, x2 = x1, x1 = s, y2 = y1, y1 = t + v.Set(u) + u.Set(r) + x2.Set(x1) + x1.Set(s) + y2.Set(y1) + y1.Set(t) + + // As soon as the remainder is less than the sqrt of n, the + // values of a1 and b1 are known. + if !found && r.Cmp(nSqrt) < 0 { + // When this condition executes ri and ti represent the + // r[i] and t[i] values such that i is the greatest + // index for which r >= sqrt(n). Meanwhile, the current + // r and t values are r[i+1] and t[i+1], respectively. + + // a1 = r[i+1], b1 = -t[i+1] + a1.Set(r) + b1.Mul(t, bigMinus1) + found = true + oneMore = true + + // Skip to the next iteration so ri and ti are not + // modified. + continue + + } else if oneMore { + // When this condition executes ri and ti still + // represent the r[i] and t[i] values while the current + // r and t are r[i+2] and t[i+2], respectively. + + // sum1 = r[i]^2 + t[i]^2 + rSquared := new(big.Int).Mul(ri, ri) + tSquared := new(big.Int).Mul(ti, ti) + sum1 := new(big.Int).Add(rSquared, tSquared) + + // sum2 = r[i+2]^2 + t[i+2]^2 + r2Squared := new(big.Int).Mul(r, r) + t2Squared := new(big.Int).Mul(t, t) + sum2 := new(big.Int).Add(r2Squared, t2Squared) + + // if (r[i]^2 + t[i]^2) <= (r[i+2]^2 + t[i+2]^2) + if sum1.Cmp(sum2) <= 0 { + // a2 = r[i], b2 = -t[i] + a2.Set(ri) + b2.Mul(ti, bigMinus1) + } else { + // a2 = r[i+2], b2 = -t[i+2] + a2.Set(r) + b2.Mul(t, bigMinus1) + } + + // All done. + break + } + + ri.Set(r) + ti.Set(t) + } + + return a1, b1, a2, b2 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go index 91c3d377..9f975b52 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go @@ -1,5 +1,5 @@ // Copyright 2015 The btcsuite developers -// Copyright (c) 2015-2022 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -8,21 +8,17 @@ package secp256k1 import ( "compress/zlib" "encoding/base64" + "encoding/binary" "io" "strings" "sync" ) -//go:generate go run genprecomps.go +//go:generate go run -tags gensecp256k1 genprecomps.go // bytePointTable describes a table used to house pre-computed values for // accelerating scalar base multiplication. -type bytePointTable [32][256]JacobianPoint - -// compressedBytePointsFn is set to a real function by the code generation to -// return the compressed pre-computed values for accelerating scalar base -// multiplication. -var compressedBytePointsFn func() string +type bytePointTable [32][256][2]FieldVal // s256BytePoints houses pre-computed values used to accelerate scalar base // multiplication such that they are only loaded on first use. @@ -42,10 +38,10 @@ var s256BytePoints = func() func() *bytePointTable { var data *bytePointTable mustLoadBytePoints := func() { // There will be no byte points to load when generating them. - if compressedBytePointsFn == nil { + bp := compressedBytePoints + if len(bp) == 0 { return } - bp := compressedBytePointsFn() // Decompress the pre-computed table used to accelerate scalar base // multiplication. @@ -66,12 +62,16 @@ var s256BytePoints = func() func() *bytePointTable { for byteNum := 0; byteNum < len(bytePoints); byteNum++ { // All points in this window. for i := 0; i < len(bytePoints[byteNum]); i++ { - p := &bytePoints[byteNum][i] - p.X.SetByteSlice(serialized[offset:]) - offset += 32 - p.Y.SetByteSlice(serialized[offset:]) - offset += 32 - p.Z.SetInt(1) + px := &bytePoints[byteNum][i][0] + py := &bytePoints[byteNum][i][1] + for i := 0; i < len(px.n); i++ { + px.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) + offset += 4 + } + for i := 0; i < len(py.n); i++ { + py.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) + offset += 4 + } } } data = &bytePoints diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go index 91940b15..8125d9a9 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2023 The Decred developers +// Copyright (c) 2020 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -46,8 +46,6 @@ const ( // // The group order of the curve per [SECG] is: // 0xffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141 - // - // nolint: dupword orderWordZero uint32 = 0xd0364141 orderWordOne uint32 = 0xbfd25e8c orderWordTwo uint32 = 0xaf48a03b @@ -78,8 +76,6 @@ const ( // // The half order of the secp256k1 curve group is: // 0x7fffffff ffffffff ffffffff ffffffff 5d576e73 57a4501d dfe92f46 681b20a0 - // - // nolint: dupword halfOrderWordZero uint32 = 0x681b20a0 halfOrderWordOne uint32 = 0xdfe92f46 halfOrderWordTwo uint32 = 0x57a4501d @@ -104,7 +100,7 @@ var ( // arithmetic over the secp256k1 group order. This means all arithmetic is // performed modulo: // -// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 // // It only implements the arithmetic needed for elliptic curve operations, // however, the operations that are not implemented can typically be worked @@ -178,19 +174,6 @@ func (s *ModNScalar) Zero() { s.n[7] = 0 } -// IsZeroBit returns 1 when the scalar is equal to zero or 0 otherwise in -// constant time. -// -// Note that a bool is not used here because it is not possible in Go to convert -// from a bool to numeric value in constant time and many constant-time -// operations require a numeric value. See IsZero for the version that returns -// a bool. -func (s *ModNScalar) IsZeroBit() uint32 { - // The scalar can only be zero if no bits are set in any of the words. - bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7] - return constantTimeEq(bits, 0) -} - // IsZero returns whether or not the scalar is equal to zero in constant time. func (s *ModNScalar) IsZero() bool { // The scalar can only be zero if no bits are set in any of the words. @@ -368,8 +351,8 @@ func (s *ModNScalar) SetByteSlice(b []byte) bool { } // PutBytesUnchecked unpacks the scalar to a 32-byte big-endian value directly -// into the passed byte slice in constant time. The target slice must have at -// least 32 bytes available or it will panic. +// into the passed byte slice in constant time. The target slice must must have +// at least 32 bytes available or it will panic. // // There is a similar function, PutBytes, which unpacks the scalar into a // 32-byte array directly. This version is provided since it can be useful to diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go index ca3e8da2..3590346c 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go @@ -1,13 +1,13 @@ // Copyright (c) 2013-2014 The btcsuite developers -// Copyright (c) 2015-2023 The Decred developers +// Copyright (c) 2015-2020 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package secp256k1 import ( - cryptorand "crypto/rand" - "io" + "crypto/ecdsa" + "crypto/rand" ) // PrivateKey provides facilities for working with secp256k1 private keys within @@ -27,61 +27,27 @@ func NewPrivateKey(key *ModNScalar) *PrivateKey { // interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1], // where N is the order of the curve. // -// WARNING: This means passing a slice with more than 32 bytes is truncated and -// that truncated value is reduced modulo N. Further, 0 is not a valid private -// key. It is up to the caller to provide a value in the appropriate range of -// [1, N-1]. Failure to do so will either result in an invalid private key or -// potentially weak private keys that have bias that could be exploited. +// Note that this means passing a slice with more than 32 bytes is truncated and +// that truncated value is reduced modulo N. It is up to the caller to either +// provide a value in the appropriate range or choose to accept the described +// behavior. // -// This function primarily exists to provide a mechanism for converting -// serialized private keys that are already known to be good. -// -// Typically callers should make use of GeneratePrivateKey or -// GeneratePrivateKeyFromRand when creating private keys since they properly -// handle generation of appropriate values. +// Typically callers should simply make use of GeneratePrivateKey when creating +// private keys which properly handles generation of appropriate values. func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey { var privKey PrivateKey privKey.Key.SetByteSlice(privKeyBytes) return &privKey } -// generatePrivateKey generates and returns a new private key that is suitable -// for use with secp256k1 using the provided reader as a source of entropy. The -// provided reader must be a source of cryptographically secure randomness to -// avoid weak private keys. -func generatePrivateKey(rand io.Reader) (*PrivateKey, error) { - // The group order is close enough to 2^256 that there is only roughly a 1 - // in 2^128 chance of generating an invalid private key, so this loop will - // virtually never run more than a single iteration in practice. - var key PrivateKey - var b32 [32]byte - for valid := false; !valid; { - if _, err := io.ReadFull(rand, b32[:]); err != nil { - return nil, err - } - - // The private key is only valid when it is in the range [1, N-1], where - // N is the order of the curve. - overflow := key.Key.SetBytes(&b32) - valid = (key.Key.IsZeroBit() | overflow) == 0 - } - zeroArray32(&b32) - - return &key, nil -} - -// GeneratePrivateKey generates and returns a new cryptographically secure -// private key that is suitable for use with secp256k1. +// GeneratePrivateKey returns a private key that is suitable for use with +// secp256k1. func GeneratePrivateKey() (*PrivateKey, error) { - return generatePrivateKey(cryptorand.Reader) -} - -// GeneratePrivateKeyFromRand generates a private key that is suitable for use -// with secp256k1 using the provided reader as a source of entropy. The -// provided reader must be a source of cryptographically secure randomness, such -// as [crypto/rand.Reader], to avoid weak private keys. -func GeneratePrivateKeyFromRand(rand io.Reader) (*PrivateKey, error) { - return generatePrivateKey(rand) + key, err := ecdsa.GenerateKey(S256(), rand.Reader) + if err != nil { + return nil, err + } + return PrivKeyFromBytes(key.D.Bytes()), nil } // PubKey computes and returns the public key corresponding to this private key. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go index 54c54be5..67165833 100644 --- a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2014 The btcsuite developers -// Copyright (c) 2015-2022 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -92,16 +92,11 @@ func NewPublicKey(x, y *FieldVal) *PublicKey { // hybrid formats as follows: // // Compressed: -// -// <32-byte X coordinate> -// +// <32-byte X coordinate> // Uncompressed: -// -// <32-byte X coordinate><32-byte Y coordinate> -// +// <32-byte X coordinate><32-byte Y coordinate> // Hybrid: -// -// <32-byte X coordinate><32-byte Y coordinate> +// <32-byte X coordinate><32-byte Y coordinate> // // NOTE: The hybrid format makes little sense in practice an therefore this // package will not produce public keys serialized in this format. However, @@ -214,9 +209,9 @@ func (p PublicKey) SerializeCompressed() []byte { return b[:] } -// IsEqual compares this public key instance to the one passed, returning true -// if both public keys are equivalent. A public key is equivalent to another, -// if they both have the same X and Y coordinates. +// IsEqual compares this PublicKey instance to the one passed, returning true if +// both PublicKeys are equivalent. A PublicKey is equivalent to another, if they +// both have the same X and Y coordinate. func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool { return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y) } diff --git a/vendor/github.com/gabriel-vasile/mimetype/LICENSE b/vendor/github.com/gabriel-vasile/mimetype/LICENSE index 13b61daa..6aac070c 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/LICENSE +++ b/vendor/github.com/gabriel-vasile/mimetype/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Gabriel Vasile +Copyright (c) 2018-2020 Gabriel Vasile Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/gabriel-vasile/mimetype/README.md b/vendor/github.com/gabriel-vasile/mimetype/README.md index fd6c533e..231b2919 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/README.md +++ b/vendor/github.com/gabriel-vasile/mimetype/README.md @@ -16,6 +16,9 @@ Go report card + + Code coverage + License diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/archive.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/archive.go index 554ac4d4..fec11f08 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/archive.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/archive.go @@ -3,7 +3,6 @@ package magic import ( "bytes" "encoding/binary" - "strconv" ) var ( @@ -75,87 +74,51 @@ func CRX(raw []byte, limit uint32) bool { } // Tar matches a (t)ape (ar)chive file. -// Tar files are divided into 512 bytes records. First record contains a 257 -// bytes header padded with NUL. func Tar(raw []byte, _ uint32) bool { - const sizeRecord = 512 - - // The structure of a tar header: - // type TarHeader struct { - // Name [100]byte - // Mode [8]byte - // Uid [8]byte - // Gid [8]byte - // Size [12]byte - // Mtime [12]byte - // Chksum [8]byte - // Linkflag byte - // Linkname [100]byte - // Magic [8]byte - // Uname [32]byte - // Gname [32]byte - // Devmajor [8]byte - // Devminor [8]byte - // } - - if len(raw) < sizeRecord { - return false + // The "magic" header field for files in in UStar (POSIX IEEE P1003.1) archives + // has the prefix "ustar". The values of the remaining bytes in this field vary + // by archiver implementation. + if len(raw) >= 512 && bytes.HasPrefix(raw[257:], []byte{0x75, 0x73, 0x74, 0x61, 0x72}) { + return true } - raw = raw[:sizeRecord] - // First 100 bytes of the header represent the file name. - // Check if file looks like Gentoo GLEP binary package. - if bytes.Contains(raw[:100], []byte("/gpkg-1\x00")) { + if len(raw) < 256 { return false } - // Get the checksum recorded into the file. - recsum, err := tarParseOctal(raw[148:156]) - if err != nil { - return false - } - sum1, sum2 := tarChksum(raw) - return recsum == sum1 || recsum == sum2 -} - -// tarParseOctal converts octal string to decimal int. -func tarParseOctal(b []byte) (int64, error) { - // Because unused fields are filled with NULs, we need to skip leading NULs. - // Fields may also be padded with spaces or NULs. - // So we remove leading and trailing NULs and spaces to be sure. - b = bytes.Trim(b, " \x00") - - if len(b) == 0 { - return 0, nil - } - x, err := strconv.ParseUint(tarParseString(b), 8, 64) - if err != nil { - return 0, err + // The older v7 format has no "magic" field, and therefore must be identified + // with heuristics based on legal ranges of values for other header fields: + // https://www.nationalarchives.gov.uk/PRONOM/Format/proFormatSearch.aspx?status=detailReport&id=385&strPageToDisplay=signatures + rules := []struct { + min, max uint8 + i int + }{ + {0x21, 0xEF, 0}, + {0x30, 0x37, 105}, + {0x20, 0x37, 106}, + {0x00, 0x00, 107}, + {0x30, 0x37, 113}, + {0x20, 0x37, 114}, + {0x00, 0x00, 115}, + {0x30, 0x37, 121}, + {0x20, 0x37, 122}, + {0x00, 0x00, 123}, + {0x30, 0x37, 134}, + {0x30, 0x37, 146}, + {0x30, 0x37, 153}, + {0x00, 0x37, 154}, } - return int64(x), nil -} - -// tarParseString converts a NUL ended bytes slice to a string. -func tarParseString(b []byte) string { - if i := bytes.IndexByte(b, 0); i >= 0 { - return string(b[:i]) + for _, r := range rules { + if raw[r.i] < r.min || raw[r.i] > r.max { + return false + } } - return string(b) -} -// tarChksum computes the checksum for the header block b. -// The actual checksum is written to same b block after it has been calculated. -// Before calculation the bytes from b reserved for checksum have placeholder -// value of ASCII space 0x20. -// POSIX specifies a sum of the unsigned byte values, but the Sun tar used -// signed byte values. We compute and return both. -func tarChksum(b []byte) (unsigned, signed int64) { - for i, c := range b { - if 148 <= i && i < 156 { - c = ' ' // Treat the checksum field itself as all spaces. + for _, i := range []uint8{135, 147, 155} { + if raw[i] != 0x00 && raw[i] != 0x20 { + return false } - unsigned += int64(c) - signed += int64(int8(c)) } - return unsigned, signed + + return true } diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go index 3ce1de11..34b84f40 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go @@ -153,11 +153,8 @@ func ftyp(sigs ...[]byte) Detector { if len(raw) < 12 { return false } - if !bytes.Equal(raw[4:8], []byte("ftyp")) { - return false - } for _, s := range sigs { - if bytes.Equal(raw[8:12], s) { + if bytes.Equal(raw[4:12], append([]byte("ftyp"), s...)) { return true } } diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text.go index 9f1a637b..e2a03caf 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text.go @@ -1,6 +1,7 @@ package magic import ( + "bufio" "bytes" "strings" "time" @@ -233,10 +234,9 @@ func GeoJSON(raw []byte, limit uint32) bool { // types. func NdJSON(raw []byte, limit uint32) bool { lCount, hasObjOrArr := 0, false - raw = dropLastLine(raw, limit) - var l []byte - for len(raw) != 0 { - l, raw = scanLine(raw) + sc := bufio.NewScanner(dropLastLine(raw, limit)) + for sc.Scan() { + l := sc.Bytes() // Empty lines are allowed in NDJSON. if l = trimRWS(trimLWS(l)); len(l) == 0 { continue @@ -301,15 +301,20 @@ func Svg(raw []byte, limit uint32) bool { } // Srt matches a SubRip file. -func Srt(raw []byte, _ uint32) bool { - line, raw := scanLine(raw) - +func Srt(in []byte, _ uint32) bool { + s := bufio.NewScanner(bytes.NewReader(in)) + if !s.Scan() { + return false + } // First line must be 1. - if string(line) != "1" { + if s.Text() != "1" { + return false + } + + if !s.Scan() { return false } - line, raw = scanLine(raw) - secondLine := string(line) + secondLine := s.Text() // Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine // length to exactly 29 characters. if len(secondLine) != 29 { @@ -320,12 +325,14 @@ func Srt(raw []byte, _ uint32) bool { if strings.Contains(secondLine, ".") { return false } + // For Go <1.17, comma is not recognised as a decimal separator by `time.Parse`. + secondLine = strings.ReplaceAll(secondLine, ",", ".") // Second line must be a time range. ts := strings.Split(secondLine, " --> ") if len(ts) != 2 { return false } - const layout = "15:04:05,000" + const layout = "15:04:05.000" t0, err := time.Parse(layout, ts[0]) if err != nil { return false @@ -338,9 +345,8 @@ func Srt(raw []byte, _ uint32) bool { return false } - line, _ = scanLine(raw) // A third line must exist and not be empty. This is the actual subtitle text. - return len(line) != 0 + return s.Scan() && len(s.Bytes()) != 0 } // Vtt matches a Web Video Text Tracks (WebVTT) file. See @@ -367,15 +373,3 @@ func Vtt(raw []byte, limit uint32) bool { return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT" bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT" } - -// dropCR drops a terminal \r from the data. -func dropCR(data []byte) []byte { - if len(data) > 0 && data[len(data)-1] == '\r' { - return data[0 : len(data)-1] - } - return data -} -func scanLine(b []byte) (line, remainder []byte) { - line, remainder, _ = bytes.Cut(b, []byte("\n")) - return dropCR(line), remainder -} diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go index af256438..84ed6492 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go @@ -18,7 +18,7 @@ func Tsv(raw []byte, limit uint32) bool { } func sv(in []byte, comma rune, limit uint32) bool { - r := csv.NewReader(bytes.NewReader(dropLastLine(in, limit))) + r := csv.NewReader(dropLastLine(in, limit)) r.Comma = comma r.ReuseRecord = true r.LazyQuotes = true @@ -44,14 +44,20 @@ func sv(in []byte, comma rune, limit uint32) bool { // mimetype limits itself to ReadLimit bytes when performing a detection. // This means, for file formats like CSV for NDJSON, the last line of the input // can be an incomplete line. -func dropLastLine(b []byte, readLimit uint32) []byte { - if readLimit == 0 || uint32(len(b)) < readLimit { - return b +func dropLastLine(b []byte, cutAt uint32) io.Reader { + if cutAt == 0 { + return bytes.NewReader(b) } - for i := len(b) - 1; i > 0; i-- { - if b[i] == '\n' { - return b[:i] + if uint32(len(b)) >= cutAt { + for i := cutAt - 1; i > 0; i-- { + if b[i] == '\n' { + return bytes.NewReader(b[:i]) + } } + + // No newline was found between the 0 index and cutAt. + return bytes.NewReader(b[:cutAt]) } - return b + + return bytes.NewReader(b) } diff --git a/vendor/github.com/gabriel-vasile/mimetype/mimetype.go b/vendor/github.com/gabriel-vasile/mimetype/mimetype.go index d8d512b8..1b5909b7 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/mimetype.go +++ b/vendor/github.com/gabriel-vasile/mimetype/mimetype.go @@ -7,15 +7,14 @@ package mimetype import ( "io" + "io/ioutil" "mime" "os" "sync/atomic" ) -var defaultLimit uint32 = 3072 - // readLimit is the maximum number of bytes from the input used when detecting. -var readLimit uint32 = defaultLimit +var readLimit uint32 = 3072 // Detect returns the MIME type found from the provided byte slice. // @@ -49,7 +48,7 @@ func DetectReader(r io.Reader) (*MIME, error) { // Using atomic because readLimit can be written at the same time in other goroutine. l := atomic.LoadUint32(&readLimit) if l == 0 { - in, err = io.ReadAll(r) + in, err = ioutil.ReadAll(r) if err != nil { return errMIME, err } @@ -104,7 +103,6 @@ func EqualsAny(s string, mimes ...string) bool { // SetLimit sets the maximum number of bytes read from input when detecting the MIME type. // Increasing the limit provides better detection for file formats which store // their magical numbers towards the end of the file: docx, pptx, xlsx, etc. -// During detection data is read in a single block of size limit, i.e. it is not buffered. // A limit of 0 means the whole input file will be used. func SetLimit(limit uint32) { // Using atomic because readLimit can be read at the same time in other goroutine. diff --git a/vendor/github.com/gballet/go-libpcsclite/error.go b/vendor/github.com/gballet/go-libpcsclite/error.go index 87cfee3d..4710de5e 100644 --- a/vendor/github.com/gballet/go-libpcsclite/error.go +++ b/vendor/github.com/gballet/go-libpcsclite/error.go @@ -36,66 +36,66 @@ type ErrorCode uint32 const ( SCardSuccess ErrorCode = 0x00000000 /* No error was encountered. */ - ErrSCardInternal ErrorCode = 0x80100001 /* An internal consistency check failed. */ - ErrSCardCancelled ErrorCode = 0x80100002 /* The action was cancelled by an SCardCancel request. */ - ErrSCardInvalidHandle ErrorCode = 0x80100003 /* The supplied handle was invalid. */ - ErrSCardInvalidParameter ErrorCode = 0x80100004 /* One or more of the supplied parameters could not be properly interpreted. */ - ErrSCardInvalidTarget ErrorCode = 0x80100005 /* Registry startup information is missing or invalid. */ - ErrSCardNoMemory ErrorCode = 0x80100006 /* Not enough memory available to complete this command. */ - ErrSCardWaitedTooLong ErrorCode = 0x80100007 /* An internal consistency timer has expired. */ - ErrSCardInsufficientBuffer ErrorCode = 0x80100008 /* The data buffer to receive returned data is too small for the returned data. */ - ErrScardUnknownReader ErrorCode = 0x80100009 /* The specified reader name is not recognized. */ - ErrSCardTimeout ErrorCode = 0x8010000A /* The user-specified timeout value has expired. */ - ErrSCardSharingViolation ErrorCode = 0x8010000B /* The smart card cannot be accessed because of other connections outstanding. */ - ErrSCardNoSmartCard ErrorCode = 0x8010000C /* The operation requires a Smart Card, but no Smart Card is currently in the device. */ - ErrSCardUnknownCard ErrorCode = 0x8010000D /* The specified smart card name is not recognized. */ - ErrSCardCannotDispose ErrorCode = 0x8010000E /* The system could not dispose of the media in the requested manner. */ - ErrSCardProtoMismatch ErrorCode = 0x8010000F /* The requested protocols are incompatible with the protocol currently in use with the smart card. */ - ErrSCardNotReady ErrorCode = 0x80100010 /* The reader or smart card is not ready to accept commands. */ - ErrSCardInvalidValue ErrorCode = 0x80100011 /* One or more of the supplied parameters values could not be properly interpreted. */ - ErrSCardSystemCancelled ErrorCode = 0x80100012 /* The action was cancelled by the system, presumably to log off or shut down. */ - ErrSCardCommError ErrorCode = 0x80100013 /* An internal communications error has been detected. */ - ErrScardUnknownError ErrorCode = 0x80100014 /* An internal error has been detected, but the source is unknown. */ - ErrSCardInvalidATR ErrorCode = 0x80100015 /* An ATR obtained from the registry is not a valid ATR string. */ - ErrSCardNotTransacted ErrorCode = 0x80100016 /* An attempt was made to end a non-existent transaction. */ - ErrSCardReaderUnavailable ErrorCode = 0x80100017 /* The specified reader is not currently available for use. */ - ErrSCardShutdown ErrorCode = 0x80100018 /* The operation has been aborted to allow the server application to exit. */ - ErrSCardPCITooSmall ErrorCode = 0x80100019 /* The PCI Receive buffer was too small. */ - ErrSCardReaderUnsupported ErrorCode = 0x8010001A /* The reader driver does not meet minimal requirements for support. */ - ErrSCardDuplicateReader ErrorCode = 0x8010001B /* The reader driver did not produce a unique reader name. */ - ErrSCardCardUnsupported ErrorCode = 0x8010001C /* The smart card does not meet minimal requirements for support. */ - ErrScardNoService ErrorCode = 0x8010001D /* The Smart card resource manager is not running. */ - ErrSCardServiceStopped ErrorCode = 0x8010001E /* The Smart card resource manager has shut down. */ - ErrSCardUnexpected ErrorCode = 0x8010001F /* An unexpected card error has occurred. */ - ErrSCardUnsupportedFeature ErrorCode = 0x8010001F /* This smart card does not support the requested feature. */ - ErrSCardICCInstallation ErrorCode = 0x80100020 /* No primary provider can be found for the smart card. */ - ErrSCardICCCreateOrder ErrorCode = 0x80100021 /* The requested order of object creation is not supported. */ - ErrSCardDirNotFound ErrorCode = 0x80100023 /* The identified directory does not exist in the smart card. */ - ErrSCardFileNotFound ErrorCode = 0x80100024 /* The identified file does not exist in the smart card. */ - ErrSCardNoDir ErrorCode = 0x80100025 /* The supplied path does not represent a smart card directory. */ - ErrSCardNoFile ErrorCode = 0x80100026 /* The supplied path does not represent a smart card file. */ - ErrScardNoAccess ErrorCode = 0x80100027 /* Access is denied to this file. */ - ErrSCardWriteTooMany ErrorCode = 0x80100028 /* The smart card does not have enough memory to store the information. */ - ErrSCardBadSeek ErrorCode = 0x80100029 /* There was an error trying to set the smart card file object pointer. */ - ErrSCardInvalidCHV ErrorCode = 0x8010002A /* The supplied PIN is incorrect. */ - ErrSCardUnknownResMNG ErrorCode = 0x8010002B /* An unrecognized error code was returned from a layered component. */ - ErrSCardNoSuchCertificate ErrorCode = 0x8010002C /* The requested certificate does not exist. */ - ErrSCardCertificateUnavailable ErrorCode = 0x8010002D /* The requested certificate could not be obtained. */ - ErrSCardNoReadersAvailable ErrorCode = 0x8010002E /* Cannot find a smart card reader. */ - ErrSCardCommDataLost ErrorCode = 0x8010002F /* A communications error with the smart card has been detected. Retry the operation. */ - ErrScardNoKeyContainer ErrorCode = 0x80100030 /* The requested key container does not exist on the smart card. */ - ErrSCardServerTooBusy ErrorCode = 0x80100031 /* The Smart Card Resource Manager is too busy to complete this operation. */ - ErrSCardUnsupportedCard ErrorCode = 0x80100065 /* The reader cannot communicate with the card, due to ATR string configuration conflicts. */ - ErrSCardUnresponsiveCard ErrorCode = 0x80100066 /* The smart card is not responding to a reset. */ - ErrSCardUnpoweredCard ErrorCode = 0x80100067 /* Power has been removed from the smart card, so that further communication is not possible. */ - ErrSCardResetCard ErrorCode = 0x80100068 /* The smart card has been reset, so any shared state information is invalid. */ - ErrSCardRemovedCard ErrorCode = 0x80100069 /* The smart card has been removed, so further communication is not possible. */ - ErrSCardSecurityViolation ErrorCode = 0x8010006A /* Access was denied because of a security violation. */ - ErrSCardWrongCHV ErrorCode = 0x8010006B /* The card cannot be accessed because the wrong PIN was presented. */ - ErrSCardCHVBlocked ErrorCode = 0x8010006C /* The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */ - ErrSCardEOF ErrorCode = 0x8010006D /* The end of the smart card file has been reached. */ - ErrSCardCancelledByUser ErrorCode = 0x8010006E /* The user pressed "Cancel" on a Smart Card Selection Dialog. */ - ErrSCardCardNotAuthenticated ErrorCode = 0x8010006F /* No PIN was presented to the smart card. */ + ErrSCardInternal = 0x80100001 /* An internal consistency check failed. */ + ErrSCardCancelled = 0x80100002 /* The action was cancelled by an SCardCancel request. */ + ErrSCardInvalidHandle = 0x80100003 /* The supplied handle was invalid. */ + ErrSCardInvalidParameter = 0x80100004 /* One or more of the supplied parameters could not be properly interpreted. */ + ErrSCardInvalidTarget = 0x80100005 /* Registry startup information is missing or invalid. */ + ErrSCardNoMemory = 0x80100006 /* Not enough memory available to complete this command. */ + ErrSCardWaitedTooLong = 0x80100007 /* An internal consistency timer has expired. */ + ErrSCardInsufficientBuffer = 0x80100008 /* The data buffer to receive returned data is too small for the returned data. */ + ErrScardUnknownReader = 0x80100009 /* The specified reader name is not recognized. */ + ErrSCardTimeout = 0x8010000A /* The user-specified timeout value has expired. */ + ErrSCardSharingViolation = 0x8010000B /* The smart card cannot be accessed because of other connections outstanding. */ + ErrSCardNoSmartCard = 0x8010000C /* The operation requires a Smart Card, but no Smart Card is currently in the device. */ + ErrSCardUnknownCard = 0x8010000D /* The specified smart card name is not recognized. */ + ErrSCardCannotDispose = 0x8010000E /* The system could not dispose of the media in the requested manner. */ + ErrSCardProtoMismatch = 0x8010000F /* The requested protocols are incompatible with the protocol currently in use with the smart card. */ + ErrSCardNotReady = 0x80100010 /* The reader or smart card is not ready to accept commands. */ + ErrSCardInvalidValue = 0x80100011 /* One or more of the supplied parameters values could not be properly interpreted. */ + ErrSCardSystemCancelled = 0x80100012 /* The action was cancelled by the system, presumably to log off or shut down. */ + ErrSCardCommError = 0x80100013 /* An internal communications error has been detected. */ + ErrScardUnknownError = 0x80100014 /* An internal error has been detected, but the source is unknown. */ + ErrSCardInvalidATR = 0x80100015 /* An ATR obtained from the registry is not a valid ATR string. */ + ErrSCardNotTransacted = 0x80100016 /* An attempt was made to end a non-existent transaction. */ + ErrSCardReaderUnavailable = 0x80100017 /* The specified reader is not currently available for use. */ + ErrSCardShutdown = 0x80100018 /* The operation has been aborted to allow the server application to exit. */ + ErrSCardPCITooSmall = 0x80100019 /* The PCI Receive buffer was too small. */ + ErrSCardReaderUnsupported = 0x8010001A /* The reader driver does not meet minimal requirements for support. */ + ErrSCardDuplicateReader = 0x8010001B /* The reader driver did not produce a unique reader name. */ + ErrSCardCardUnsupported = 0x8010001C /* The smart card does not meet minimal requirements for support. */ + ErrScardNoService = 0x8010001D /* The Smart card resource manager is not running. */ + ErrSCardServiceStopped = 0x8010001E /* The Smart card resource manager has shut down. */ + ErrSCardUnexpected = 0x8010001F /* An unexpected card error has occurred. */ + ErrSCardUnsupportedFeature = 0x8010001F /* This smart card does not support the requested feature. */ + ErrSCardICCInstallation = 0x80100020 /* No primary provider can be found for the smart card. */ + ErrSCardICCCreateOrder = 0x80100021 /* The requested order of object creation is not supported. */ + ErrSCardDirNotFound = 0x80100023 /* The identified directory does not exist in the smart card. */ + ErrSCardFileNotFound = 0x80100024 /* The identified file does not exist in the smart card. */ + ErrSCardNoDir = 0x80100025 /* The supplied path does not represent a smart card directory. */ + ErrSCardNoFile = 0x80100026 /* The supplied path does not represent a smart card file. */ + ErrScardNoAccess = 0x80100027 /* Access is denied to this file. */ + ErrSCardWriteTooMany = 0x80100028 /* The smart card does not have enough memory to store the information. */ + ErrSCardBadSeek = 0x80100029 /* There was an error trying to set the smart card file object pointer. */ + ErrSCardInvalidCHV = 0x8010002A /* The supplied PIN is incorrect. */ + ErrSCardUnknownResMNG = 0x8010002B /* An unrecognized error code was returned from a layered component. */ + ErrSCardNoSuchCertificate = 0x8010002C /* The requested certificate does not exist. */ + ErrSCardCertificateUnavailable = 0x8010002D /* The requested certificate could not be obtained. */ + ErrSCardNoReadersAvailable = 0x8010002E /* Cannot find a smart card reader. */ + ErrSCardCommDataLost = 0x8010002F /* A communications error with the smart card has been detected. Retry the operation. */ + ErrScardNoKeyContainer = 0x80100030 /* The requested key container does not exist on the smart card. */ + ErrSCardServerTooBusy = 0x80100031 /* The Smart Card Resource Manager is too busy to complete this operation. */ + ErrSCardUnsupportedCard = 0x80100065 /* The reader cannot communicate with the card, due to ATR string configuration conflicts. */ + ErrSCardUnresponsiveCard = 0x80100066 /* The smart card is not responding to a reset. */ + ErrSCardUnpoweredCard = 0x80100067 /* Power has been removed from the smart card, so that further communication is not possible. */ + ErrSCardResetCard = 0x80100068 /* The smart card has been reset, so any shared state information is invalid. */ + ErrSCardRemovedCard = 0x80100069 /* The smart card has been removed, so further communication is not possible. */ + ErrSCardSecurityViolation = 0x8010006A /* Access was denied because of a security violation. */ + ErrSCardWrongCHV = 0x8010006B /* The card cannot be accessed because the wrong PIN was presented. */ + ErrSCardCHVBlocked = 0x8010006C /* The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */ + ErrSCardEOF = 0x8010006D /* The end of the smart card file has been reached. */ + ErrSCardCancelledByUser = 0x8010006E /* The user pressed "Cancel" on a Smart Card Selection Dialog. */ + ErrSCardCardNotAuthenticated = 0x8010006F /* No PIN was presented to the smart card. */ ) // Code returns the error code, with an uint32 type to be used in PutUInt32 @@ -106,95 +106,95 @@ func (code ErrorCode) Code() uint32 { func (code ErrorCode) Error() error { switch code { case SCardSuccess: - return fmt.Errorf("command successful") + return fmt.Errorf("Command successful") case ErrSCardInternal: - return fmt.Errorf("internal error") + return fmt.Errorf("Internal error") case ErrSCardCancelled: - return fmt.Errorf("command cancelled") + return fmt.Errorf("Command cancelled") case ErrSCardInvalidHandle: - return fmt.Errorf("invalid handle") + return fmt.Errorf("Invalid handle") case ErrSCardInvalidParameter: - return fmt.Errorf("invalid parameter given") + return fmt.Errorf("Invalid parameter given") case ErrSCardInvalidTarget: - return fmt.Errorf("invalid target given") + return fmt.Errorf("Invalid target given") case ErrSCardNoMemory: - return fmt.Errorf("not enough memory") + return fmt.Errorf("Not enough memory") case ErrSCardWaitedTooLong: - return fmt.Errorf("waited too long") + return fmt.Errorf("Waited too long") case ErrSCardInsufficientBuffer: - return fmt.Errorf("insufficient buffer") + return fmt.Errorf("Insufficient buffer") case ErrScardUnknownReader: - return fmt.Errorf("unknown reader specified") + return fmt.Errorf("Unknown reader specified") case ErrSCardTimeout: - return fmt.Errorf("command timeout") + return fmt.Errorf("Command timeout") case ErrSCardSharingViolation: - return fmt.Errorf("sharing violation") + return fmt.Errorf("Sharing violation") case ErrSCardNoSmartCard: - return fmt.Errorf("no smart card inserted") + return fmt.Errorf("No smart card inserted") case ErrSCardUnknownCard: - return fmt.Errorf("unknown card") + return fmt.Errorf("Unknown card") case ErrSCardCannotDispose: - return fmt.Errorf("cannot dispose handle") + return fmt.Errorf("Cannot dispose handle") case ErrSCardProtoMismatch: - return fmt.Errorf("card protocol mismatch") + return fmt.Errorf("Card protocol mismatch") case ErrSCardNotReady: - return fmt.Errorf("subsystem not ready") + return fmt.Errorf("Subsystem not ready") case ErrSCardInvalidValue: - return fmt.Errorf("invalid value given") + return fmt.Errorf("Invalid value given") case ErrSCardSystemCancelled: - return fmt.Errorf("system cancelled") + return fmt.Errorf("System cancelled") case ErrSCardCommError: - return fmt.Errorf("rpc transport error") + return fmt.Errorf("RPC transport error") case ErrScardUnknownError: - return fmt.Errorf("unknown error") + return fmt.Errorf("Unknown error") case ErrSCardInvalidATR: - return fmt.Errorf("invalid ATR") + return fmt.Errorf("Invalid ATR") case ErrSCardNotTransacted: - return fmt.Errorf("transaction failed") + return fmt.Errorf("Transaction failed") case ErrSCardReaderUnavailable: - return fmt.Errorf("reader is unavailable") + return fmt.Errorf("Reader is unavailable") /* case SCARD_P_SHUTDOWN: */ case ErrSCardPCITooSmall: return fmt.Errorf("PCI struct too small") case ErrSCardReaderUnsupported: - return fmt.Errorf("reader is unsupported") + return fmt.Errorf("Reader is unsupported") case ErrSCardDuplicateReader: - return fmt.Errorf("reader already exists") + return fmt.Errorf("Reader already exists") case ErrSCardCardUnsupported: - return fmt.Errorf("card is unsupported") + return fmt.Errorf("Card is unsupported") case ErrScardNoService: - return fmt.Errorf("service not available") + return fmt.Errorf("Service not available") case ErrSCardServiceStopped: - return fmt.Errorf("service was stopped") + return fmt.Errorf("Service was stopped") /* case SCARD_E_UNEXPECTED: */ /* case SCARD_E_ICC_CREATEORDER: */ @@ -210,7 +210,7 @@ func (code ErrorCode) Error() error { /* case SCARD_E_NO_SUCH_CERTIFICATE: */ /* case SCARD_E_CERTIFICATE_UNAVAILABLE: */ case ErrSCardNoReadersAvailable: - return fmt.Errorf("cannot find a smart card reader") + return fmt.Errorf("Cannot find a smart card reader") /* case SCARD_E_COMM_DATA_LOST: */ /* case SCARD_E_NO_KEY_CONTAINER: */ @@ -238,7 +238,7 @@ func (code ErrorCode) Error() error { /* case SCARD_W_CARD_NOT_AUTHENTICATED: */ case ErrSCardUnsupportedFeature: - return fmt.Errorf("feature not supported") + return fmt.Errorf("Feature not supported") default: return fmt.Errorf("unknown error: %08x", code) diff --git a/vendor/github.com/gballet/go-libpcsclite/winscard.go b/vendor/github.com/gballet/go-libpcsclite/winscard.go index 791c974f..b916db16 100644 --- a/vendor/github.com/gballet/go-libpcsclite/winscard.go +++ b/vendor/github.com/gballet/go-libpcsclite/winscard.go @@ -291,16 +291,16 @@ func (client *Client) Connect(name string, shareMode uint32, preferredProtocol u * * These data are passed throw the field \c sharedSegmentMsg.data. */ -//type transmit struct { -//hCard uint32 -//ioSendPciProtocol uint32 -//ioSendPciLength uint32 -//cbSendLength uint32 -//ioRecvPciProtocol uint32 -//ioRecvPciLength uint32 -//pcbRecvLength uint32 -//rv uint32 -//} +type transmit struct { + hCard uint32 + ioSendPciProtocol uint32 + ioSendPciLength uint32 + cbSendLength uint32 + ioRecvPciProtocol uint32 + ioRecvPciLength uint32 + pcbRecvLength uint32 + rv uint32 +} // SCardIoRequest contains the info needed for performing an IO request type SCardIoRequest struct { @@ -336,7 +336,7 @@ func (card *Card) Transmit(adpu []byte) ([]byte, *SCardIoRequest, error) { return nil, nil, err } if n != len(adpu) { - return nil, nil, fmt.Errorf("invalid number of bytes written: expected %d, got %d", len(adpu), n) + return nil, nil, fmt.Errorf("Invalid number of bytes written: expected %d, got %d", len(adpu), n) } response := [TransmitRequestLength]byte{} total := 0 diff --git a/vendor/github.com/gdamore/encoding/.travis.yml b/vendor/github.com/gdamore/encoding/.travis.yml new file mode 100644 index 00000000..50424138 --- /dev/null +++ b/vendor/github.com/gdamore/encoding/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - 1.9.x + - 1.10.x + - 1.11.x + - tip diff --git a/vendor/github.com/gdamore/encoding/CODE_OF_CONDUCT.md b/vendor/github.com/gdamore/encoding/CODE_OF_CONDUCT.md deleted file mode 100644 index 65527da0..00000000 --- a/vendor/github.com/gdamore/encoding/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,73 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at garrett@damore.org. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org diff --git a/vendor/github.com/gdamore/encoding/README.md b/vendor/github.com/gdamore/encoding/README.md index 2ce29a9f..3db2b4c5 100644 --- a/vendor/github.com/gdamore/encoding/README.md +++ b/vendor/github.com/gdamore/encoding/README.md @@ -1,11 +1,10 @@ ## encoding - -[![Linux](https://img.shields.io/github/actions/workflow/status/gdamore/encoding/linux.yml?branch=main&logoColor=grey&logo=linux&label=)](https://github.com/gdamore/encoding/actions/workflows/linux.yml) -[![Windows](https://img.shields.io/github/actions/workflow/status/gdamore/encoding/windows.yml?branch=main&logoColor=grey&logo=windows&label=)](https://github.com/gdamore/encoding/actions/workflows/windows.yml) -[![Apache License](https://img.shields.io/github/license/gdamore/encoding.svg?logoColor=silver&logo=opensourceinitiative&color=blue&label=)](https://github.com/gdamore/encoding/blob/master/LICENSE) -[![Coverage](https://img.shields.io/codecov/c/github/gdamore/encoding?logoColor=grey&logo=codecov&label=)](https://codecov.io/gh/gdamore/encoding) +[![Linux Status](https://img.shields.io/travis/gdamore/encoding.svg?label=linux)](https://travis-ci.org/gdamore/encoding) +[![Windows Status](https://img.shields.io/appveyor/ci/gdamore/encoding.svg?label=windows)](https://ci.appveyor.com/project/gdamore/encoding) +[![Apache License](https://img.shields.io/badge/license-APACHE2-blue.svg)](https://github.com/gdamore/encoding/blob/master/LICENSE) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/gdamore/encoding) +[![Go Report Card](http://goreportcard.com/badge/gdamore/encoding)](http://goreportcard.com/report/gdamore/encoding) Package encoding provides a number of encodings that are missing from the standard Go [encoding]("https://godoc.org/golang.org/x/text/encoding") package. diff --git a/vendor/github.com/gdamore/encoding/SECURITY.md b/vendor/github.com/gdamore/encoding/SECURITY.md deleted file mode 100644 index b9f64966..00000000 --- a/vendor/github.com/gdamore/encoding/SECURITY.md +++ /dev/null @@ -1,12 +0,0 @@ -# Security Policy - -We take security very seriously in mangos, since you may be using it in -Internet-facing applications. - -## Reporting a Vulnerability - -To report a vulnerability, please contact us on our discord. -You may also send an email to garrett@damore.org, or info@staysail.tech. - -We will keep the reporter updated on any status updates on a regular basis, -and will respond within two business days for any reported security issue. diff --git a/vendor/github.com/gdamore/encoding/charmap.go b/vendor/github.com/gdamore/encoding/charmap.go index e8089c45..db1c33ef 100644 --- a/vendor/github.com/gdamore/encoding/charmap.go +++ b/vendor/github.com/gdamore/encoding/charmap.go @@ -1,4 +1,4 @@ -// Copyright 2024 Garrett D'Amore +// Copyright 2015 Garrett D'Amore // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use file except in compliance with the License. @@ -52,6 +52,7 @@ const ( // direction takes about 100 nsec/op. (The larger cost for conversion // from UTF-8 is most likely due to the need to convert the UTF-8 byte stream // to a rune before conversion. +// type Charmap struct { transform.NopResetter bytes map[rune]byte @@ -176,7 +177,7 @@ func (d *cmapEncoder) Transform(dst, src []byte, atEOF bool) (int, int, error) { if r == utf8.RuneError && sz == 1 { // If its inconclusive due to insufficient data in // in the source, report it - if atEOF && !utf8.FullRune(src[nsrc:]) { + if !atEOF && !utf8.FullRune(src[nsrc:]) { e = transform.ErrShortSrc break } diff --git a/vendor/github.com/getsentry/sentry-go/CHANGELOG.md b/vendor/github.com/getsentry/sentry-go/CHANGELOG.md index 046f49c4..4d267072 100644 --- a/vendor/github.com/getsentry/sentry-go/CHANGELOG.md +++ b/vendor/github.com/getsentry/sentry-go/CHANGELOG.md @@ -1,34 +1,5 @@ # Changelog -## 0.28.1 - -The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.28.1. - -### Bug Fixes - -- Implement `http.ResponseWriter` to hook into various parts of the response process ([#837](https://github.com/getsentry/sentry-go/pull/837)) - -## 0.28.0 - -The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.28.0. - -### Features - -- Add a `Fiber` performance tracing & error reporting integration ([#795](https://github.com/getsentry/sentry-go/pull/795)) -- Add performance tracing to the `Echo` integration ([#722](https://github.com/getsentry/sentry-go/pull/722)) -- Add performance tracing to the `FastHTTP` integration ([#732](https://github.com/getsentry/sentry-go/pull/723)) -- Add performance tracing to the `Iris` integration ([#809](https://github.com/getsentry/sentry-go/pull/809)) -- Add performance tracing to the `Negroni` integration ([#808](https://github.com/getsentry/sentry-go/pull/808)) -- Add `FailureIssueThreshold` & `RecoveryThreshold` to `MonitorConfig` ([#775](https://github.com/getsentry/sentry-go/pull/775)) -- Use `errors.Unwrap()` to create exception groups ([#792](https://github.com/getsentry/sentry-go/pull/792)) -- Add support for matching on strings for `ClientOptions.IgnoreErrors` & `ClientOptions.IgnoreTransactions` ([#819](https://github.com/getsentry/sentry-go/pull/819)) -- Add `http.request.method` attribute for performance span data ([#786](https://github.com/getsentry/sentry-go/pull/786)) -- Accept `interface{}` for span data values ([#784](https://github.com/getsentry/sentry-go/pull/784)) - -### Bug Fixes - -- Fix missing stack trace for parsing error in `logrusentry` ([#689](https://github.com/getsentry/sentry-go/pull/689)) - ## 0.27.0 The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.27.0. diff --git a/vendor/github.com/getsentry/sentry-go/README.md b/vendor/github.com/getsentry/sentry-go/README.md index 73cbdbc6..82f9293f 100644 --- a/vendor/github.com/getsentry/sentry-go/README.md +++ b/vendor/github.com/getsentry/sentry-go/README.md @@ -13,6 +13,7 @@ [![Build Status](https://github.com/getsentry/sentry-go/workflows/go-workflow/badge.svg)](https://github.com/getsentry/sentry-go/actions?query=workflow%3Ago-workflow) [![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/sentry-go)](https://goreportcard.com/report/github.com/getsentry/sentry-go) [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +[![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go) [![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go) `sentry-go` provides a Sentry client implementation for the Go programming @@ -84,6 +85,7 @@ checkout the official documentation: - [Bug Tracker](https://github.com/getsentry/sentry-go/issues) - [GitHub Project](https://github.com/getsentry/sentry-go) +- [![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go) - [![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go) - [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/go/) - [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-go.svg)](https://github.com/getsentry/sentry-go/discussions) diff --git a/vendor/github.com/getsentry/sentry-go/check_in.go b/vendor/github.com/getsentry/sentry-go/check_in.go index de6d0adb..d41ba3d2 100644 --- a/vendor/github.com/getsentry/sentry-go/check_in.go +++ b/vendor/github.com/getsentry/sentry-go/check_in.go @@ -87,10 +87,6 @@ type MonitorConfig struct { //nolint: maligned // prefer readability over optima // A tz database string representing the timezone which the monitor's execution schedule is in. // See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones Timezone string `json:"timezone,omitempty"` - // The number of consecutive failed check-ins it takes before an issue is created. - FailureIssueThreshold int64 `json:"failure_issue_threshold,omitempty"` - // The number of consecutive OK check-ins it takes before an issue is resolved. - RecoveryThreshold int64 `json:"recovery_threshold,omitempty"` } type CheckIn struct { //nolint: maligned // prefer readability over optimal memory layout diff --git a/vendor/github.com/getsentry/sentry-go/dsn.go b/vendor/github.com/getsentry/sentry-go/dsn.go index ac6991a4..52d9b9f7 100644 --- a/vendor/github.com/getsentry/sentry-go/dsn.go +++ b/vendor/github.com/getsentry/sentry-go/dsn.go @@ -90,10 +90,11 @@ func NewDsn(rawURL string) (*Dsn, error) { // Port var port int if parsedURL.Port() != "" { - port, err = strconv.Atoi(parsedURL.Port()) + parsedPort, err := strconv.Atoi(parsedURL.Port()) if err != nil { return nil, &DsnParseError{"invalid port"} } + port = parsedPort } else { port = scheme.defaultPort() } diff --git a/vendor/github.com/getsentry/sentry-go/integrations.go b/vendor/github.com/getsentry/sentry-go/integrations.go index a8b2082a..4d76bef6 100644 --- a/vendor/github.com/getsentry/sentry-go/integrations.go +++ b/vendor/github.com/getsentry/sentry-go/integrations.go @@ -140,7 +140,7 @@ func (iei *ignoreErrorsIntegration) processor(event *Event, _ *EventHint) *Event for _, suspect := range suspects { for _, pattern := range iei.ignoreErrors { - if pattern.Match([]byte(suspect)) || strings.Contains(suspect, pattern.String()) { + if pattern.Match([]byte(suspect)) { Logger.Printf("Event dropped due to being matched by `IgnoreErrors` option."+ "| Value matched: %s | Filter used: %s", suspect, pattern) return nil @@ -202,7 +202,7 @@ func (iei *ignoreTransactionsIntegration) processor(event *Event, _ *EventHint) } for _, pattern := range iei.ignoreTransactions { - if pattern.Match([]byte(suspect)) || strings.Contains(suspect, pattern.String()) { + if pattern.Match([]byte(suspect)) { Logger.Printf("Transaction dropped due to being matched by `IgnoreTransactions` option."+ "| Value matched: %s | Filter used: %s", suspect, pattern) return nil diff --git a/vendor/github.com/getsentry/sentry-go/interfaces.go b/vendor/github.com/getsentry/sentry-go/interfaces.go index 35686a02..c769faa7 100644 --- a/vendor/github.com/getsentry/sentry-go/interfaces.go +++ b/vendor/github.com/getsentry/sentry-go/interfaces.go @@ -3,7 +3,6 @@ package sentry import ( "context" "encoding/json" - "errors" "fmt" "net" "net/http" @@ -25,9 +24,6 @@ const profileType = "profile" // checkInType is the type of a check in event. const checkInType = "check_in" -// metricType is the type of a metric event. -const metricType = "statsd" - // Level marks the severity of the event. type Level string @@ -40,6 +36,15 @@ const ( LevelFatal Level = "fatal" ) +func getSensitiveHeaders() map[string]bool { + return map[string]bool{ + "Authorization": true, + "Cookie": true, + "X-Forwarded-For": true, + "X-Real-Ip": true, + } +} + // SdkInfo contains all metadata about about the SDK being used. type SdkInfo struct { Name string `json:"name,omitempty"` @@ -165,13 +170,6 @@ type Request struct { Env map[string]string `json:"env,omitempty"` } -var sensitiveHeaders = map[string]struct{}{ - "Authorization": {}, - "Cookie": {}, - "X-Forwarded-For": {}, - "X-Real-Ip": {}, -} - // NewRequest returns a new Sentry Request from the given http.Request. // // NewRequest avoids operations that depend on network access. In particular, it @@ -202,6 +200,7 @@ func NewRequest(r *http.Request) *Request { env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port} } } else { + sensitiveHeaders := getSensitiveHeaders() for k, v := range r.Header { if _, ok := sensitiveHeaders[k]; !ok { headers[k] = strings.Join(v, ",") @@ -223,15 +222,11 @@ func NewRequest(r *http.Request) *Request { // Mechanism is the mechanism by which an exception was generated and handled. type Mechanism struct { - Type string `json:"type,omitempty"` - Description string `json:"description,omitempty"` - HelpLink string `json:"help_link,omitempty"` - Source string `json:"source,omitempty"` - Handled *bool `json:"handled,omitempty"` - ParentID *int `json:"parent_id,omitempty"` - ExceptionID int `json:"exception_id"` - IsExceptionGroup bool `json:"is_exception_group,omitempty"` - Data map[string]any `json:"data,omitempty"` + Type string `json:"type,omitempty"` + Description string `json:"description,omitempty"` + HelpLink string `json:"help_link,omitempty"` + Handled *bool `json:"handled,omitempty"` + Data map[string]interface{} `json:"data,omitempty"` } // SetUnhandled indicates that the exception is an unhandled exception, i.e. @@ -323,7 +318,6 @@ type Event struct { Exception []Exception `json:"exception,omitempty"` DebugMeta *DebugMeta `json:"debug_meta,omitempty"` Attachments []*Attachment `json:"-"` - Metrics []Metric `json:"-"` // The fields below are only relevant for transactions. @@ -345,43 +339,27 @@ type Event struct { // SetException appends the unwrapped errors to the event's exception list. // // maxErrorDepth is the maximum depth of the error chain we will look -// into while unwrapping the errors. If maxErrorDepth is -1, we will -// unwrap all errors in the chain. +// into while unwrapping the errors. func (e *Event) SetException(exception error, maxErrorDepth int) { - if exception == nil { + err := exception + if err == nil { return } - err := exception - - for i := 0; err != nil && (i < maxErrorDepth || maxErrorDepth == -1); i++ { - // Add the current error to the exception slice with its details + for i := 0; i < maxErrorDepth && err != nil; i++ { e.Exception = append(e.Exception, Exception{ Value: err.Error(), Type: reflect.TypeOf(err).String(), Stacktrace: ExtractStacktrace(err), }) - - // Attempt to unwrap the error using the standard library's Unwrap method. - // If errors.Unwrap returns nil, it means either there is no error to unwrap, - // or the error does not implement the Unwrap method. - unwrappedErr := errors.Unwrap(err) - - if unwrappedErr != nil { - // The error was successfully unwrapped using the standard library's Unwrap method. - err = unwrappedErr - continue + switch previous := err.(type) { + case interface{ Unwrap() error }: + err = previous.Unwrap() + case interface{ Cause() error }: + err = previous.Cause() + default: + err = nil } - - cause, ok := err.(interface{ Cause() error }) - if !ok { - // We cannot unwrap the error further. - break - } - - // The error implements the Cause method, indicating it may have been wrapped - // using the github.com/pkg/errors package. - err = cause.Cause() } // Add a trace of the current stack to the most recent error in a chain if @@ -392,23 +370,8 @@ func (e *Event) SetException(exception error, maxErrorDepth int) { e.Exception[0].Stacktrace = NewStacktrace() } - if len(e.Exception) <= 1 { - return - } - // event.Exception should be sorted such that the most recent error is last. reverse(e.Exception) - - for i := range e.Exception { - e.Exception[i].Mechanism = &Mechanism{ - IsExceptionGroup: true, - ExceptionID: i, - } - if i == 0 { - continue - } - e.Exception[i].Mechanism.ParentID = Pointer(i - 1) - } } // TODO: Event.Contexts map[string]interface{} => map[string]EventContext, @@ -529,12 +492,13 @@ func (e *Event) checkInMarshalJSON() ([]byte, error) { // NewEvent creates a new Event. func NewEvent() *Event { - return &Event{ + event := Event{ Contexts: make(map[string]Context), Extra: make(map[string]interface{}), Tags: make(map[string]string), Modules: make(map[string]string), } + return &event } // Thread specifies threads that were running at the time of an event. diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go index 2db76d2b..cf5dff50 100644 --- a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go @@ -32,14 +32,15 @@ var knownCategories = map[Category]struct{}{ // String returns the category formatted for debugging. func (c Category) String() string { - if c == "" { + switch c { + case "": return "CategoryAll" + default: + caser := cases.Title(language.English) + rv := "Category" + for _, w := range strings.Fields(string(c)) { + rv += caser.String(w) + } + return rv } - - caser := cases.Title(language.English) - rv := "Category" - for _, w := range strings.Fields(string(c)) { - rv += caser.String(w) - } - return rv } diff --git a/vendor/github.com/getsentry/sentry-go/metrics.go b/vendor/github.com/getsentry/sentry-go/metrics.go deleted file mode 100644 index bcc94e88..00000000 --- a/vendor/github.com/getsentry/sentry-go/metrics.go +++ /dev/null @@ -1,427 +0,0 @@ -package sentry - -import ( - "fmt" - "hash/crc32" - "math" - "regexp" - "sort" - "strings" -) - -type ( - NumberOrString interface { - int | string - } - - void struct{} -) - -var ( - member void - keyRegex = regexp.MustCompile(`[^a-zA-Z0-9_/.-]+`) - valueRegex = regexp.MustCompile(`[^\w\d\s_:/@\.{}\[\]$-]+`) - unitRegex = regexp.MustCompile(`[^a-z]+`) -) - -type MetricUnit struct { - unit string -} - -func (m MetricUnit) toString() string { - return m.unit -} - -func NanoSecond() MetricUnit { - return MetricUnit{ - "nanosecond", - } -} - -func MicroSecond() MetricUnit { - return MetricUnit{ - "microsecond", - } -} - -func MilliSecond() MetricUnit { - return MetricUnit{ - "millisecond", - } -} - -func Second() MetricUnit { - return MetricUnit{ - "second", - } -} - -func Minute() MetricUnit { - return MetricUnit{ - "minute", - } -} - -func Hour() MetricUnit { - return MetricUnit{ - "hour", - } -} - -func Day() MetricUnit { - return MetricUnit{ - "day", - } -} - -func Week() MetricUnit { - return MetricUnit{ - "week", - } -} - -func Bit() MetricUnit { - return MetricUnit{ - "bit", - } -} - -func Byte() MetricUnit { - return MetricUnit{ - "byte", - } -} - -func KiloByte() MetricUnit { - return MetricUnit{ - "kilobyte", - } -} - -func KibiByte() MetricUnit { - return MetricUnit{ - "kibibyte", - } -} - -func MegaByte() MetricUnit { - return MetricUnit{ - "megabyte", - } -} - -func MebiByte() MetricUnit { - return MetricUnit{ - "mebibyte", - } -} - -func GigaByte() MetricUnit { - return MetricUnit{ - "gigabyte", - } -} - -func GibiByte() MetricUnit { - return MetricUnit{ - "gibibyte", - } -} - -func TeraByte() MetricUnit { - return MetricUnit{ - "terabyte", - } -} - -func TebiByte() MetricUnit { - return MetricUnit{ - "tebibyte", - } -} - -func PetaByte() MetricUnit { - return MetricUnit{ - "petabyte", - } -} - -func PebiByte() MetricUnit { - return MetricUnit{ - "pebibyte", - } -} - -func ExaByte() MetricUnit { - return MetricUnit{ - "exabyte", - } -} - -func ExbiByte() MetricUnit { - return MetricUnit{ - "exbibyte", - } -} - -func Ratio() MetricUnit { - return MetricUnit{ - "ratio", - } -} - -func Percent() MetricUnit { - return MetricUnit{ - "percent", - } -} - -func CustomUnit(unit string) MetricUnit { - return MetricUnit{ - unitRegex.ReplaceAllString(unit, ""), - } -} - -type Metric interface { - GetType() string - GetTags() map[string]string - GetKey() string - GetUnit() string - GetTimestamp() int64 - SerializeValue() string - SerializeTags() string -} - -type abstractMetric struct { - key string - unit MetricUnit - tags map[string]string - // A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC). - timestamp int64 -} - -func (am abstractMetric) GetTags() map[string]string { - return am.tags -} - -func (am abstractMetric) GetKey() string { - return am.key -} - -func (am abstractMetric) GetUnit() string { - return am.unit.toString() -} - -func (am abstractMetric) GetTimestamp() int64 { - return am.timestamp -} - -func (am abstractMetric) SerializeTags() string { - var sb strings.Builder - - values := make([]string, 0, len(am.tags)) - for k := range am.tags { - values = append(values, k) - } - sortSlice(values) - - for _, key := range values { - val := sanitizeValue(am.tags[key]) - key = sanitizeKey(key) - sb.WriteString(fmt.Sprintf("%s:%s,", key, val)) - } - s := sb.String() - if len(s) > 0 { - s = s[:len(s)-1] - } - return s -} - -// Counter Metric. -type CounterMetric struct { - value float64 - abstractMetric -} - -func (c *CounterMetric) Add(value float64) { - c.value += value -} - -func (c CounterMetric) GetType() string { - return "c" -} - -func (c CounterMetric) SerializeValue() string { - return fmt.Sprintf(":%v", c.value) -} - -// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC). -func NewCounterMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) CounterMetric { - am := abstractMetric{ - key, - unit, - tags, - timestamp, - } - - return CounterMetric{ - value, - am, - } -} - -// Distribution Metric. -type DistributionMetric struct { - values []float64 - abstractMetric -} - -func (d *DistributionMetric) Add(value float64) { - d.values = append(d.values, value) -} - -func (d DistributionMetric) GetType() string { - return "d" -} - -func (d DistributionMetric) SerializeValue() string { - var sb strings.Builder - for _, el := range d.values { - sb.WriteString(fmt.Sprintf(":%v", el)) - } - return sb.String() -} - -// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC). -func NewDistributionMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) DistributionMetric { - am := abstractMetric{ - key, - unit, - tags, - timestamp, - } - - return DistributionMetric{ - []float64{value}, - am, - } -} - -// Gauge Metric. -type GaugeMetric struct { - last float64 - min float64 - max float64 - sum float64 - count float64 - abstractMetric -} - -func (g *GaugeMetric) Add(value float64) { - g.last = value - g.min = math.Min(g.min, value) - g.max = math.Max(g.max, value) - g.sum += value - g.count++ -} - -func (g GaugeMetric) GetType() string { - return "g" -} - -func (g GaugeMetric) SerializeValue() string { - return fmt.Sprintf(":%v:%v:%v:%v:%v", g.last, g.min, g.max, g.sum, g.count) -} - -// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC). -func NewGaugeMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) GaugeMetric { - am := abstractMetric{ - key, - unit, - tags, - timestamp, - } - - return GaugeMetric{ - value, // last - value, // min - value, // max - value, // sum - value, // count - am, - } -} - -// Set Metric. -type SetMetric[T NumberOrString] struct { - values map[T]void - abstractMetric -} - -func (s *SetMetric[T]) Add(value T) { - s.values[value] = member -} - -func (s SetMetric[T]) GetType() string { - return "s" -} - -func (s SetMetric[T]) SerializeValue() string { - _hash := func(s string) uint32 { - return crc32.ChecksumIEEE([]byte(s)) - } - - values := make([]T, 0, len(s.values)) - for k := range s.values { - values = append(values, k) - } - sortSlice(values) - - var sb strings.Builder - for _, el := range values { - switch any(el).(type) { - case int: - sb.WriteString(fmt.Sprintf(":%v", el)) - case string: - s := fmt.Sprintf("%v", el) - sb.WriteString(fmt.Sprintf(":%d", _hash(s))) - } - } - - return sb.String() -} - -// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC). -func NewSetMetric[T NumberOrString](key string, unit MetricUnit, tags map[string]string, timestamp int64, value T) SetMetric[T] { - am := abstractMetric{ - key, - unit, - tags, - timestamp, - } - - return SetMetric[T]{ - map[T]void{ - value: member, - }, - am, - } -} - -func sanitizeKey(s string) string { - return keyRegex.ReplaceAllString(s, "_") -} - -func sanitizeValue(s string) string { - return valueRegex.ReplaceAllString(s, "") -} - -type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string -} - -func sortSlice[T Ordered](s []T) { - sort.Slice(s, func(i, j int) bool { - return s[i] < s[j] - }) -} diff --git a/vendor/github.com/getsentry/sentry-go/sentry.go b/vendor/github.com/getsentry/sentry-go/sentry.go index c8246de0..3df2cdbc 100644 --- a/vendor/github.com/getsentry/sentry-go/sentry.go +++ b/vendor/github.com/getsentry/sentry-go/sentry.go @@ -6,7 +6,7 @@ import ( ) // The version of the SDK. -const SDKVersion = "0.28.1" +const SDKVersion = "0.27.0" // apiVersion is the minimum version of the Sentry API compatible with the // sentry-go SDK. @@ -72,17 +72,18 @@ func Recover() *EventID { // RecoverWithContext captures a panic and passes relevant context object. func RecoverWithContext(ctx context.Context) *EventID { - err := recover() - if err == nil { - return nil - } + if err := recover(); err != nil { + var hub *Hub - hub := GetHubFromContext(ctx) - if hub == nil { - hub = CurrentHub() - } + if HasHubOnContext(ctx) { + hub = GetHubFromContext(ctx) + } else { + hub = CurrentHub() + } - return hub.RecoverWithContext(ctx, err) + return hub.RecoverWithContext(ctx, err) + } + return nil } // WithScope is a shorthand for CurrentHub().WithScope. diff --git a/vendor/github.com/getsentry/sentry-go/traces_profiler.go b/vendor/github.com/getsentry/sentry-go/traces_profiler.go index 23573421..2655fe84 100644 --- a/vendor/github.com/getsentry/sentry-go/traces_profiler.go +++ b/vendor/github.com/getsentry/sentry-go/traces_profiler.go @@ -7,8 +7,8 @@ import ( // Checks whether the transaction should be profiled (according to ProfilesSampleRate) // and starts a profiler if so. -func (s *Span) sampleTransactionProfile() { - var sampleRate = s.clientOptions().ProfilesSampleRate +func (span *Span) sampleTransactionProfile() { + var sampleRate = span.clientOptions().ProfilesSampleRate switch { case sampleRate < 0.0 || sampleRate > 1.0: Logger.Printf("Skipping transaction profiling: ProfilesSampleRate out of range [0.0, 1.0]: %f\n", sampleRate) @@ -19,7 +19,7 @@ func (s *Span) sampleTransactionProfile() { if globalProfiler == nil { Logger.Println("Skipping transaction profiling: the profiler couldn't be started") } else { - s.collectProfile = collectTransactionProfile + span.collectProfile = collectTransactionProfile } } } @@ -69,27 +69,22 @@ func (info *profileInfo) UpdateFromEvent(event *Event) { info.Dist = event.Dist info.Transaction.ID = event.EventID - getStringFromContext := func(context map[string]interface{}, originalValue, key string) string { - v, ok := context[key] - if !ok { - return originalValue + if runtimeContext, ok := event.Contexts["runtime"]; ok { + if value, ok := runtimeContext["name"]; !ok { + info.Runtime.Name = value.(string) } - - if s, ok := v.(string); ok { - return s + if value, ok := runtimeContext["version"]; !ok { + info.Runtime.Version = value.(string) } - - return originalValue - } - - if runtimeContext, ok := event.Contexts["runtime"]; ok { - info.Runtime.Name = getStringFromContext(runtimeContext, info.Runtime.Name, "name") - info.Runtime.Version = getStringFromContext(runtimeContext, info.Runtime.Version, "version") } if osContext, ok := event.Contexts["os"]; ok { - info.OS.Name = getStringFromContext(osContext, info.OS.Name, "name") + if value, ok := osContext["name"]; !ok { + info.OS.Name = value.(string) + } } if deviceContext, ok := event.Contexts["device"]; ok { - info.Device.Architecture = getStringFromContext(deviceContext, info.Device.Architecture, "arch") + if value, ok := deviceContext["arch"]; !ok { + info.Device.Architecture = value.(string) + } } } diff --git a/vendor/github.com/getsentry/sentry-go/tracing.go b/vendor/github.com/getsentry/sentry-go/tracing.go index 1bb53d0d..4d51c0d5 100644 --- a/vendor/github.com/getsentry/sentry-go/tracing.go +++ b/vendor/github.com/getsentry/sentry-go/tracing.go @@ -169,11 +169,11 @@ func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Sp span.Sampled = span.sample() - span.recorder = &spanRecorder{} if hasParent { span.recorder = parent.spanRecorder() + } else { + span.recorder = &spanRecorder{} } - span.recorder.record(&span) hub := hubFromContext(ctx) @@ -226,11 +226,7 @@ func (s *Span) SetTag(name, value string) { // SetData sets a data on the span. It is recommended to use SetData instead of // accessing the data map directly as SetData takes care of initializing the map // when necessary. -func (s *Span) SetData(name string, value interface{}) { - if value == nil { - return - } - +func (s *Span) SetData(name, value string) { s.mu.Lock() defer s.mu.Unlock() diff --git a/vendor/github.com/getsentry/sentry-go/transport.go b/vendor/github.com/getsentry/sentry-go/transport.go index 20f69941..0d034622 100644 --- a/vendor/github.com/getsentry/sentry-go/transport.go +++ b/vendor/github.com/getsentry/sentry-go/transport.go @@ -2,7 +2,6 @@ package sentry import ( "bytes" - "context" "crypto/tls" "encoding/json" "errors" @@ -95,55 +94,6 @@ func getRequestBodyFromEvent(event *Event) []byte { return nil } -func marshalMetrics(metrics []Metric) []byte { - var b bytes.Buffer - for i, metric := range metrics { - b.WriteString(metric.GetKey()) - if unit := metric.GetUnit(); unit != "" { - b.WriteString(fmt.Sprintf("@%s", unit)) - } - b.WriteString(fmt.Sprintf("%s|%s", metric.SerializeValue(), metric.GetType())) - if serializedTags := metric.SerializeTags(); serializedTags != "" { - b.WriteString(fmt.Sprintf("|#%s", serializedTags)) - } - b.WriteString(fmt.Sprintf("|T%d", metric.GetTimestamp())) - - if i < len(metrics)-1 { - b.WriteString("\n") - } - } - return b.Bytes() -} - -func encodeMetric(enc *json.Encoder, b io.Writer, metrics []Metric) error { - body := marshalMetrics(metrics) - // Item header - err := enc.Encode(struct { - Type string `json:"type"` - Length int `json:"length"` - }{ - Type: metricType, - Length: len(body), - }) - if err != nil { - return err - } - - // metric payload - if _, err = b.Write(body); err != nil { - return err - } - - // "Envelopes should be terminated with a trailing newline." - // - // [1]: https://develop.sentry.dev/sdk/envelopes/#envelopes - if _, err := b.Write([]byte("\n")); err != nil { - return err - } - - return err -} - func encodeAttachment(enc *json.Encoder, b io.Writer, attachment *Attachment) error { // Attachment header err := enc.Encode(struct { @@ -225,15 +175,11 @@ func envelopeFromBody(event *Event, dsn *Dsn, sentAt time.Time, body json.RawMes return nil, err } - switch event.Type { - case transactionType, checkInType: + if event.Type == transactionType || event.Type == checkInType { err = encodeEnvelopeItem(enc, event.Type, body) - case metricType: - err = encodeMetric(enc, &b, event.Metrics) - default: + } else { err = encodeEnvelopeItem(enc, eventType, body) } - if err != nil { return nil, err } @@ -260,7 +206,7 @@ func envelopeFromBody(event *Event, dsn *Dsn, sentAt time.Time, body json.RawMes return &b, nil } -func getRequestFromEvent(ctx context.Context, event *Event, dsn *Dsn) (r *http.Request, err error) { +func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) { defer func() { if r != nil { r.Header.Set("User-Agent", fmt.Sprintf("%s/%s", event.Sdk.Name, event.Sdk.Version)) @@ -287,13 +233,7 @@ func getRequestFromEvent(ctx context.Context, event *Event, dsn *Dsn) (r *http.R if err != nil { return nil, err } - - if ctx == nil { - ctx = context.Background() - } - - return http.NewRequestWithContext( - ctx, + return http.NewRequest( http.MethodPost, dsn.GetAPIURL().String(), envelope, @@ -404,13 +344,8 @@ func (t *HTTPTransport) Configure(options ClientOptions) { }) } -// SendEvent assembles a new packet out of Event and sends it to the remote server. +// SendEvent assembles a new packet out of Event and sends it to remote server. func (t *HTTPTransport) SendEvent(event *Event) { - t.SendEventWithContext(context.Background(), event) -} - -// SendEventWithContext assembles a new packet out of Event and sends it to the remote server. -func (t *HTTPTransport) SendEventWithContext(ctx context.Context, event *Event) { if t.dsn == nil { return } @@ -421,7 +356,7 @@ func (t *HTTPTransport) SendEventWithContext(ctx context.Context, event *Event) return } - request, err := getRequestFromEvent(ctx, event, t.dsn) + request, err := getRequestFromEvent(event, t.dsn) if err != nil { return } @@ -543,13 +478,6 @@ func (t *HTTPTransport) worker() { Logger.Printf("There was an issue with sending an event: %v", err) continue } - if response.StatusCode >= 400 && response.StatusCode <= 599 { - b, err := io.ReadAll(response.Body) - if err != nil { - Logger.Printf("Error while reading response code: %v", err) - } - Logger.Printf("Sending %s failed with the following error: %s", eventType, string(b)) - } t.mu.Lock() t.limits.Merge(ratelimit.FromResponse(response)) t.mu.Unlock() @@ -639,13 +567,8 @@ func (t *HTTPSyncTransport) Configure(options ClientOptions) { } } -// SendEvent assembles a new packet out of Event and sends it to the remote server. +// SendEvent assembles a new packet out of Event and sends it to remote server. func (t *HTTPSyncTransport) SendEvent(event *Event) { - t.SendEventWithContext(context.Background(), event) -} - -// SendEventWithContext assembles a new packet out of Event and sends it to the remote server. -func (t *HTTPSyncTransport) SendEventWithContext(ctx context.Context, event *Event) { if t.dsn == nil { return } @@ -654,18 +577,15 @@ func (t *HTTPSyncTransport) SendEventWithContext(ctx context.Context, event *Eve return } - request, err := getRequestFromEvent(ctx, event, t.dsn) + request, err := getRequestFromEvent(event, t.dsn) if err != nil { return } var eventType string - switch { - case event.Type == transactionType: + if event.Type == transactionType { eventType = "transaction" - case event.Type == metricType: - eventType = metricType - default: + } else { eventType = fmt.Sprintf("%s event", event.Level) } Logger.Printf( @@ -681,14 +601,6 @@ func (t *HTTPSyncTransport) SendEventWithContext(ctx context.Context, event *Eve Logger.Printf("There was an issue with sending an event: %v", err) return } - if response.StatusCode >= 400 && response.StatusCode <= 599 { - b, err := io.ReadAll(response.Body) - if err != nil { - Logger.Printf("Error while reading response code: %v", err) - } - Logger.Printf("Sending %s failed with the following error: %s", eventType, string(b)) - } - t.mu.Lock() t.limits.Merge(ratelimit.FromResponse(response)) t.mu.Unlock() diff --git a/vendor/github.com/getsentry/sentry-go/util.go b/vendor/github.com/getsentry/sentry-go/util.go index 8f999ed7..2d2ee4ca 100644 --- a/vendor/github.com/getsentry/sentry-go/util.go +++ b/vendor/github.com/getsentry/sentry-go/util.go @@ -112,7 +112,3 @@ func revisionFromBuildInfo(info *debug.BuildInfo) string { return "" } - -func Pointer[T any](v T) *T { - return &v -} diff --git a/vendor/github.com/gofrs/flock/.golangci.yml b/vendor/github.com/gofrs/flock/.golangci.yml deleted file mode 100644 index 3ad88a38..00000000 --- a/vendor/github.com/gofrs/flock/.golangci.yml +++ /dev/null @@ -1,114 +0,0 @@ -run: - timeout: 10m - -linters: - enable: - - asasalint - - bidichk - - dogsled - - dupword - - durationcheck - - err113 - - errname - - errorlint - - fatcontext - - forbidigo - - gocheckcompilerdirectives - - gochecknoinits - - gocritic - - godot - - godox - - gofumpt - - goheader - - goimports - - gomoddirectives - - goprintffuncname - - gosec - - inamedparam - - interfacebloat - - ireturn - - mirror - - misspell - - nolintlint - - revive - - stylecheck - - tenv - - testifylint - - thelper - - unconvert - - unparam - - usestdlibvars - - whitespace - -linters-settings: - misspell: - locale: US - godox: - keywords: - - FIXME - goheader: - template: |- - Copyright 2015 Tim Heckman. All rights reserved. - Copyright 2018-{{ YEAR }} The Gofrs. All rights reserved. - Use of this source code is governed by the BSD 3-Clause - license that can be found in the LICENSE file. - gofumpt: - extra-rules: true - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - paramTypeCombine # already handle by gofumpt.extra-rules - - whyNoLint # already handle by nonolint - - unnamedResult - - hugeParam - - sloppyReassign - - rangeValCopy - - octalLiteral - - ptrToRefParam - - appendAssign - - ruleguard - - httpNoBody - - exposedSyncMutex - - revive: - rules: - - name: struct-tag - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: exported - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: unused-parameter - - name: unreachable-code - - name: redefines-builtin-id - -issues: - exclude-use-default: true - max-issues-per-linter: 0 - max-same-issues: 0 - -output: - show-stats: true - sort-results: true - sort-order: - - linter - - file diff --git a/vendor/github.com/gofrs/flock/.travis.yml b/vendor/github.com/gofrs/flock/.travis.yml new file mode 100644 index 00000000..b16d040f --- /dev/null +++ b/vendor/github.com/gofrs/flock/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - 1.14.x + - 1.15.x +script: go test -v -check.vv -race ./... +sudo: false +notifications: + email: + on_success: never + on_failure: always diff --git a/vendor/github.com/gofrs/flock/LICENSE b/vendor/github.com/gofrs/flock/LICENSE index 7de525bf..8b8ff36f 100644 --- a/vendor/github.com/gofrs/flock/LICENSE +++ b/vendor/github.com/gofrs/flock/LICENSE @@ -1,4 +1,3 @@ -Copyright (c) 2018-2024, The Gofrs Copyright (c) 2015-2020, Tim Heckman All rights reserved. diff --git a/vendor/github.com/gofrs/flock/Makefile b/vendor/github.com/gofrs/flock/Makefile deleted file mode 100644 index 65c139d6..00000000 --- a/vendor/github.com/gofrs/flock/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: lint test test_race build_cross_os - -default: lint test build_cross_os - -test: - go test -v -cover ./... - -test_race: - CGO_ENABLED=1 go test -v -race ./... - -lint: - golangci-lint run - -build_cross_os: - ./build.sh diff --git a/vendor/github.com/gofrs/flock/README.md b/vendor/github.com/gofrs/flock/README.md index a3479dba..71ce6369 100644 --- a/vendor/github.com/gofrs/flock/README.md +++ b/vendor/github.com/gofrs/flock/README.md @@ -1,22 +1,26 @@ # flock - -[![Go Reference](https://pkg.go.dev/badge/github.com/gofrs/flock.svg)](https://pkg.go.dev/github.com/gofrs/flock) +[![TravisCI Build Status](https://img.shields.io/travis/gofrs/flock/master.svg?style=flat)](https://travis-ci.org/gofrs/flock) +[![GoDoc](https://img.shields.io/badge/godoc-flock-blue.svg?style=flat)](https://godoc.org/github.com/gofrs/flock) [![License](https://img.shields.io/badge/license-BSD_3--Clause-brightgreen.svg?style=flat)](https://github.com/gofrs/flock/blob/master/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/gofrs/flock)](https://goreportcard.com/report/github.com/gofrs/flock) -`flock` implements a thread-safe file lock. +`flock` implements a thread-safe sync.Locker interface for file locking. It also +includes a non-blocking TryLock() function to allow locking without blocking execution. -It also includes a non-blocking `TryLock()` function to allow locking without blocking execution. +## License +`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for more details. -## Installation +## Go Compatibility +This package makes use of the `context` package that was introduced in Go 1.7. As such, this +package has an implicit dependency on Go 1.7+. -```bash +## Installation +``` go get -u github.com/gofrs/flock ``` ## Usage - -```go +```Go import "github.com/gofrs/flock" fileLock := flock.New("/var/lock/go-lock.lock") @@ -34,12 +38,4 @@ if locked { ``` For more detailed usage information take a look at the package API docs on -[GoDoc](https://pkg.go.dev/github.com/gofrs/flock). - -## License - -`flock` is released under the BSD 3-Clause License. See the [`LICENSE`](./LICENSE) file for more details. - -## Project History - -This project was originally `github.com/theckman/go-flock`, it was transferred to Gofrs by the original author [Tim Heckman ](https://github.com/theckman). +[GoDoc](https://godoc.org/github.com/gofrs/flock). diff --git a/vendor/github.com/gofrs/flock/SECURITY.md b/vendor/github.com/gofrs/flock/SECURITY.md deleted file mode 100644 index 01419bd5..00000000 --- a/vendor/github.com/gofrs/flock/SECURITY.md +++ /dev/null @@ -1,21 +0,0 @@ -# Security Policy - -## Supported Versions - -We support the latest version of this library. -We do not guarantee support of previous versions. - -If a defect is reported, it will generally be fixed on the latest version (provided it exists) irrespective of whether it was introduced in a prior version. - -## Reporting a Vulnerability - -To report a potential security vulnerability, please create a [security advisory](https://github.com/gofrs/flock/security/advisories/new). - -For us to respond to your report most effectively, please include any of the following: - -- Steps to reproduce or a proof-of-concept -- Any relevant information, including the versions used - -## Security Scorecard - -This project submits security [results](https://scorecard.dev/viewer/?uri=github.com/gofrs/flock) to the [OpenSSF Scorecard](https://securityscorecards.dev/). diff --git a/vendor/github.com/gofrs/flock/appveyor.yml b/vendor/github.com/gofrs/flock/appveyor.yml new file mode 100644 index 00000000..909b4bf7 --- /dev/null +++ b/vendor/github.com/gofrs/flock/appveyor.yml @@ -0,0 +1,25 @@ +version: '{build}' + +build: false +deploy: false + +clone_folder: 'c:\gopath\src\github.com\gofrs\flock' + +environment: + GOPATH: 'c:\gopath' + GOVERSION: '1.15' + +init: + - git config --global core.autocrlf input + +install: + - rmdir c:\go /s /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi + - msiexec /i go%GOVERSION%.windows-amd64.msi /q + - set Path=c:\go\bin;c:\gopath\bin;%Path% + - go version + - go env + +test_script: + - go get -t ./... + - go test -race -v ./... diff --git a/vendor/github.com/gofrs/flock/build.sh b/vendor/github.com/gofrs/flock/build.sh deleted file mode 100644 index 60f7809f..00000000 --- a/vendor/github.com/gofrs/flock/build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -e - -# Not supported by flock: -# - plan9/* -# - js/wasm -# - wasp1/wasm - -for row in $(go tool dist list -json | jq -r '.[] | @base64'); do - _jq() { - echo ${row} | base64 --decode | jq -r ${1} - } - - GOOS=$(_jq '.GOOS') - GOARCH=$(_jq '.GOARCH') - - echo "$GOOS/$GOARCH" - GOOS=$GOOS GOARCH=$GOARCH go build -done diff --git a/vendor/github.com/gofrs/flock/flock.go b/vendor/github.com/gofrs/flock/flock.go index 4c995515..95c784ca 100644 --- a/vendor/github.com/gofrs/flock/flock.go +++ b/vendor/github.com/gofrs/flock/flock.go @@ -1,5 +1,4 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. @@ -19,29 +18,12 @@ package flock import ( "context" - "io/fs" "os" "runtime" "sync" "time" ) -type Option func(f *Flock) - -// SetFlag sets the flag used to create/open the file. -func SetFlag(flag int) Option { - return func(f *Flock) { - f.flag = flag - } -} - -// SetPermissions sets the OS permissions to set on the file. -func SetPermissions(perm fs.FileMode) Option { - return func(f *Flock) { - f.perm = perm - } -} - // Flock is the struct type to handle file locking. All fields are unexported, // with access to some of the fields provided by getter methods (Path() and Locked()). type Flock struct { @@ -50,37 +32,12 @@ type Flock struct { fh *os.File l bool r bool - - // flag is the flag used to create/open the file. - flag int - // perm is the OS permissions to set on the file. - perm fs.FileMode } // New returns a new instance of *Flock. The only parameter // it takes is the path to the desired lockfile. -func New(path string, opts ...Option) *Flock { - // create it if it doesn't exist, and open the file read-only. - flags := os.O_CREATE - switch runtime.GOOS { - case "aix", "solaris", "illumos": - // AIX cannot preform write-lock (i.e. exclusive) on a read-only file. - flags |= os.O_RDWR - default: - flags |= os.O_RDONLY - } - - f := &Flock{ - path: path, - flag: flags, - perm: fs.FileMode(0o600), - } - - for _, opt := range opts { - opt(f) - } - - return f +func New(path string) *Flock { + return &Flock{path: path} } // NewFlock returns a new instance of *Flock. The only parameter @@ -110,7 +67,6 @@ func (f *Flock) Path() string { func (f *Flock) Locked() bool { f.m.RLock() defer f.m.RUnlock() - return f.l } @@ -120,7 +76,6 @@ func (f *Flock) Locked() bool { func (f *Flock) RLocked() bool { f.m.RLock() defer f.m.RUnlock() - return f.r } @@ -128,18 +83,16 @@ func (f *Flock) String() string { return f.path } -// TryLockContext repeatedly tries to take an exclusive lock until one of the conditions is met: -// - TryLock succeeds -// - TryLock fails with error -// - Context Done channel is closed. +// TryLockContext repeatedly tries to take an exclusive lock until one of the +// conditions is met: TryLock succeeds, TryLock fails with error, or Context +// Done channel is closed. func (f *Flock) TryLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) { return tryCtx(ctx, f.TryLock, retryDelay) } -// TryRLockContext repeatedly tries to take a shared lock until one of the conditions is met: -// - TryRLock succeeds -// - TryRLock fails with error -// - Context Done channel is closed. +// TryRLockContext repeatedly tries to take a shared lock until one of the +// conditions is met: TryRLock succeeds, TryRLock fails with error, or Context +// Done channel is closed. func (f *Flock) TryRLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) { return tryCtx(ctx, f.TryRLock, retryDelay) } @@ -148,12 +101,10 @@ func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Durati if ctx.Err() != nil { return false, ctx.Err() } - for { if ok, err := fn(); ok || err != nil { return ok, err } - select { case <-ctx.Done(): return false, ctx.Err() @@ -165,33 +116,29 @@ func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Durati func (f *Flock) setFh() error { // open a new os.File instance - fh, err := os.OpenFile(f.path, f.flag, f.perm) + // create it if it doesn't exist, and open the file read-only. + flags := os.O_CREATE + if runtime.GOOS == "aix" { + // AIX cannot preform write-lock (ie exclusive) on a + // read-only file. + flags |= os.O_RDWR + } else { + flags |= os.O_RDONLY + } + fh, err := os.OpenFile(f.path, flags, os.FileMode(0600)) if err != nil { return err } - // set the file handle on the struct + // set the filehandle on the struct f.fh = fh - return nil } -// ensure the file handle is closed if no lock is held. +// ensure the file handle is closed if no lock is held func (f *Flock) ensureFhState() { - if f.l || f.r || f.fh == nil { - return + if !f.l && !f.r && f.fh != nil { + f.fh.Close() + f.fh = nil } - - _ = f.fh.Close() - - f.fh = nil -} - -func (f *Flock) reset() { - f.l = false - f.r = false - - _ = f.fh.Close() - - f.fh = nil } diff --git a/vendor/github.com/gofrs/flock/flock_aix.go b/vendor/github.com/gofrs/flock/flock_aix.go new file mode 100644 index 00000000..7277c1b6 --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock_aix.go @@ -0,0 +1,281 @@ +// Copyright 2019 Tim Heckman. All rights reserved. Use of this source code is +// governed by the BSD 3-Clause license that can be found in the LICENSE file. + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code implements the filelock API using POSIX 'fcntl' locks, which attach +// to an (inode, process) pair rather than a file descriptor. To avoid unlocking +// files prematurely when the same file is opened through different descriptors, +// we allow only one read-lock at a time. +// +// This code is adapted from the Go package: +// cmd/go/internal/lockedfile/internal/filelock + +//+build aix + +package flock + +import ( + "errors" + "io" + "os" + "sync" + "syscall" + + "golang.org/x/sys/unix" +) + +type lockType int16 + +const ( + readLock lockType = unix.F_RDLCK + writeLock lockType = unix.F_WRLCK +) + +type cmdType int + +const ( + tryLock cmdType = unix.F_SETLK + waitLock cmdType = unix.F_SETLKW +) + +type inode = uint64 + +type inodeLock struct { + owner *Flock + queue []<-chan *Flock +} + +var ( + mu sync.Mutex + inodes = map[*Flock]inode{} + locks = map[inode]inodeLock{} +) + +// Lock is a blocking call to try and take an exclusive file lock. It will wait +// until it is able to obtain the exclusive file lock. It's recommended that +// TryLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already exclusive-locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. +// +// If the *Flock has a shared lock (RLock), this may transparently replace the +// shared lock with an exclusive lock on some UNIX-like operating systems. Be +// careful when using exclusive locks in conjunction with shared locks +// (RLock()), because calling Unlock() may accidentally release the exclusive +// lock that was once a shared lock. +func (f *Flock) Lock() error { + return f.lock(&f.l, writeLock) +} + +// RLock is a blocking call to try and take a shared file lock. It will wait +// until it is able to obtain the shared file lock. It's recommended that +// TryRLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already shared-locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. +func (f *Flock) RLock() error { + return f.lock(&f.r, readLock) +} + +func (f *Flock) lock(locked *bool, flag lockType) error { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return nil + } + + if f.fh == nil { + if err := f.setFh(); err != nil { + return err + } + defer f.ensureFhState() + } + + if _, err := f.doLock(waitLock, flag, true); err != nil { + return err + } + + *locked = true + return nil +} + +func (f *Flock) doLock(cmd cmdType, lt lockType, blocking bool) (bool, error) { + // POSIX locks apply per inode and process, and the lock for an inode is + // released when *any* descriptor for that inode is closed. So we need to + // synchronize access to each inode internally, and must serialize lock and + // unlock calls that refer to the same inode through different descriptors. + fi, err := f.fh.Stat() + if err != nil { + return false, err + } + ino := inode(fi.Sys().(*syscall.Stat_t).Ino) + + mu.Lock() + if i, dup := inodes[f]; dup && i != ino { + mu.Unlock() + return false, &os.PathError{ + Path: f.Path(), + Err: errors.New("inode for file changed since last Lock or RLock"), + } + } + + inodes[f] = ino + + var wait chan *Flock + l := locks[ino] + if l.owner == f { + // This file already owns the lock, but the call may change its lock type. + } else if l.owner == nil { + // No owner: it's ours now. + l.owner = f + } else if !blocking { + // Already owned: cannot take the lock. + mu.Unlock() + return false, nil + } else { + // Already owned: add a channel to wait on. + wait = make(chan *Flock) + l.queue = append(l.queue, wait) + } + locks[ino] = l + mu.Unlock() + + if wait != nil { + wait <- f + } + + err = setlkw(f.fh.Fd(), cmd, lt) + + if err != nil { + f.doUnlock() + if cmd == tryLock && err == unix.EACCES { + return false, nil + } + return false, err + } + + return true, nil +} + +func (f *Flock) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // if we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked + if (!f.l && !f.r) || f.fh == nil { + return nil + } + + if err := f.doUnlock(); err != nil { + return err + } + + f.fh.Close() + + f.l = false + f.r = false + f.fh = nil + + return nil +} + +func (f *Flock) doUnlock() (err error) { + var owner *Flock + mu.Lock() + ino, ok := inodes[f] + if ok { + owner = locks[ino].owner + } + mu.Unlock() + + if owner == f { + err = setlkw(f.fh.Fd(), waitLock, unix.F_UNLCK) + } + + mu.Lock() + l := locks[ino] + if len(l.queue) == 0 { + // No waiters: remove the map entry. + delete(locks, ino) + } else { + // The first waiter is sending us their file now. + // Receive it and update the queue. + l.owner = <-l.queue[0] + l.queue = l.queue[1:] + locks[ino] = l + } + delete(inodes, f) + mu.Unlock() + + return err +} + +// TryLock is the preferred function for taking an exclusive file lock. This +// function takes an RW-mutex lock before it tries to lock the file, so there is +// the possibility that this function may block for a short time if another +// goroutine is trying to take any action. +// +// The actual file lock is non-blocking. If we are unable to get the exclusive +// file lock, the function will return false instead of waiting for the lock. If +// we get the lock, we also set the *Flock instance as being exclusive-locked. +func (f *Flock) TryLock() (bool, error) { + return f.try(&f.l, writeLock) +} + +// TryRLock is the preferred function for taking a shared file lock. This +// function takes an RW-mutex lock before it tries to lock the file, so there is +// the possibility that this function may block for a short time if another +// goroutine is trying to take any action. +// +// The actual file lock is non-blocking. If we are unable to get the shared file +// lock, the function will return false instead of waiting for the lock. If we +// get the lock, we also set the *Flock instance as being share-locked. +func (f *Flock) TryRLock() (bool, error) { + return f.try(&f.r, readLock) +} + +func (f *Flock) try(locked *bool, flag lockType) (bool, error) { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return true, nil + } + + if f.fh == nil { + if err := f.setFh(); err != nil { + return false, err + } + defer f.ensureFhState() + } + + haslock, err := f.doLock(tryLock, flag, false) + if err != nil { + return false, err + } + + *locked = haslock + return haslock, nil +} + +// setlkw calls FcntlFlock with cmd for the entire file indicated by fd. +func setlkw(fd uintptr, cmd cmdType, lt lockType) error { + for { + err := unix.FcntlFlock(fd, int(cmd), &unix.Flock_t{ + Type: int16(lt), + Whence: io.SeekStart, + Start: 0, + Len: 0, // All bytes. + }) + if err != unix.EINTR { + return err + } + } +} diff --git a/vendor/github.com/gofrs/flock/flock_others.go b/vendor/github.com/gofrs/flock/flock_others.go deleted file mode 100644 index 18b14f1b..00000000 --- a/vendor/github.com/gofrs/flock/flock_others.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build (!unix && !windows) || plan9 - -package flock - -import ( - "errors" - "io/fs" -) - -func (f *Flock) Lock() error { - return &fs.PathError{ - Op: "Lock", - Path: f.Path(), - Err: errors.ErrUnsupported, - } -} - -func (f *Flock) RLock() error { - return &fs.PathError{ - Op: "RLock", - Path: f.Path(), - Err: errors.ErrUnsupported, - } -} - -func (f *Flock) Unlock() error { - return &fs.PathError{ - Op: "Unlock", - Path: f.Path(), - Err: errors.ErrUnsupported, - } -} - -func (f *Flock) TryLock() (bool, error) { - return false, f.Lock() -} - -func (f *Flock) TryRLock() (bool, error) { - return false, f.RLock() -} diff --git a/vendor/github.com/gofrs/flock/flock_unix.go b/vendor/github.com/gofrs/flock/flock_unix.go index 1c9d0793..c315a3e2 100644 --- a/vendor/github.com/gofrs/flock/flock_unix.go +++ b/vendor/github.com/gofrs/flock/flock_unix.go @@ -1,44 +1,42 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. -//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd +// +build !aix,!windows package flock import ( - "errors" "os" - - "golang.org/x/sys/unix" + "syscall" ) -// Lock is a blocking call to try and take an exclusive file lock. -// It will wait until it is able to obtain the exclusive file lock. -// It's recommended that TryLock() be used over this function. -// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// Lock is a blocking call to try and take an exclusive file lock. It will wait +// until it is able to obtain the exclusive file lock. It's recommended that +// TryLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. // -// If we are already exclusive-locked, -// this function short-circuits and returns immediately assuming it can take the mutex lock. +// If we are already exclusive-locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. // -// If the *Flock has a shared lock (RLock), -// this may transparently replace the shared lock with an exclusive lock on some UNIX-like operating systems. -// Be careful when using exclusive locks in conjunction with shared locks (RLock()), -// because calling Unlock() may accidentally release the exclusive lock that was once a shared lock. +// If the *Flock has a shared lock (RLock), this may transparently replace the +// shared lock with an exclusive lock on some UNIX-like operating systems. Be +// careful when using exclusive locks in conjunction with shared locks +// (RLock()), because calling Unlock() may accidentally release the exclusive +// lock that was once a shared lock. func (f *Flock) Lock() error { - return f.lock(&f.l, unix.LOCK_EX) + return f.lock(&f.l, syscall.LOCK_EX) } -// RLock is a blocking call to try and take a shared file lock. -// It will wait until it is able to obtain the shared file lock. -// It's recommended that TryRLock() be used over this function. -// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// RLock is a blocking call to try and take a shared file lock. It will wait +// until it is able to obtain the shared file lock. It's recommended that +// TryRLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. // -// If we are already shared-locked, -// this function short-circuits and returns immediately assuming it can take the mutex lock. +// If we are already shared-locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. func (f *Flock) RLock() error { - return f.lock(&f.r, unix.LOCK_SH) + return f.lock(&f.r, syscall.LOCK_SH) } func (f *Flock) lock(locked *bool, flag int) error { @@ -53,12 +51,10 @@ func (f *Flock) lock(locked *bool, flag int) error { if err := f.setFh(); err != nil { return err } - defer f.ensureFhState() } - err := unix.Flock(int(f.fh.Fd()), flag) - if err != nil { + if err := syscall.Flock(int(f.fh.Fd()), flag); err != nil { shouldRetry, reopenErr := f.reopenFDOnError(err) if reopenErr != nil { return reopenErr @@ -68,74 +64,71 @@ func (f *Flock) lock(locked *bool, flag int) error { return err } - err = unix.Flock(int(f.fh.Fd()), flag) - if err != nil { + if err = syscall.Flock(int(f.fh.Fd()), flag); err != nil { return err } } *locked = true - return nil } -// Unlock is a function to unlock the file. -// This file takes a RW-mutex lock, -// so while it is running the Locked() and RLocked() functions will be blocked. +// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so +// while it is running the Locked() and RLocked() functions will be blocked. // -// This function short-circuits if we are unlocked already. -// If not, it calls unix.LOCK_UN on the file and closes the file descriptor. -// It does not remove the file from disk. It's up to your application to do. +// This function short-circuits if we are unlocked already. If not, it calls +// syscall.LOCK_UN on the file and closes the file descriptor. It does not +// remove the file from disk. It's up to your application to do. // -// Please note, -// if your shared lock became an exclusive lock, -// this may unintentionally drop the exclusive lock if called by the consumer that believes they have a shared lock. -// Please see Lock() for more details. +// Please note, if your shared lock became an exclusive lock this may +// unintentionally drop the exclusive lock if called by the consumer that +// believes they have a shared lock. Please see Lock() for more details. func (f *Flock) Unlock() error { f.m.Lock() defer f.m.Unlock() - // If we aren't locked or if the lockfile instance is nil - // just return a nil error because we are unlocked. + // if we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked if (!f.l && !f.r) || f.fh == nil { return nil } - // Mark the file as unlocked. - err := unix.Flock(int(f.fh.Fd()), unix.LOCK_UN) - if err != nil { + // mark the file as unlocked + if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil { return err } - f.reset() + f.fh.Close() + + f.l = false + f.r = false + f.fh = nil return nil } -// TryLock is the preferred function for taking an exclusive file lock. -// This function takes an RW-mutex lock before it tries to lock the file, -// so there is the possibility that this function may block for a short time -// if another goroutine is trying to take any action. +// TryLock is the preferred function for taking an exclusive file lock. This +// function takes an RW-mutex lock before it tries to lock the file, so there is +// the possibility that this function may block for a short time if another +// goroutine is trying to take any action. // -// The actual file lock is non-blocking. -// If we are unable to get the exclusive file lock, -// the function will return false instead of waiting for the lock. -// If we get the lock, we also set the *Flock instance as being exclusive-locked. +// The actual file lock is non-blocking. If we are unable to get the exclusive +// file lock, the function will return false instead of waiting for the lock. If +// we get the lock, we also set the *Flock instance as being exclusive-locked. func (f *Flock) TryLock() (bool, error) { - return f.try(&f.l, unix.LOCK_EX) + return f.try(&f.l, syscall.LOCK_EX) } -// TryRLock is the preferred function for taking a shared file lock. -// This function takes an RW-mutex lock before it tries to lock the file, -// so there is the possibility that this function may block for a short time -// if another goroutine is trying to take any action. +// TryRLock is the preferred function for taking a shared file lock. This +// function takes an RW-mutex lock before it tries to lock the file, so there is +// the possibility that this function may block for a short time if another +// goroutine is trying to take any action. // -// The actual file lock is non-blocking. -// If we are unable to get the shared file lock, -// the function will return false instead of waiting for the lock. -// If we get the lock, we also set the *Flock instance as being share-locked. +// The actual file lock is non-blocking. If we are unable to get the shared file +// lock, the function will return false instead of waiting for the lock. If we +// get the lock, we also set the *Flock instance as being share-locked. func (f *Flock) TryRLock() (bool, error) { - return f.try(&f.r, unix.LOCK_SH) + return f.try(&f.r, syscall.LOCK_SH) } func (f *Flock) try(locked *bool, flag int) (bool, error) { @@ -150,25 +143,22 @@ func (f *Flock) try(locked *bool, flag int) (bool, error) { if err := f.setFh(); err != nil { return false, err } - defer f.ensureFhState() } var retried bool retry: - err := unix.Flock(int(f.fh.Fd()), flag|unix.LOCK_NB) + err := syscall.Flock(int(f.fh.Fd()), flag|syscall.LOCK_NB) - switch { - case errors.Is(err, unix.EWOULDBLOCK): + switch err { + case syscall.EWOULDBLOCK: return false, nil - case err == nil: + case nil: *locked = true return true, nil } - if !retried { - shouldRetry, reopenErr := f.reopenFDOnError(err) - if reopenErr != nil { + if shouldRetry, reopenErr := f.reopenFDOnError(err); reopenErr != nil { return false, reopenErr } else if shouldRetry { retried = true @@ -179,34 +169,29 @@ retry: return false, err } -// reopenFDOnError determines whether we should reopen the file handle in readwrite mode and try again. -// This comes from `util-linux/sys-utils/flock.c`: -// > Since Linux 3.4 (commit 55725513) -// > Probably NFSv4 where flock() is emulated by fcntl(). +// reopenFDOnError determines whether we should reopen the file handle +// in readwrite mode and try again. This comes from util-linux/sys-utils/flock.c: +// Since Linux 3.4 (commit 55725513) +// Probably NFSv4 where flock() is emulated by fcntl(). func (f *Flock) reopenFDOnError(err error) (bool, error) { - if !errors.Is(err, unix.EIO) && !errors.Is(err, unix.EBADF) { - return false, nil - } - - st, err := f.fh.Stat() - if err != nil { - return false, nil - } - - if st.Mode()&f.perm != f.perm { + if err != syscall.EIO && err != syscall.EBADF { return false, nil } - - _ = f.fh.Close() - f.fh = nil - - // reopen in read-write mode and set the file handle - fh, err := os.OpenFile(f.path, f.flag, f.perm) - if err != nil { - return false, err + if st, err := f.fh.Stat(); err == nil { + // if the file is able to be read and written + if st.Mode()&0600 == 0600 { + f.fh.Close() + f.fh = nil + + // reopen in read-write mode and set the filehandle + fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDWR, os.FileMode(0600)) + if err != nil { + return false, err + } + f.fh = fh + return true, nil + } } - f.fh = fh - - return true, nil + return false, nil } diff --git a/vendor/github.com/gofrs/flock/flock_unix_fcntl.go b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go deleted file mode 100644 index e8825161..00000000 --- a/vendor/github.com/gofrs/flock/flock_unix_fcntl.go +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. -// Use of this source code is governed by the BSD 3-Clause -// license that can be found in the LICENSE file. - -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This code implements the filelock API using POSIX 'fcntl' locks, -// which attach to an (inode, process) pair rather than a file descriptor. -// To avoid unlocking files prematurely when the same file is opened through different descriptors, -// we allow only one read-lock at a time. -// -// This code is adapted from the Go package (go.22): -// https://github.com/golang/go/blob/release-branch.go1.22/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go - -//go:build aix || (solaris && !illumos) - -package flock - -import ( - "errors" - "io" - "io/fs" - "math/rand" - "sync" - "syscall" - "time" - - "golang.org/x/sys/unix" -) - -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L28 -type lockType int16 - -// String returns the name of the function corresponding to lt -// (Lock, RLock, or Unlock). -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go#L67 -func (lt lockType) String() string { - switch lt { - case readLock: - return "RLock" - case writeLock: - return "Lock" - default: - return "Unlock" - } -} - -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L30-L33 -const ( - readLock lockType = unix.F_RDLCK - writeLock lockType = unix.F_WRLCK -) - -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L35 -type inode = uint64 - -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L37-L40 -type inodeLock struct { - owner *Flock - queue []<-chan *Flock -} - -type cmdType int - -const ( - tryLock cmdType = unix.F_SETLK - waitLock cmdType = unix.F_SETLKW -) - -var ( - mu sync.Mutex - inodes = map[*Flock]inode{} - locks = map[inode]inodeLock{} -) - -// Lock is a blocking call to try and take an exclusive file lock. -// It will wait until it is able to obtain the exclusive file lock. -// It's recommended that TryLock() be used over this function. -// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. -// -// If we are already exclusive-locked, this function short-circuits and -// returns immediately assuming it can take the mutex lock. -// -// If the *Flock has a shared lock (RLock), -// this may transparently replace the shared lock with an exclusive lock on some UNIX-like operating systems. -// Be careful when using exclusive locks in conjunction with shared locks (RLock()), -// because calling Unlock() may accidentally release the exclusive lock that was once a shared lock. -func (f *Flock) Lock() error { - return f.lock(&f.l, writeLock) -} - -// RLock is a blocking call to try and take a shared file lock. -// It will wait until it is able to obtain the shared file lock. -// It's recommended that TryRLock() be used over this function. -// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. -// -// If we are already shared-locked, this function short-circuits and -// returns immediately assuming it can take the mutex lock. -func (f *Flock) RLock() error { - return f.lock(&f.r, readLock) -} - -func (f *Flock) lock(locked *bool, flag lockType) error { - f.m.Lock() - defer f.m.Unlock() - - if *locked { - return nil - } - - if f.fh == nil { - if err := f.setFh(); err != nil { - return err - } - - defer f.ensureFhState() - } - - _, err := f.doLock(waitLock, flag, true) - if err != nil { - return err - } - - *locked = true - - return nil -} - -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L48 -func (f *Flock) doLock(cmd cmdType, lt lockType, blocking bool) (bool, error) { - // POSIX locks apply per inode and process, - // and the lock for an inode is released when *any* descriptor for that inode is closed. - // So we need to synchronize access to each inode internally, - // and must serialize lock and unlock calls that refer to the same inode through different descriptors. - fi, err := f.fh.Stat() - if err != nil { - return false, err - } - - // Note(ldez): don't replace `syscall.Stat_t` by `unix.Stat_t` because `FileInfo.Sys()` returns `syscall.Stat_t` - ino := fi.Sys().(*syscall.Stat_t).Ino - - mu.Lock() - - if i, dup := inodes[f]; dup && i != ino { - mu.Unlock() - return false, &fs.PathError{ - Op: lt.String(), - Path: f.Path(), - Err: errors.New("inode for file changed since last Lock or RLock"), - } - } - - inodes[f] = ino - - var wait chan *Flock - - l := locks[ino] - - switch { - case l.owner == f: - // This file already owns the lock, but the call may change its lock type. - case l.owner == nil: - // No owner: it's ours now. - l.owner = f - - case !blocking: - // Already owned: cannot take the lock. - mu.Unlock() - return false, nil - - default: - // Already owned: add a channel to wait on. - wait = make(chan *Flock) - l.queue = append(l.queue, wait) - } - - locks[ino] = l - - mu.Unlock() - - if wait != nil { - wait <- f - } - - // Spurious EDEADLK errors arise on platforms that compute deadlock graphs at - // the process, rather than thread, level. Consider processes P and Q, with - // threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be - // reported as a deadlock on systems that consider only process granularity: - // - // P.1 locks file A. - // Q.3 locks file B. - // Q.3 blocks on file A. - // P.2 blocks on file B. (This is erroneously reported as a deadlock.) - // P.1 unlocks file A. - // Q.3 unblocks and locks file A. - // Q.3 unlocks files A and B. - // P.2 unblocks and locks file B. - // P.2 unlocks file B. - // - // These spurious errors were observed in practice on AIX and Solaris in - // cmd/go: see https://golang.org/issue/32817. - // - // We work around this bug by treating EDEADLK as always spurious. If there - // really is a lock-ordering bug between the interacting processes, it will - // become a livelock instead, but that's not appreciably worse than if we had - // a proper flock implementation (which generally does not even attempt to - // diagnose deadlocks). - // - // In the above example, that changes the trace to: - // - // P.1 locks file A. - // Q.3 locks file B. - // Q.3 blocks on file A. - // P.2 spuriously fails to lock file B and goes to sleep. - // P.1 unlocks file A. - // Q.3 unblocks and locks file A. - // Q.3 unlocks files A and B. - // P.2 wakes up and locks file B. - // P.2 unlocks file B. - // - // We know that the retry loop will not introduce a *spurious* livelock - // because, according to the POSIX specification, EDEADLK is only to be - // returned when “the lock is blocked by a lock from another process”. - // If that process is blocked on some lock that we are holding, then the - // resulting livelock is due to a real deadlock (and would manifest as such - // when using, for example, the flock implementation of this package). - // If the other process is *not* blocked on some other lock that we are - // holding, then it will eventually release the requested lock. - - nextSleep := 1 * time.Millisecond - const maxSleep = 500 * time.Millisecond - for { - err = setlkw(f.fh.Fd(), cmd, lt) - if !errors.Is(err, unix.EDEADLK) { - break - } - - time.Sleep(nextSleep) - - nextSleep += nextSleep - if nextSleep > maxSleep { - nextSleep = maxSleep - } - // Apply 10% jitter to avoid synchronizing collisions when we finally unblock. - nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep)) - } - - if err != nil { - f.doUnlock() - - if cmd == tryLock && errors.Is(err, unix.EACCES) { - return false, nil - } - - return false, &fs.PathError{ - Op: lt.String(), - Path: f.Path(), - Err: err, - } - } - - return true, nil -} - -func (f *Flock) Unlock() error { - f.m.Lock() - defer f.m.Unlock() - - // If we aren't locked or if the lockfile instance is nil - // just return a nil error because we are unlocked. - if (!f.l && !f.r) || f.fh == nil { - return nil - } - - if err := f.doUnlock(); err != nil { - return err - } - - f.reset() - - return nil -} - -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L163 -func (f *Flock) doUnlock() (err error) { - var owner *Flock - - mu.Lock() - - ino, ok := inodes[f] - if ok { - owner = locks[ino].owner - } - - mu.Unlock() - - if owner == f { - err = setlkw(f.fh.Fd(), waitLock, unix.F_UNLCK) - } - - mu.Lock() - - l := locks[ino] - - if len(l.queue) == 0 { - // No waiters: remove the map entry. - delete(locks, ino) - } else { - // The first waiter is sending us their file now. - // Receive it and update the queue. - l.owner = <-l.queue[0] - l.queue = l.queue[1:] - locks[ino] = l - } - - delete(inodes, f) - - mu.Unlock() - - return err -} - -// TryLock is the preferred function for taking an exclusive file lock. -// This function takes an RW-mutex lock before it tries to lock the file, -// so there is the possibility that this function may block for a short time -// if another goroutine is trying to take any action. -// -// The actual file lock is non-blocking. -// If we are unable to get the exclusive file lock, -// the function will return false instead of waiting for the lock. -// If we get the lock, we also set the *Flock instance as being exclusive-locked. -func (f *Flock) TryLock() (bool, error) { - return f.try(&f.l, writeLock) -} - -// TryRLock is the preferred function for taking a shared file lock. -// This function takes an RW-mutex lock before it tries to lock the file, -// so there is the possibility that this function may block for a short time -// if another goroutine is trying to take any action. -// -// The actual file lock is non-blocking. -// If we are unable to get the shared file lock, -// the function will return false instead of waiting for the lock. -// If we get the lock, we also set the *Flock instance as being share-locked. -func (f *Flock) TryRLock() (bool, error) { - return f.try(&f.r, readLock) -} - -func (f *Flock) try(locked *bool, flag lockType) (bool, error) { - f.m.Lock() - defer f.m.Unlock() - - if *locked { - return true, nil - } - - if f.fh == nil { - if err := f.setFh(); err != nil { - return false, err - } - - defer f.ensureFhState() - } - - hasLock, err := f.doLock(tryLock, flag, false) - if err != nil { - return false, err - } - - *locked = hasLock - - return hasLock, nil -} - -// setlkw calls FcntlFlock with cmd for the entire file indicated by fd. -// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L198 -func setlkw(fd uintptr, cmd cmdType, lt lockType) error { - for { - err := unix.FcntlFlock(fd, int(cmd), &unix.Flock_t{ - Type: int16(lt), - Whence: io.SeekStart, - Start: 0, - Len: 0, // All bytes. - }) - if !errors.Is(err, unix.EINTR) { - return err - } - } -} diff --git a/vendor/github.com/gofrs/flock/flock_winapi.go b/vendor/github.com/gofrs/flock/flock_winapi.go new file mode 100644 index 00000000..fe405a25 --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock_winapi.go @@ -0,0 +1,76 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +// +build windows + +package flock + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32, _ = syscall.LoadLibrary("kernel32.dll") + procLockFileEx, _ = syscall.GetProcAddress(kernel32, "LockFileEx") + procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx") +) + +const ( + winLockfileFailImmediately = 0x00000001 + winLockfileExclusiveLock = 0x00000002 + winLockfileSharedLock = 0x00000000 +) + +// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows +// `LockFileEX` docs, which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as: +// +// > The function requests an exclusive lock. Otherwise, it requests a shared +// > lock. +// +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx + +func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) { + r1, _, errNo := syscall.Syscall6( + uintptr(procLockFileEx), + 6, + uintptr(handle), + uintptr(flags), + uintptr(reserved), + uintptr(numberOfBytesToLockLow), + uintptr(numberOfBytesToLockHigh), + uintptr(unsafe.Pointer(offset))) + + if r1 != 1 { + if errNo == 0 { + return false, syscall.EINVAL + } + + return false, errNo + } + + return true, 0 +} + +func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) { + r1, _, errNo := syscall.Syscall6( + uintptr(procUnlockFileEx), + 5, + uintptr(handle), + uintptr(reserved), + uintptr(numberOfBytesToLockLow), + uintptr(numberOfBytesToLockHigh), + uintptr(unsafe.Pointer(offset)), + 0) + + if r1 != 1 { + if errNo == 0 { + return false, syscall.EINVAL + } + + return false, errNo + } + + return true, 0 +} diff --git a/vendor/github.com/gofrs/flock/flock_windows.go b/vendor/github.com/gofrs/flock/flock_windows.go index 4df90e29..ddb534cc 100644 --- a/vendor/github.com/gofrs/flock/flock_windows.go +++ b/vendor/github.com/gofrs/flock/flock_windows.go @@ -1,48 +1,35 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. -//go:build windows - package flock import ( - "errors" - - "golang.org/x/sys/windows" + "syscall" ) -// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows `LockFileEX` docs, -// which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as: -// -// > The function requests an exclusive lock. Otherwise, it requests a shared lock. -// -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx -const winLockfileSharedLock = 0x00000000 - -// ErrorLockViolation is the error code returned from the Windows syscall when a lock would block, -// and you ask to fail immediately. -const ErrorLockViolation windows.Errno = 0x21 // 33 +// ErrorLockViolation is the error code returned from the Windows syscall when a +// lock would block and you ask to fail immediately. +const ErrorLockViolation syscall.Errno = 0x21 // 33 -// Lock is a blocking call to try and take an exclusive file lock. -// It will wait until it is able to obtain the exclusive file lock. -// It's recommended that TryLock() be used over this function. -// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// Lock is a blocking call to try and take an exclusive file lock. It will wait +// until it is able to obtain the exclusive file lock. It's recommended that +// TryLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. // -// If we are already locked, this function short-circuits and -// returns immediately assuming it can take the mutex lock. +// If we are already locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. func (f *Flock) Lock() error { - return f.lock(&f.l, windows.LOCKFILE_EXCLUSIVE_LOCK) + return f.lock(&f.l, winLockfileExclusiveLock) } -// RLock is a blocking call to try and take a shared file lock. -// It will wait until it is able to obtain the shared file lock. -// It's recommended that TryRLock() be used over this function. -// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// RLock is a blocking call to try and take a shared file lock. It will wait +// until it is able to obtain the shared file lock. It's recommended that +// TryRLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. // -// If we are already locked, this function short-circuits and -// returns immediately assuming it can take the mutex lock. +// If we are already locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. func (f *Flock) RLock() error { return f.lock(&f.r, winLockfileSharedLock) } @@ -59,28 +46,23 @@ func (f *Flock) lock(locked *bool, flag uint32) error { if err := f.setFh(); err != nil { return err } - defer f.ensureFhState() } - err := windows.LockFileEx(windows.Handle(f.fh.Fd()), flag, 0, 1, 0, &windows.Overlapped{}) - if err != nil && !errors.Is(err, windows.Errno(0)) { - return err + if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}); errNo > 0 { + return errNo } *locked = true - return nil } -// Unlock is a function to unlock the file. -// This file takes a RW-mutex lock, -// so while it is running the Locked() and RLocked() functions will be blocked. +// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so +// while it is running the Locked() and RLocked() functions will be blocked. // -// This function short-circuits if we are unlocked already. -// If not, it calls UnlockFileEx() on the file and closes the file descriptor. -// It does not remove the file from disk. -// It's up to your application to do. +// This function short-circuits if we are unlocked already. If not, it calls +// UnlockFileEx() on the file and closes the file descriptor. It does not remove +// the file from disk. It's up to your application to do. func (f *Flock) Unlock() error { f.m.Lock() defer f.m.Unlock() @@ -92,37 +74,39 @@ func (f *Flock) Unlock() error { } // mark the file as unlocked - err := windows.UnlockFileEx(windows.Handle(f.fh.Fd()), 0, 1, 0, &windows.Overlapped{}) - if err != nil && !errors.Is(err, windows.Errno(0)) { - return err + if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); errNo > 0 { + return errNo } - f.reset() + f.fh.Close() + + f.l = false + f.r = false + f.fh = nil return nil } -// TryLock is the preferred function for taking an exclusive file lock. -// This function does take a RW-mutex lock before it tries to lock the file, -// so there is the possibility that this function may block for a short time -// if another goroutine is trying to take any action. +// TryLock is the preferred function for taking an exclusive file lock. This +// function does take a RW-mutex lock before it tries to lock the file, so there +// is the possibility that this function may block for a short time if another +// goroutine is trying to take any action. // -// The actual file lock is non-blocking. -// If we are unable to get the exclusive file lock, -// the function will return false instead of waiting for the lock. -// If we get the lock, we also set the *Flock instance as being exclusive-locked. +// The actual file lock is non-blocking. If we are unable to get the exclusive +// file lock, the function will return false instead of waiting for the lock. If +// we get the lock, we also set the *Flock instance as being exclusive-locked. func (f *Flock) TryLock() (bool, error) { - return f.try(&f.l, windows.LOCKFILE_EXCLUSIVE_LOCK) + return f.try(&f.l, winLockfileExclusiveLock) } -// TryRLock is the preferred function for taking a shared file lock. -// This function does take a RW-mutex lock before it tries to lock the file, -// so there is the possibility that this function may block for a short time if another goroutine is trying to take any action. +// TryRLock is the preferred function for taking a shared file lock. This +// function does take a RW-mutex lock before it tries to lock the file, so there +// is the possibility that this function may block for a short time if another +// goroutine is trying to take any action. // -// The actual file lock is non-blocking. -// If we are unable to get the shared file lock, -// the function will return false instead of waiting for the lock. -// If we get the lock, we also set the *Flock instance as being shared-locked. +// The actual file lock is non-blocking. If we are unable to get the shared file +// lock, the function will return false instead of waiting for the lock. If we +// get the lock, we also set the *Flock instance as being shared-locked. func (f *Flock) TryRLock() (bool, error) { return f.try(&f.r, winLockfileSharedLock) } @@ -139,17 +123,17 @@ func (f *Flock) try(locked *bool, flag uint32) (bool, error) { if err := f.setFh(); err != nil { return false, err } - defer f.ensureFhState() } - err := windows.LockFileEx(windows.Handle(f.fh.Fd()), flag|windows.LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &windows.Overlapped{}) - if err != nil && !errors.Is(err, windows.Errno(0)) { - if errors.Is(err, ErrorLockViolation) || errors.Is(err, windows.ERROR_IO_PENDING) { + _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{}) + + if errNo > 0 { + if errNo == ErrorLockViolation || errNo == syscall.ERROR_IO_PENDING { return false, nil } - return false, err + return false, errNo } *locked = true diff --git a/vendor/github.com/hashicorp/go-bexpr/CODEOWNERS b/vendor/github.com/hashicorp/go-bexpr/CODEOWNERS deleted file mode 100644 index 1b35cec3..00000000 --- a/vendor/github.com/hashicorp/go-bexpr/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @hashicorp/release-engineering diff --git a/vendor/github.com/hashicorp/go-bexpr/LICENSE b/vendor/github.com/hashicorp/go-bexpr/LICENSE index 3b97eaf3..a612ad98 100644 --- a/vendor/github.com/hashicorp/go-bexpr/LICENSE +++ b/vendor/github.com/hashicorp/go-bexpr/LICENSE @@ -1,5 +1,3 @@ -Copyright (c) 2019 HashiCorp, Inc. - Mozilla Public License Version 2.0 ================================== diff --git a/vendor/github.com/hashicorp/go-bexpr/README.md b/vendor/github.com/hashicorp/go-bexpr/README.md index 72395de3..5e9d34f2 100644 --- a/vendor/github.com/hashicorp/go-bexpr/README.md +++ b/vendor/github.com/hashicorp/go-bexpr/README.md @@ -99,6 +99,6 @@ The [Makefile](Makefile) contains 3 main targets to aid with testing: `1s` seemed like too little to get results consistent enough for comparison between two runs. For the highest degree of confidence that performance has remained steady increase this value even further. The time it takes to run the bench testing suite grows linearly with this value. - * `BENCHTESTS=BenchmarkEvaluate` - This is used to run a particular benchmark including all of its + * `BENCHTESTS=BenchmarkEvalute` - This is used to run a particular benchmark including all of its sub-benchmarks. This is just an example and "BenchmarkEvaluate" can be replaced with any benchmark functions name. diff --git a/vendor/github.com/hashicorp/go-bexpr/bexpr.go b/vendor/github.com/hashicorp/go-bexpr/bexpr.go index 4b5a35c8..1dc36f56 100644 --- a/vendor/github.com/hashicorp/go-bexpr/bexpr.go +++ b/vendor/github.com/hashicorp/go-bexpr/bexpr.go @@ -1,10 +1,7 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// Package bexpr is an implementation of a generic boolean expression evaluator. +// bexpr is an implementation of a generic boolean expression evaluator. // The general goal is to be able to evaluate some expression against some -// arbitrary data and get back a boolean indicating if the data was matched by -// the expression +// arbitrary data and get back a boolean of whether or not the data +// was matched by the expression package bexpr //go:generate pigeon -o grammar/grammar.go -optimize-parser grammar/grammar.peg @@ -15,7 +12,7 @@ import ( "github.com/mitchellh/pointerstructure" ) -// ValueTransformationHookFn provides a way to translate one reflect.Value to another during +// HookFn provides a way to translate one reflect.Value to another during // evaluation by bexpr. This facilitates making Go structures appear in a way // that matches the expected JSON Pointers used for evaluation. This is // helpful, for example, when working with protocol buffers' well-known types. @@ -26,14 +23,8 @@ type Evaluator struct { ast grammar.Expression tagName string valueTransformationHook ValueTransformationHookFn - unknownVal *interface{} - expression string } -// CreateEvaluator is used to create and configure a new Evaluator, the expression -// will be used by the evaluator when evaluating against any supplied datum. -// The following Option types are supported: -// WithHookFn, WithMaxExpressions, WithTagName, WithUnknownValue. func CreateEvaluator(expression string, opts ...Option) (*Evaluator, error) { parsedOpts := getOpts(opts...) var parserOpts []grammar.Option @@ -50,29 +41,11 @@ func CreateEvaluator(expression string, opts ...Option) (*Evaluator, error) { ast: ast.(grammar.Expression), tagName: parsedOpts.withTagName, valueTransformationHook: parsedOpts.withHookFn, - unknownVal: parsedOpts.withUnknown, - expression: expression, } return eval, nil } -// Evaluate attempts to match the configured expression against the supplied datum. -// It returns a value indicating if a match was found and any error that occurred. -// If an error is returned, the value indicating a match will be false. func (eval *Evaluator) Evaluate(datum interface{}) (bool, error) { - opts := []Option{ - WithTagName(eval.tagName), - WithHookFn(eval.valueTransformationHook), - } - if eval.unknownVal != nil { - opts = append(opts, WithUnknownValue(*eval.unknownVal)) - } - - return evaluate(eval.ast, datum, opts...) -} - -// Expression can be used to return the initial expression used to create the Evaluator. -func (eval *Evaluator) Expression() string { - return eval.expression + return evaluate(eval.ast, datum, WithTagName(eval.tagName), WithHookFn(eval.valueTransformationHook)) } diff --git a/vendor/github.com/hashicorp/go-bexpr/coerce.go b/vendor/github.com/hashicorp/go-bexpr/coerce.go index ed24b6d1..1878e0cb 100644 --- a/vendor/github.com/hashicorp/go-bexpr/coerce.go +++ b/vendor/github.com/hashicorp/go-bexpr/coerce.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package bexpr import ( diff --git a/vendor/github.com/hashicorp/go-bexpr/evaluate.go b/vendor/github.com/hashicorp/go-bexpr/evaluate.go index 47165a63..6bf73be6 100644 --- a/vendor/github.com/hashicorp/go-bexpr/evaluate.go +++ b/vendor/github.com/hashicorp/go-bexpr/evaluate.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package bexpr import ( @@ -216,75 +213,10 @@ func getMatchExprValue(expression *grammar.MatchExpression, rvalue reflect.Kind) } } -// evaluateNotPresent is called after a pointerstructure.ErrNotFound is -// encountered during evaluation. -// -// Returns true if the Selector Path's parent is a map as the missing key may -// be handled by the MatchOperator's NotPresentDisposition method. -// -// Returns false if the Selector Path has a length of 1, or if the parent of -// the Selector's Path is not a map, a pointerstructure.ErrNotFound error is -// returned. -func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { - if len(ptr.Parts) < 2 { - return false - } - - // Pop the missing leaf part of the path - ptr.Parts = ptr.Parts[0 : len(ptr.Parts)-1] - - val, _ := ptr.Get(datum) - return reflect.ValueOf(val).Kind() == reflect.Map -} - -// getValue resolves path to the value it references by first looking into the -// the local variables, then into the global datum state if it does not. -// -// When the path points to a local variable we have multiple cases we have to -// take care of, in some constructions like -// -// all Slice as item { item != "forbidden" } -// -// `item` is actually an alias to "/Slice/0", "/Slice/1", etc. In that case we -// compute the full path because we tracked what each of them points to. -// -// In some other cases like -// -// all Map as key { key != "forbidden" } -// -// `key` has no equivalent JSON Pointer. In that case we kept track of the the -// concrete value instead of the path and we return it directly. -func getValue(datum interface{}, path []string, opt ...Option) (interface{}, bool, error) { +func evaluateMatchExpression(expression *grammar.MatchExpression, datum interface{}, opt ...Option) (bool, error) { opts := getOpts(opt...) - if len(path) != 0 && len(opts.withLocalVariables) > 0 { - for i := len(opts.withLocalVariables) - 1; i >= 0; i-- { - name := path[0] - lv := opts.withLocalVariables[i] - if name == lv.name { - if len(lv.path) == 0 { - // This local variable is a key or an index and we know its - // value without having to call pointerstructure, we stop - // here. - if len(path) > 1 { - first := pointerstructure.Pointer{Parts: []string{name}} - full := pointerstructure.Pointer{Parts: path} - return nil, false, fmt.Errorf("%s references a %T so %s is invalid", first.String(), lv.value, full.String()) - } - return lv.value, true, nil - } else { - // This local variable references another value, we prepend the - // path of the selector it replaces and continue searching - prefix := append([]string(nil), lv.path...) - path = append(prefix, path[1:]...) - } - } - } - } - - // This is not a local variable, we use pointerstructure to look for it - // in the global datum ptr := pointerstructure.Pointer{ - Parts: path, + Parts: expression.Selector.Path, Config: pointerstructure.Config{ TagName: opts.withTagName, ValueTransformationHook: opts.withHookFn, @@ -292,37 +224,7 @@ func getValue(datum interface{}, path []string, opt ...Option) (interface{}, boo } val, err := ptr.Get(datum) if err != nil { - if errors.Is(err, pointerstructure.ErrNotFound) { - // Prefer the withUnknown option if set, otherwise defer to NotPresent - // disposition - switch { - case opts.withUnknown != nil: - err = nil - val = *opts.withUnknown - case evaluateNotPresent(ptr, datum): - return nil, false, nil - } - } - - if err != nil { - return false, false, fmt.Errorf("error finding value in datum: %w", err) - } - } - - return val, true, nil -} - -func evaluateMatchExpression(expression *grammar.MatchExpression, datum interface{}, opt ...Option) (bool, error) { - val, present, err := getValue( - datum, - expression.Selector.Path, - opt..., - ) - if err != nil { - return false, err - } - if !present { - return expression.Operator.NotPresentDisposition(), nil + return false, fmt.Errorf("error finding value in datum: %w", err) } if jn, ok := val.(json.Number); ok { @@ -374,85 +276,6 @@ func evaluateMatchExpression(expression *grammar.MatchExpression, datum interfac } } -func evaluateCollectionExpression(expression *grammar.CollectionExpression, datum interface{}, opt ...Option) (bool, error) { - val, present, err := getValue( - datum, - expression.Selector.Path, - opt..., - ) - if err != nil { - return false, err - } - if !present { - return expression.Op == grammar.CollectionOpAll, nil - } - - v := reflect.ValueOf(val) - - var keys []reflect.Value - if v.Kind() == reflect.Map { - if v.Type().Key() != reflect.TypeOf("") { - return false, fmt.Errorf("%s can only iterate over maps indexed with strings", expression.Op) - } - keys = v.MapKeys() - } - - switch v.Kind() { - case reflect.Slice, reflect.Array, reflect.Map: - for i := 0; i < v.Len(); i++ { - innerOpt := append([]Option(nil), opt...) - - if expression.NameBinding.Mode == grammar.CollectionBindIndexAndValue && - expression.NameBinding.Index == expression.NameBinding.Value { - return false, fmt.Errorf("%q cannot be used as a placeholder for both the index and the value", expression.NameBinding.Index) - } - - if v.Kind() == reflect.Map { - key := keys[i] - if expression.NameBinding.Default != "" { - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Default, nil, key.Interface())) - } - if expression.NameBinding.Index != "" { - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Index, nil, key.Interface())) - } - if expression.NameBinding.Value != "" { - path := make([]string, 0, len(expression.Selector.Path)+1) - path = append(path, expression.Selector.Path...) - path = append(path, key.Interface().(string)) - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, path, nil)) - } - } else { - if expression.NameBinding.Index != "" { - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Index, nil, i)) - } - - pathValue := make([]string, 0, len(expression.Selector.Path)+1) - pathValue = append(pathValue, expression.Selector.Path...) - pathValue = append(pathValue, fmt.Sprintf("%d", i)) - if expression.NameBinding.Default != "" { - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Default, pathValue, nil)) - } - if expression.NameBinding.Value != "" { - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, pathValue, nil)) - } - } - - result, err := evaluate(expression.Inner, datum, innerOpt...) - if err != nil { - return false, err - } - if (result && expression.Op == grammar.CollectionOpAny) || (!result && expression.Op == grammar.CollectionOpAll) { - return result, nil - } - } - - return expression.Op == grammar.CollectionOpAll, nil - - default: - return false, fmt.Errorf(`%s is not a list or a map`, expression.Selector.String()) - } -} - func evaluate(ast grammar.Expression, datum interface{}, opt ...Option) (bool, error) { switch node := ast.(type) { case *grammar.UnaryExpression: @@ -481,8 +304,6 @@ func evaluate(ast grammar.Expression, datum interface{}, opt ...Option) (bool, e } case *grammar.MatchExpression: return evaluateMatchExpression(node, datum, opt...) - case *grammar.CollectionExpression: - return evaluateCollectionExpression(node, datum, opt...) } return false, fmt.Errorf("Invalid AST node") } diff --git a/vendor/github.com/hashicorp/go-bexpr/filter.go b/vendor/github.com/hashicorp/go-bexpr/filter.go index 2d1e6ab3..390d57c9 100644 --- a/vendor/github.com/hashicorp/go-bexpr/filter.go +++ b/vendor/github.com/hashicorp/go-bexpr/filter.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package bexpr import ( diff --git a/vendor/github.com/hashicorp/go-bexpr/grammar/ast.go b/vendor/github.com/hashicorp/go-bexpr/grammar/ast.go index d6faab0c..bf6e6c19 100644 --- a/vendor/github.com/hashicorp/go-bexpr/grammar/ast.go +++ b/vendor/github.com/hashicorp/go-bexpr/grammar/ast.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package grammar import ( @@ -84,42 +81,6 @@ func (op MatchOperator) String() string { } } -// NotPresentDisposition is called during evaluation when Selector fails to -// find a map key to determine the operator's behavior. -func (op MatchOperator) NotPresentDisposition() bool { - // For a selector M["x"] against a map M that lacks an "x" key... - switch op { - case MatchEqual: - // ...M["x"] == is false. Nothing is equal to a missing key - return false - case MatchNotEqual: - // ...M["x"] != is true. Nothing is equal to a missing key - return true - case MatchIn: - // "a" in M["x"] is false. Missing keys contain no values - return false - case MatchNotIn: - // "a" not in M["x"] is true. Missing keys contain no values - return true - case MatchIsEmpty: - // M["x"] is empty is true. Missing keys contain no values - return true - case MatchIsNotEmpty: - // M["x"] is not empty is false. Missing keys contain no values - return false - case MatchMatches: - // M["x"] matches is false. Nothing matches a missing key - return false - case MatchNotMatches: - // M["x"] not matches is true. Nothing matches a missing key - return true - default: - // Should never be reached as every operator should explicitly define its - // behavior. - return false - } -} - type MatchValue struct { Raw string Converted interface{} @@ -192,55 +153,3 @@ func (expr *MatchExpression) ExpressionDump(w io.Writer, indent string, level in fmt.Fprintf(w, "%[1]s%[3]s {\n%[2]sSelector: %[4]v\n%[1]s}\n", strings.Repeat(indent, level), strings.Repeat(indent, level+1), expr.Operator.String(), expr.Selector) } } - -type CollectionBindMode string - -const ( - CollectionBindDefault CollectionBindMode = "Default" - CollectionBindIndex CollectionBindMode = "Index" - CollectionBindValue CollectionBindMode = "Value" - CollectionBindIndexAndValue CollectionBindMode = "Index & Value" -) - -type CollectionNameBinding struct { - Mode CollectionBindMode - Default string - Index string - Value string -} - -func (b *CollectionNameBinding) String() string { - switch b.Mode { - case CollectionBindDefault: - return fmt.Sprintf("%v (%s)", b.Mode, b.Default) - case CollectionBindIndex: - return fmt.Sprintf("%v (%s)", b.Mode, b.Index) - case CollectionBindValue: - return fmt.Sprintf("%v (%s)", b.Mode, b.Value) - case CollectionBindIndexAndValue: - return fmt.Sprintf("%v (%s, %s)", b.Mode, b.Index, b.Value) - default: - return fmt.Sprintf("UNKNOWN (%s, %s, %s)", b.Default, b.Index, b.Value) - } -} - -type CollectionOperator string - -const ( - CollectionOpAll CollectionOperator = "ALL" - CollectionOpAny CollectionOperator = "ANY" -) - -type CollectionExpression struct { - Op CollectionOperator - Selector Selector - Inner Expression - NameBinding CollectionNameBinding -} - -func (expr *CollectionExpression) ExpressionDump(w io.Writer, indent string, level int) { - localIndent := strings.Repeat(indent, level) - fmt.Fprintf(w, "%s%s %s on %v {\n", localIndent, expr.Op, expr.NameBinding.String(), expr.Selector) - expr.Inner.ExpressionDump(w, indent, level+1) - fmt.Fprintf(w, "%s}\n", localIndent) -} diff --git a/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.go b/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.go index ad675ed1..7aee78a1 100644 --- a/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.go +++ b/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "math" "os" "sort" @@ -25,13 +26,13 @@ var g = &grammar{ pos: position{line: 12, col: 1, offset: 103}, expr: &choiceExpr{ pos: position{line: 12, col: 10, offset: 112}, - alternatives: []any{ + alternatives: []interface{}{ &actionExpr{ pos: position{line: 12, col: 10, offset: 112}, run: (*parser).callonInput2, expr: &seqExpr{ pos: position{line: 12, col: 10, offset: 112}, - exprs: []any{ + exprs: []interface{}{ &zeroOrOneExpr{ pos: position{line: 12, col: 10, offset: 112}, expr: &ruleRefExpr{ @@ -92,7 +93,7 @@ var g = &grammar{ run: (*parser).callonInput17, expr: &seqExpr{ pos: position{line: 14, col: 5, offset: 180}, - exprs: []any{ + exprs: []interface{}{ &zeroOrOneExpr{ pos: position{line: 14, col: 5, offset: 180}, expr: &ruleRefExpr{ @@ -130,13 +131,13 @@ var g = &grammar{ pos: position{line: 18, col: 1, offset: 233}, expr: &choiceExpr{ pos: position{line: 18, col: 17, offset: 249}, - alternatives: []any{ + alternatives: []interface{}{ &actionExpr{ pos: position{line: 18, col: 17, offset: 249}, run: (*parser).callonOrExpression2, expr: &seqExpr{ pos: position{line: 18, col: 17, offset: 249}, - exprs: []any{ + exprs: []interface{}{ &labeledExpr{ pos: position{line: 18, col: 17, offset: 249}, label: "left", @@ -182,60 +183,48 @@ var g = &grammar{ }, }, }, - &actionExpr{ - pos: position{line: 26, col: 5, offset: 478}, - run: (*parser).callonOrExpression14, - expr: &labeledExpr{ - pos: position{line: 26, col: 5, offset: 478}, - label: "expr", - expr: &ruleRefExpr{ - pos: position{line: 26, col: 10, offset: 483}, - name: "CollectionExpression", - }, - }, - }, }, }, }, { name: "AndExpression", - pos: position{line: 30, col: 1, offset: 529}, + pos: position{line: 28, col: 1, offset: 477}, expr: &choiceExpr{ - pos: position{line: 30, col: 18, offset: 546}, - alternatives: []any{ + pos: position{line: 28, col: 18, offset: 494}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 30, col: 18, offset: 546}, + pos: position{line: 28, col: 18, offset: 494}, run: (*parser).callonAndExpression2, expr: &seqExpr{ - pos: position{line: 30, col: 18, offset: 546}, - exprs: []any{ + pos: position{line: 28, col: 18, offset: 494}, + exprs: []interface{}{ &labeledExpr{ - pos: position{line: 30, col: 18, offset: 546}, + pos: position{line: 28, col: 18, offset: 494}, label: "left", expr: &ruleRefExpr{ - pos: position{line: 30, col: 23, offset: 551}, + pos: position{line: 28, col: 23, offset: 499}, name: "NotExpression", }, }, &ruleRefExpr{ - pos: position{line: 30, col: 37, offset: 565}, + pos: position{line: 28, col: 37, offset: 513}, name: "_", }, &litMatcher{ - pos: position{line: 30, col: 39, offset: 567}, + pos: position{line: 28, col: 39, offset: 515}, val: "and", ignoreCase: false, want: "\"and\"", }, &ruleRefExpr{ - pos: position{line: 30, col: 45, offset: 573}, + pos: position{line: 28, col: 45, offset: 521}, name: "_", }, &labeledExpr{ - pos: position{line: 30, col: 47, offset: 575}, + pos: position{line: 28, col: 47, offset: 523}, label: "right", expr: &ruleRefExpr{ - pos: position{line: 30, col: 53, offset: 581}, + pos: position{line: 28, col: 53, offset: 529}, name: "AndExpression", }, }, @@ -243,13 +232,13 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 36, col: 5, offset: 733}, + pos: position{line: 34, col: 5, offset: 681}, run: (*parser).callonAndExpression11, expr: &labeledExpr{ - pos: position{line: 36, col: 5, offset: 733}, + pos: position{line: 34, col: 5, offset: 681}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 36, col: 10, offset: 738}, + pos: position{line: 34, col: 10, offset: 686}, name: "NotExpression", }, }, @@ -259,31 +248,31 @@ var g = &grammar{ }, { name: "NotExpression", - pos: position{line: 40, col: 1, offset: 777}, + pos: position{line: 38, col: 1, offset: 725}, expr: &choiceExpr{ - pos: position{line: 40, col: 18, offset: 794}, - alternatives: []any{ + pos: position{line: 38, col: 18, offset: 742}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 40, col: 18, offset: 794}, + pos: position{line: 38, col: 18, offset: 742}, run: (*parser).callonNotExpression2, expr: &seqExpr{ - pos: position{line: 40, col: 18, offset: 794}, - exprs: []any{ + pos: position{line: 38, col: 18, offset: 742}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 40, col: 18, offset: 794}, + pos: position{line: 38, col: 18, offset: 742}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 40, col: 24, offset: 800}, + pos: position{line: 38, col: 24, offset: 748}, name: "_", }, &labeledExpr{ - pos: position{line: 40, col: 26, offset: 802}, + pos: position{line: 38, col: 26, offset: 750}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 40, col: 31, offset: 807}, + pos: position{line: 38, col: 31, offset: 755}, name: "NotExpression", }, }, @@ -291,13 +280,13 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 51, col: 5, offset: 1194}, + pos: position{line: 49, col: 5, offset: 1142}, run: (*parser).callonNotExpression8, expr: &labeledExpr{ - pos: position{line: 51, col: 5, offset: 1194}, + pos: position{line: 49, col: 5, offset: 1142}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 51, col: 10, offset: 1199}, + pos: position{line: 49, col: 10, offset: 1147}, name: "ParenthesizedExpression", }, }, @@ -305,349 +294,49 @@ var g = &grammar{ }, }, }, - { - name: "CollectionExpression", - pos: position{line: 55, col: 1, offset: 1248}, - expr: &actionExpr{ - pos: position{line: 55, col: 25, offset: 1272}, - run: (*parser).callonCollectionExpression1, - expr: &seqExpr{ - pos: position{line: 55, col: 25, offset: 1272}, - exprs: []any{ - &labeledExpr{ - pos: position{line: 55, col: 25, offset: 1272}, - label: "op", - expr: &choiceExpr{ - pos: position{line: 55, col: 29, offset: 1276}, - alternatives: []any{ - &ruleRefExpr{ - pos: position{line: 55, col: 29, offset: 1276}, - name: "CollectionOpAny", - }, - &ruleRefExpr{ - pos: position{line: 55, col: 47, offset: 1294}, - name: "CollectionOpAll", - }, - }, - }, - }, - &labeledExpr{ - pos: position{line: 55, col: 64, offset: 1311}, - label: "selector", - expr: &ruleRefExpr{ - pos: position{line: 55, col: 73, offset: 1320}, - name: "Selector", - }, - }, - &ruleRefExpr{ - pos: position{line: 55, col: 82, offset: 1329}, - name: "_", - }, - &litMatcher{ - pos: position{line: 55, col: 84, offset: 1331}, - val: "as", - ignoreCase: false, - want: "\"as\"", - }, - &ruleRefExpr{ - pos: position{line: 55, col: 89, offset: 1336}, - name: "_", - }, - &labeledExpr{ - pos: position{line: 55, col: 91, offset: 1338}, - label: "binding", - expr: &ruleRefExpr{ - pos: position{line: 55, col: 99, offset: 1346}, - name: "CollectionIdentifiers", - }, - }, - &zeroOrOneExpr{ - pos: position{line: 55, col: 121, offset: 1368}, - expr: &ruleRefExpr{ - pos: position{line: 55, col: 121, offset: 1368}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 55, col: 124, offset: 1371}, - val: "{", - ignoreCase: false, - want: "\"{\"", - }, - &zeroOrOneExpr{ - pos: position{line: 55, col: 128, offset: 1375}, - expr: &ruleRefExpr{ - pos: position{line: 55, col: 128, offset: 1375}, - name: "_", - }, - }, - &labeledExpr{ - pos: position{line: 55, col: 131, offset: 1378}, - label: "expr", - expr: &ruleRefExpr{ - pos: position{line: 55, col: 136, offset: 1383}, - name: "OrExpression", - }, - }, - &zeroOrOneExpr{ - pos: position{line: 55, col: 149, offset: 1396}, - expr: &ruleRefExpr{ - pos: position{line: 55, col: 149, offset: 1396}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 55, col: 152, offset: 1399}, - val: "}", - ignoreCase: false, - want: "\"}\"", - }, - }, - }, - }, - }, - { - name: "CollectionIdentifiers", - displayName: "\"collection-identifiers\"", - pos: position{line: 64, col: 1, offset: 1625}, - expr: &choiceExpr{ - pos: position{line: 64, col: 51, offset: 1675}, - alternatives: []any{ - &actionExpr{ - pos: position{line: 64, col: 51, offset: 1675}, - run: (*parser).callonCollectionIdentifiers2, - expr: &seqExpr{ - pos: position{line: 64, col: 51, offset: 1675}, - exprs: []any{ - &labeledExpr{ - pos: position{line: 64, col: 51, offset: 1675}, - label: "id1", - expr: &ruleRefExpr{ - pos: position{line: 64, col: 55, offset: 1679}, - name: "Identifier", - }, - }, - &zeroOrOneExpr{ - pos: position{line: 64, col: 66, offset: 1690}, - expr: &ruleRefExpr{ - pos: position{line: 64, col: 66, offset: 1690}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 64, col: 69, offset: 1693}, - val: ",", - ignoreCase: false, - want: "\",\"", - }, - &zeroOrOneExpr{ - pos: position{line: 64, col: 73, offset: 1697}, - expr: &ruleRefExpr{ - pos: position{line: 64, col: 73, offset: 1697}, - name: "_", - }, - }, - &labeledExpr{ - pos: position{line: 64, col: 76, offset: 1700}, - label: "id2", - expr: &ruleRefExpr{ - pos: position{line: 64, col: 80, offset: 1704}, - name: "Identifier", - }, - }, - }, - }, - }, - &actionExpr{ - pos: position{line: 70, col: 5, offset: 1859}, - run: (*parser).callonCollectionIdentifiers13, - expr: &seqExpr{ - pos: position{line: 70, col: 5, offset: 1859}, - exprs: []any{ - &labeledExpr{ - pos: position{line: 70, col: 5, offset: 1859}, - label: "id1", - expr: &ruleRefExpr{ - pos: position{line: 70, col: 9, offset: 1863}, - name: "Identifier", - }, - }, - &zeroOrOneExpr{ - pos: position{line: 70, col: 20, offset: 1874}, - expr: &ruleRefExpr{ - pos: position{line: 70, col: 20, offset: 1874}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 70, col: 23, offset: 1877}, - val: ",", - ignoreCase: false, - want: "\",\"", - }, - &zeroOrOneExpr{ - pos: position{line: 70, col: 27, offset: 1881}, - expr: &ruleRefExpr{ - pos: position{line: 70, col: 27, offset: 1881}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 70, col: 30, offset: 1884}, - val: "_", - ignoreCase: false, - want: "\"_\"", - }, - }, - }, - }, - &actionExpr{ - pos: position{line: 75, col: 5, offset: 1997}, - run: (*parser).callonCollectionIdentifiers23, - expr: &seqExpr{ - pos: position{line: 75, col: 5, offset: 1997}, - exprs: []any{ - &litMatcher{ - pos: position{line: 75, col: 5, offset: 1997}, - val: "_", - ignoreCase: false, - want: "\"_\"", - }, - &zeroOrOneExpr{ - pos: position{line: 75, col: 9, offset: 2001}, - expr: &ruleRefExpr{ - pos: position{line: 75, col: 9, offset: 2001}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 75, col: 12, offset: 2004}, - val: ",", - ignoreCase: false, - want: "\",\"", - }, - &zeroOrOneExpr{ - pos: position{line: 75, col: 16, offset: 2008}, - expr: &ruleRefExpr{ - pos: position{line: 75, col: 16, offset: 2008}, - name: "_", - }, - }, - &labeledExpr{ - pos: position{line: 75, col: 19, offset: 2011}, - label: "id2", - expr: &ruleRefExpr{ - pos: position{line: 75, col: 23, offset: 2015}, - name: "Identifier", - }, - }, - }, - }, - }, - &actionExpr{ - pos: position{line: 80, col: 5, offset: 2135}, - run: (*parser).callonCollectionIdentifiers33, - expr: &labeledExpr{ - pos: position{line: 80, col: 5, offset: 2135}, - label: "id", - expr: &ruleRefExpr{ - pos: position{line: 80, col: 8, offset: 2138}, - name: "Identifier", - }, - }, - }, - }, - }, - }, - { - name: "CollectionOpAny", - pos: position{line: 87, col: 1, offset: 2260}, - expr: &actionExpr{ - pos: position{line: 87, col: 20, offset: 2279}, - run: (*parser).callonCollectionOpAny1, - expr: &seqExpr{ - pos: position{line: 87, col: 20, offset: 2279}, - exprs: []any{ - &litMatcher{ - pos: position{line: 87, col: 20, offset: 2279}, - val: "any", - ignoreCase: false, - want: "\"any\"", - }, - &ruleRefExpr{ - pos: position{line: 87, col: 26, offset: 2285}, - name: "_", - }, - }, - }, - }, - }, - { - name: "CollectionOpAll", - pos: position{line: 91, col: 1, offset: 2323}, - expr: &actionExpr{ - pos: position{line: 91, col: 20, offset: 2342}, - run: (*parser).callonCollectionOpAll1, - expr: &seqExpr{ - pos: position{line: 91, col: 20, offset: 2342}, - exprs: []any{ - &litMatcher{ - pos: position{line: 91, col: 20, offset: 2342}, - val: "all", - ignoreCase: false, - want: "\"all\"", - }, - &ruleRefExpr{ - pos: position{line: 91, col: 26, offset: 2348}, - name: "_", - }, - }, - }, - }, - }, { name: "ParenthesizedExpression", displayName: "\"grouping\"", - pos: position{line: 95, col: 1, offset: 2386}, + pos: position{line: 53, col: 1, offset: 1196}, expr: &choiceExpr{ - pos: position{line: 95, col: 39, offset: 2424}, - alternatives: []any{ + pos: position{line: 53, col: 39, offset: 1234}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 95, col: 39, offset: 2424}, + pos: position{line: 53, col: 39, offset: 1234}, run: (*parser).callonParenthesizedExpression2, expr: &seqExpr{ - pos: position{line: 95, col: 39, offset: 2424}, - exprs: []any{ + pos: position{line: 53, col: 39, offset: 1234}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 95, col: 39, offset: 2424}, + pos: position{line: 53, col: 39, offset: 1234}, val: "(", ignoreCase: false, want: "\"(\"", }, &zeroOrOneExpr{ - pos: position{line: 95, col: 43, offset: 2428}, + pos: position{line: 53, col: 43, offset: 1238}, expr: &ruleRefExpr{ - pos: position{line: 95, col: 43, offset: 2428}, + pos: position{line: 53, col: 43, offset: 1238}, name: "_", }, }, &labeledExpr{ - pos: position{line: 95, col: 46, offset: 2431}, + pos: position{line: 53, col: 46, offset: 1241}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 95, col: 51, offset: 2436}, + pos: position{line: 53, col: 51, offset: 1246}, name: "OrExpression", }, }, &zeroOrOneExpr{ - pos: position{line: 95, col: 64, offset: 2449}, + pos: position{line: 53, col: 64, offset: 1259}, expr: &ruleRefExpr{ - pos: position{line: 95, col: 64, offset: 2449}, + pos: position{line: 53, col: 64, offset: 1259}, name: "_", }, }, &litMatcher{ - pos: position{line: 95, col: 67, offset: 2452}, + pos: position{line: 53, col: 67, offset: 1262}, val: ")", ignoreCase: false, want: "\")\"", @@ -656,55 +345,55 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 97, col: 5, offset: 2482}, + pos: position{line: 55, col: 5, offset: 1292}, run: (*parser).callonParenthesizedExpression12, expr: &labeledExpr{ - pos: position{line: 97, col: 5, offset: 2482}, + pos: position{line: 55, col: 5, offset: 1292}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 97, col: 10, offset: 2487}, + pos: position{line: 55, col: 10, offset: 1297}, name: "MatchExpression", }, }, }, &seqExpr{ - pos: position{line: 99, col: 5, offset: 2529}, - exprs: []any{ + pos: position{line: 57, col: 5, offset: 1339}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 99, col: 5, offset: 2529}, + pos: position{line: 57, col: 5, offset: 1339}, val: "(", ignoreCase: false, want: "\"(\"", }, &zeroOrOneExpr{ - pos: position{line: 99, col: 9, offset: 2533}, + pos: position{line: 57, col: 9, offset: 1343}, expr: &ruleRefExpr{ - pos: position{line: 99, col: 9, offset: 2533}, + pos: position{line: 57, col: 9, offset: 1343}, name: "_", }, }, &ruleRefExpr{ - pos: position{line: 99, col: 12, offset: 2536}, + pos: position{line: 57, col: 12, offset: 1346}, name: "OrExpression", }, &zeroOrOneExpr{ - pos: position{line: 99, col: 25, offset: 2549}, + pos: position{line: 57, col: 25, offset: 1359}, expr: &ruleRefExpr{ - pos: position{line: 99, col: 25, offset: 2549}, + pos: position{line: 57, col: 25, offset: 1359}, name: "_", }, }, ¬Expr{ - pos: position{line: 99, col: 28, offset: 2552}, + pos: position{line: 57, col: 28, offset: 1362}, expr: &litMatcher{ - pos: position{line: 99, col: 29, offset: 2553}, + pos: position{line: 57, col: 29, offset: 1363}, val: ")", ignoreCase: false, want: "\")\"", }, }, &andCodeExpr{ - pos: position{line: 99, col: 33, offset: 2557}, + pos: position{line: 57, col: 33, offset: 1367}, run: (*parser).callonParenthesizedExpression24, }, }, @@ -715,20 +404,20 @@ var g = &grammar{ { name: "MatchExpression", displayName: "\"match\"", - pos: position{line: 103, col: 1, offset: 2616}, + pos: position{line: 61, col: 1, offset: 1426}, expr: &choiceExpr{ - pos: position{line: 103, col: 28, offset: 2643}, - alternatives: []any{ + pos: position{line: 61, col: 28, offset: 1453}, + alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 103, col: 28, offset: 2643}, + pos: position{line: 61, col: 28, offset: 1453}, name: "MatchSelectorOpValue", }, &ruleRefExpr{ - pos: position{line: 103, col: 51, offset: 2666}, + pos: position{line: 61, col: 51, offset: 1476}, name: "MatchSelectorOp", }, &ruleRefExpr{ - pos: position{line: 103, col: 69, offset: 2684}, + pos: position{line: 61, col: 69, offset: 1494}, name: "MatchValueOpSelector", }, }, @@ -737,59 +426,59 @@ var g = &grammar{ { name: "MatchSelectorOpValue", displayName: "\"match\"", - pos: position{line: 105, col: 1, offset: 2706}, + pos: position{line: 63, col: 1, offset: 1516}, expr: &actionExpr{ - pos: position{line: 105, col: 33, offset: 2738}, + pos: position{line: 63, col: 33, offset: 1548}, run: (*parser).callonMatchSelectorOpValue1, expr: &seqExpr{ - pos: position{line: 105, col: 33, offset: 2738}, - exprs: []any{ + pos: position{line: 63, col: 33, offset: 1548}, + exprs: []interface{}{ &labeledExpr{ - pos: position{line: 105, col: 33, offset: 2738}, + pos: position{line: 63, col: 33, offset: 1548}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 105, col: 42, offset: 2747}, + pos: position{line: 63, col: 42, offset: 1557}, name: "Selector", }, }, &labeledExpr{ - pos: position{line: 105, col: 51, offset: 2756}, + pos: position{line: 63, col: 51, offset: 1566}, label: "operator", expr: &choiceExpr{ - pos: position{line: 105, col: 61, offset: 2766}, - alternatives: []any{ + pos: position{line: 63, col: 61, offset: 1576}, + alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 105, col: 61, offset: 2766}, + pos: position{line: 63, col: 61, offset: 1576}, name: "MatchEqual", }, &ruleRefExpr{ - pos: position{line: 105, col: 74, offset: 2779}, + pos: position{line: 63, col: 74, offset: 1589}, name: "MatchNotEqual", }, &ruleRefExpr{ - pos: position{line: 105, col: 90, offset: 2795}, + pos: position{line: 63, col: 90, offset: 1605}, name: "MatchContains", }, &ruleRefExpr{ - pos: position{line: 105, col: 106, offset: 2811}, + pos: position{line: 63, col: 106, offset: 1621}, name: "MatchNotContains", }, &ruleRefExpr{ - pos: position{line: 105, col: 125, offset: 2830}, + pos: position{line: 63, col: 125, offset: 1640}, name: "MatchMatches", }, &ruleRefExpr{ - pos: position{line: 105, col: 140, offset: 2845}, + pos: position{line: 63, col: 140, offset: 1655}, name: "MatchNotMatches", }, }, }, }, &labeledExpr{ - pos: position{line: 105, col: 157, offset: 2862}, + pos: position{line: 63, col: 157, offset: 1672}, label: "value", expr: &ruleRefExpr{ - pos: position{line: 105, col: 163, offset: 2868}, + pos: position{line: 63, col: 163, offset: 1678}, name: "Value", }, }, @@ -800,33 +489,33 @@ var g = &grammar{ { name: "MatchSelectorOp", displayName: "\"match\"", - pos: position{line: 109, col: 1, offset: 3006}, + pos: position{line: 67, col: 1, offset: 1816}, expr: &actionExpr{ - pos: position{line: 109, col: 28, offset: 3033}, + pos: position{line: 67, col: 28, offset: 1843}, run: (*parser).callonMatchSelectorOp1, expr: &seqExpr{ - pos: position{line: 109, col: 28, offset: 3033}, - exprs: []any{ + pos: position{line: 67, col: 28, offset: 1843}, + exprs: []interface{}{ &labeledExpr{ - pos: position{line: 109, col: 28, offset: 3033}, + pos: position{line: 67, col: 28, offset: 1843}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 109, col: 37, offset: 3042}, + pos: position{line: 67, col: 37, offset: 1852}, name: "Selector", }, }, &labeledExpr{ - pos: position{line: 109, col: 46, offset: 3051}, + pos: position{line: 67, col: 46, offset: 1861}, label: "operator", expr: &choiceExpr{ - pos: position{line: 109, col: 56, offset: 3061}, - alternatives: []any{ + pos: position{line: 67, col: 56, offset: 1871}, + alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 109, col: 56, offset: 3061}, + pos: position{line: 67, col: 56, offset: 1871}, name: "MatchIsEmpty", }, &ruleRefExpr{ - pos: position{line: 109, col: 71, offset: 3076}, + pos: position{line: 67, col: 71, offset: 1886}, name: "MatchIsNotEmpty", }, }, @@ -839,46 +528,46 @@ var g = &grammar{ { name: "MatchValueOpSelector", displayName: "\"match\"", - pos: position{line: 113, col: 1, offset: 3209}, + pos: position{line: 71, col: 1, offset: 2019}, expr: &choiceExpr{ - pos: position{line: 113, col: 33, offset: 3241}, - alternatives: []any{ + pos: position{line: 71, col: 33, offset: 2051}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 113, col: 33, offset: 3241}, + pos: position{line: 71, col: 33, offset: 2051}, run: (*parser).callonMatchValueOpSelector2, expr: &seqExpr{ - pos: position{line: 113, col: 33, offset: 3241}, - exprs: []any{ + pos: position{line: 71, col: 33, offset: 2051}, + exprs: []interface{}{ &labeledExpr{ - pos: position{line: 113, col: 33, offset: 3241}, + pos: position{line: 71, col: 33, offset: 2051}, label: "value", expr: &ruleRefExpr{ - pos: position{line: 113, col: 39, offset: 3247}, + pos: position{line: 71, col: 39, offset: 2057}, name: "Value", }, }, &labeledExpr{ - pos: position{line: 113, col: 45, offset: 3253}, + pos: position{line: 71, col: 45, offset: 2063}, label: "operator", expr: &choiceExpr{ - pos: position{line: 113, col: 55, offset: 3263}, - alternatives: []any{ + pos: position{line: 71, col: 55, offset: 2073}, + alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 113, col: 55, offset: 3263}, + pos: position{line: 71, col: 55, offset: 2073}, name: "MatchIn", }, &ruleRefExpr{ - pos: position{line: 113, col: 65, offset: 3273}, + pos: position{line: 71, col: 65, offset: 2083}, name: "MatchNotIn", }, }, }, }, &labeledExpr{ - pos: position{line: 113, col: 77, offset: 3285}, + pos: position{line: 71, col: 77, offset: 2095}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 113, col: 86, offset: 3294}, + pos: position{line: 71, col: 86, offset: 2104}, name: "Selector", }, }, @@ -886,38 +575,38 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 115, col: 5, offset: 3436}, - exprs: []any{ + pos: position{line: 73, col: 5, offset: 2246}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 115, col: 5, offset: 3436}, + pos: position{line: 73, col: 5, offset: 2246}, name: "Value", }, &labeledExpr{ - pos: position{line: 115, col: 11, offset: 3442}, + pos: position{line: 73, col: 11, offset: 2252}, label: "operator", expr: &choiceExpr{ - pos: position{line: 115, col: 21, offset: 3452}, - alternatives: []any{ + pos: position{line: 73, col: 21, offset: 2262}, + alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 115, col: 21, offset: 3452}, + pos: position{line: 73, col: 21, offset: 2262}, name: "MatchIn", }, &ruleRefExpr{ - pos: position{line: 115, col: 31, offset: 3462}, + pos: position{line: 73, col: 31, offset: 2272}, name: "MatchNotIn", }, }, }, }, ¬Expr{ - pos: position{line: 115, col: 43, offset: 3474}, + pos: position{line: 73, col: 43, offset: 2284}, expr: &ruleRefExpr{ - pos: position{line: 115, col: 44, offset: 3475}, + pos: position{line: 73, col: 44, offset: 2285}, name: "Selector", }, }, &andCodeExpr{ - pos: position{line: 115, col: 53, offset: 3484}, + pos: position{line: 73, col: 53, offset: 2294}, run: (*parser).callonMatchValueOpSelector20, }, }, @@ -927,30 +616,30 @@ var g = &grammar{ }, { name: "MatchEqual", - pos: position{line: 119, col: 1, offset: 3538}, + pos: position{line: 77, col: 1, offset: 2348}, expr: &actionExpr{ - pos: position{line: 119, col: 15, offset: 3552}, + pos: position{line: 77, col: 15, offset: 2362}, run: (*parser).callonMatchEqual1, expr: &seqExpr{ - pos: position{line: 119, col: 15, offset: 3552}, - exprs: []any{ + pos: position{line: 77, col: 15, offset: 2362}, + exprs: []interface{}{ &zeroOrOneExpr{ - pos: position{line: 119, col: 15, offset: 3552}, + pos: position{line: 77, col: 15, offset: 2362}, expr: &ruleRefExpr{ - pos: position{line: 119, col: 15, offset: 3552}, + pos: position{line: 77, col: 15, offset: 2362}, name: "_", }, }, &litMatcher{ - pos: position{line: 119, col: 18, offset: 3555}, + pos: position{line: 77, col: 18, offset: 2365}, val: "==", ignoreCase: false, want: "\"==\"", }, &zeroOrOneExpr{ - pos: position{line: 119, col: 23, offset: 3560}, + pos: position{line: 77, col: 23, offset: 2370}, expr: &ruleRefExpr{ - pos: position{line: 119, col: 23, offset: 3560}, + pos: position{line: 77, col: 23, offset: 2370}, name: "_", }, }, @@ -960,30 +649,30 @@ var g = &grammar{ }, { name: "MatchNotEqual", - pos: position{line: 122, col: 1, offset: 3593}, + pos: position{line: 80, col: 1, offset: 2403}, expr: &actionExpr{ - pos: position{line: 122, col: 18, offset: 3610}, + pos: position{line: 80, col: 18, offset: 2420}, run: (*parser).callonMatchNotEqual1, expr: &seqExpr{ - pos: position{line: 122, col: 18, offset: 3610}, - exprs: []any{ + pos: position{line: 80, col: 18, offset: 2420}, + exprs: []interface{}{ &zeroOrOneExpr{ - pos: position{line: 122, col: 18, offset: 3610}, + pos: position{line: 80, col: 18, offset: 2420}, expr: &ruleRefExpr{ - pos: position{line: 122, col: 18, offset: 3610}, + pos: position{line: 80, col: 18, offset: 2420}, name: "_", }, }, &litMatcher{ - pos: position{line: 122, col: 21, offset: 3613}, + pos: position{line: 80, col: 21, offset: 2423}, val: "!=", ignoreCase: false, want: "\"!=\"", }, &zeroOrOneExpr{ - pos: position{line: 122, col: 26, offset: 3618}, + pos: position{line: 80, col: 26, offset: 2428}, expr: &ruleRefExpr{ - pos: position{line: 122, col: 26, offset: 3618}, + pos: position{line: 80, col: 26, offset: 2428}, name: "_", }, }, @@ -993,29 +682,29 @@ var g = &grammar{ }, { name: "MatchIsEmpty", - pos: position{line: 125, col: 1, offset: 3654}, + pos: position{line: 83, col: 1, offset: 2464}, expr: &actionExpr{ - pos: position{line: 125, col: 17, offset: 3670}, + pos: position{line: 83, col: 17, offset: 2480}, run: (*parser).callonMatchIsEmpty1, expr: &seqExpr{ - pos: position{line: 125, col: 17, offset: 3670}, - exprs: []any{ + pos: position{line: 83, col: 17, offset: 2480}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 125, col: 17, offset: 3670}, + pos: position{line: 83, col: 17, offset: 2480}, name: "_", }, &litMatcher{ - pos: position{line: 125, col: 19, offset: 3672}, + pos: position{line: 83, col: 19, offset: 2482}, val: "is", ignoreCase: false, want: "\"is\"", }, &ruleRefExpr{ - pos: position{line: 125, col: 24, offset: 3677}, + pos: position{line: 83, col: 24, offset: 2487}, name: "_", }, &litMatcher{ - pos: position{line: 125, col: 26, offset: 3679}, + pos: position{line: 83, col: 26, offset: 2489}, val: "empty", ignoreCase: false, want: "\"empty\"", @@ -1026,39 +715,39 @@ var g = &grammar{ }, { name: "MatchIsNotEmpty", - pos: position{line: 128, col: 1, offset: 3719}, + pos: position{line: 86, col: 1, offset: 2529}, expr: &actionExpr{ - pos: position{line: 128, col: 20, offset: 3738}, + pos: position{line: 86, col: 20, offset: 2548}, run: (*parser).callonMatchIsNotEmpty1, expr: &seqExpr{ - pos: position{line: 128, col: 20, offset: 3738}, - exprs: []any{ + pos: position{line: 86, col: 20, offset: 2548}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 128, col: 20, offset: 3738}, + pos: position{line: 86, col: 20, offset: 2548}, name: "_", }, &litMatcher{ - pos: position{line: 128, col: 21, offset: 3739}, + pos: position{line: 86, col: 21, offset: 2549}, val: "is", ignoreCase: false, want: "\"is\"", }, &ruleRefExpr{ - pos: position{line: 128, col: 26, offset: 3744}, + pos: position{line: 86, col: 26, offset: 2554}, name: "_", }, &litMatcher{ - pos: position{line: 128, col: 28, offset: 3746}, + pos: position{line: 86, col: 28, offset: 2556}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 128, col: 34, offset: 3752}, + pos: position{line: 86, col: 34, offset: 2562}, name: "_", }, &litMatcher{ - pos: position{line: 128, col: 36, offset: 3754}, + pos: position{line: 86, col: 36, offset: 2564}, val: "empty", ignoreCase: false, want: "\"empty\"", @@ -1069,25 +758,25 @@ var g = &grammar{ }, { name: "MatchIn", - pos: position{line: 131, col: 1, offset: 3797}, + pos: position{line: 89, col: 1, offset: 2607}, expr: &actionExpr{ - pos: position{line: 131, col: 12, offset: 3808}, + pos: position{line: 89, col: 12, offset: 2618}, run: (*parser).callonMatchIn1, expr: &seqExpr{ - pos: position{line: 131, col: 12, offset: 3808}, - exprs: []any{ + pos: position{line: 89, col: 12, offset: 2618}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 131, col: 12, offset: 3808}, + pos: position{line: 89, col: 12, offset: 2618}, name: "_", }, &litMatcher{ - pos: position{line: 131, col: 14, offset: 3810}, + pos: position{line: 89, col: 14, offset: 2620}, val: "in", ignoreCase: false, want: "\"in\"", }, &ruleRefExpr{ - pos: position{line: 131, col: 19, offset: 3815}, + pos: position{line: 89, col: 19, offset: 2625}, name: "_", }, }, @@ -1096,35 +785,35 @@ var g = &grammar{ }, { name: "MatchNotIn", - pos: position{line: 134, col: 1, offset: 3844}, + pos: position{line: 92, col: 1, offset: 2654}, expr: &actionExpr{ - pos: position{line: 134, col: 15, offset: 3858}, + pos: position{line: 92, col: 15, offset: 2668}, run: (*parser).callonMatchNotIn1, expr: &seqExpr{ - pos: position{line: 134, col: 15, offset: 3858}, - exprs: []any{ + pos: position{line: 92, col: 15, offset: 2668}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 134, col: 15, offset: 3858}, + pos: position{line: 92, col: 15, offset: 2668}, name: "_", }, &litMatcher{ - pos: position{line: 134, col: 17, offset: 3860}, + pos: position{line: 92, col: 17, offset: 2670}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 134, col: 23, offset: 3866}, + pos: position{line: 92, col: 23, offset: 2676}, name: "_", }, &litMatcher{ - pos: position{line: 134, col: 25, offset: 3868}, + pos: position{line: 92, col: 25, offset: 2678}, val: "in", ignoreCase: false, want: "\"in\"", }, &ruleRefExpr{ - pos: position{line: 134, col: 30, offset: 3873}, + pos: position{line: 92, col: 30, offset: 2683}, name: "_", }, }, @@ -1133,25 +822,25 @@ var g = &grammar{ }, { name: "MatchContains", - pos: position{line: 137, col: 1, offset: 3905}, + pos: position{line: 95, col: 1, offset: 2715}, expr: &actionExpr{ - pos: position{line: 137, col: 18, offset: 3922}, + pos: position{line: 95, col: 18, offset: 2732}, run: (*parser).callonMatchContains1, expr: &seqExpr{ - pos: position{line: 137, col: 18, offset: 3922}, - exprs: []any{ + pos: position{line: 95, col: 18, offset: 2732}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 137, col: 18, offset: 3922}, + pos: position{line: 95, col: 18, offset: 2732}, name: "_", }, &litMatcher{ - pos: position{line: 137, col: 20, offset: 3924}, + pos: position{line: 95, col: 20, offset: 2734}, val: "contains", ignoreCase: false, want: "\"contains\"", }, &ruleRefExpr{ - pos: position{line: 137, col: 31, offset: 3935}, + pos: position{line: 95, col: 31, offset: 2745}, name: "_", }, }, @@ -1160,35 +849,35 @@ var g = &grammar{ }, { name: "MatchNotContains", - pos: position{line: 140, col: 1, offset: 3964}, + pos: position{line: 98, col: 1, offset: 2774}, expr: &actionExpr{ - pos: position{line: 140, col: 21, offset: 3984}, + pos: position{line: 98, col: 21, offset: 2794}, run: (*parser).callonMatchNotContains1, expr: &seqExpr{ - pos: position{line: 140, col: 21, offset: 3984}, - exprs: []any{ + pos: position{line: 98, col: 21, offset: 2794}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 140, col: 21, offset: 3984}, + pos: position{line: 98, col: 21, offset: 2794}, name: "_", }, &litMatcher{ - pos: position{line: 140, col: 23, offset: 3986}, + pos: position{line: 98, col: 23, offset: 2796}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 140, col: 29, offset: 3992}, + pos: position{line: 98, col: 29, offset: 2802}, name: "_", }, &litMatcher{ - pos: position{line: 140, col: 31, offset: 3994}, + pos: position{line: 98, col: 31, offset: 2804}, val: "contains", ignoreCase: false, want: "\"contains\"", }, &ruleRefExpr{ - pos: position{line: 140, col: 42, offset: 4005}, + pos: position{line: 98, col: 42, offset: 2815}, name: "_", }, }, @@ -1197,25 +886,25 @@ var g = &grammar{ }, { name: "MatchMatches", - pos: position{line: 143, col: 1, offset: 4037}, + pos: position{line: 101, col: 1, offset: 2847}, expr: &actionExpr{ - pos: position{line: 143, col: 17, offset: 4053}, + pos: position{line: 101, col: 17, offset: 2863}, run: (*parser).callonMatchMatches1, expr: &seqExpr{ - pos: position{line: 143, col: 17, offset: 4053}, - exprs: []any{ + pos: position{line: 101, col: 17, offset: 2863}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 143, col: 17, offset: 4053}, + pos: position{line: 101, col: 17, offset: 2863}, name: "_", }, &litMatcher{ - pos: position{line: 143, col: 19, offset: 4055}, + pos: position{line: 101, col: 19, offset: 2865}, val: "matches", ignoreCase: false, want: "\"matches\"", }, &ruleRefExpr{ - pos: position{line: 143, col: 29, offset: 4065}, + pos: position{line: 101, col: 29, offset: 2875}, name: "_", }, }, @@ -1224,35 +913,35 @@ var g = &grammar{ }, { name: "MatchNotMatches", - pos: position{line: 146, col: 1, offset: 4099}, + pos: position{line: 104, col: 1, offset: 2909}, expr: &actionExpr{ - pos: position{line: 146, col: 20, offset: 4118}, + pos: position{line: 104, col: 20, offset: 2928}, run: (*parser).callonMatchNotMatches1, expr: &seqExpr{ - pos: position{line: 146, col: 20, offset: 4118}, - exprs: []any{ + pos: position{line: 104, col: 20, offset: 2928}, + exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 146, col: 20, offset: 4118}, + pos: position{line: 104, col: 20, offset: 2928}, name: "_", }, &litMatcher{ - pos: position{line: 146, col: 22, offset: 4120}, + pos: position{line: 104, col: 22, offset: 2930}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 146, col: 28, offset: 4126}, + pos: position{line: 104, col: 28, offset: 2936}, name: "_", }, &litMatcher{ - pos: position{line: 146, col: 30, offset: 4128}, + pos: position{line: 104, col: 30, offset: 2938}, val: "matches", ignoreCase: false, want: "\"matches\"", }, &ruleRefExpr{ - pos: position{line: 146, col: 40, offset: 4138}, + pos: position{line: 104, col: 40, offset: 2948}, name: "_", }, }, @@ -1262,31 +951,31 @@ var g = &grammar{ { name: "Selector", displayName: "\"selector\"", - pos: position{line: 150, col: 1, offset: 4176}, + pos: position{line: 108, col: 1, offset: 2986}, expr: &choiceExpr{ - pos: position{line: 150, col: 24, offset: 4199}, - alternatives: []any{ + pos: position{line: 108, col: 24, offset: 3009}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 150, col: 24, offset: 4199}, + pos: position{line: 108, col: 24, offset: 3009}, run: (*parser).callonSelector2, expr: &seqExpr{ - pos: position{line: 150, col: 24, offset: 4199}, - exprs: []any{ + pos: position{line: 108, col: 24, offset: 3009}, + exprs: []interface{}{ &labeledExpr{ - pos: position{line: 150, col: 24, offset: 4199}, + pos: position{line: 108, col: 24, offset: 3009}, label: "first", expr: &ruleRefExpr{ - pos: position{line: 150, col: 30, offset: 4205}, + pos: position{line: 108, col: 30, offset: 3015}, name: "Identifier", }, }, &labeledExpr{ - pos: position{line: 150, col: 41, offset: 4216}, + pos: position{line: 108, col: 41, offset: 3026}, label: "rest", expr: &zeroOrMoreExpr{ - pos: position{line: 150, col: 46, offset: 4221}, + pos: position{line: 108, col: 46, offset: 3031}, expr: &ruleRefExpr{ - pos: position{line: 150, col: 46, offset: 4221}, + pos: position{line: 108, col: 46, offset: 3031}, name: "SelectorOrIndex", }, }, @@ -1295,30 +984,30 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 161, col: 5, offset: 4485}, + pos: position{line: 119, col: 5, offset: 3295}, run: (*parser).callonSelector9, expr: &seqExpr{ - pos: position{line: 161, col: 5, offset: 4485}, - exprs: []any{ + pos: position{line: 119, col: 5, offset: 3295}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 161, col: 5, offset: 4485}, + pos: position{line: 119, col: 5, offset: 3295}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &labeledExpr{ - pos: position{line: 161, col: 9, offset: 4489}, + pos: position{line: 119, col: 9, offset: 3299}, label: "ptrsegs", expr: &zeroOrMoreExpr{ - pos: position{line: 161, col: 17, offset: 4497}, + pos: position{line: 119, col: 17, offset: 3307}, expr: &ruleRefExpr{ - pos: position{line: 161, col: 17, offset: 4497}, + pos: position{line: 119, col: 17, offset: 3307}, name: "JsonPointerSegment", }, }, }, &litMatcher{ - pos: position{line: 161, col: 37, offset: 4517}, + pos: position{line: 119, col: 37, offset: 3327}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -1331,26 +1020,26 @@ var g = &grammar{ }, { name: "JsonPointerSegment", - pos: position{line: 182, col: 1, offset: 4995}, + pos: position{line: 140, col: 1, offset: 3805}, expr: &actionExpr{ - pos: position{line: 182, col: 23, offset: 5017}, + pos: position{line: 140, col: 23, offset: 3827}, run: (*parser).callonJsonPointerSegment1, expr: &seqExpr{ - pos: position{line: 182, col: 23, offset: 5017}, - exprs: []any{ + pos: position{line: 140, col: 23, offset: 3827}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 182, col: 23, offset: 5017}, + pos: position{line: 140, col: 23, offset: 3827}, val: "/", ignoreCase: false, want: "\"/\"", }, &labeledExpr{ - pos: position{line: 182, col: 27, offset: 5021}, + pos: position{line: 140, col: 27, offset: 3831}, label: "ident", expr: &oneOrMoreExpr{ - pos: position{line: 182, col: 33, offset: 5027}, + pos: position{line: 140, col: 33, offset: 3837}, expr: &charClassMatcher{ - pos: position{line: 182, col: 33, offset: 5027}, + pos: position{line: 140, col: 33, offset: 3837}, val: "[\\pL\\pN-_.~:|]", chars: []rune{'-', '_', '.', '~', ':', '|'}, classes: []*unicode.RangeTable{rangeTable("L"), rangeTable("N")}, @@ -1365,24 +1054,24 @@ var g = &grammar{ }, { name: "Identifier", - pos: position{line: 186, col: 1, offset: 5082}, + pos: position{line: 144, col: 1, offset: 3892}, expr: &actionExpr{ - pos: position{line: 186, col: 15, offset: 5096}, + pos: position{line: 144, col: 15, offset: 3906}, run: (*parser).callonIdentifier1, expr: &seqExpr{ - pos: position{line: 186, col: 15, offset: 5096}, - exprs: []any{ + pos: position{line: 144, col: 15, offset: 3906}, + exprs: []interface{}{ &charClassMatcher{ - pos: position{line: 186, col: 15, offset: 5096}, + pos: position{line: 144, col: 15, offset: 3906}, val: "[a-zA-Z]", ranges: []rune{'a', 'z', 'A', 'Z'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 186, col: 24, offset: 5105}, + pos: position{line: 144, col: 24, offset: 3915}, expr: &charClassMatcher{ - pos: position{line: 186, col: 24, offset: 5105}, + pos: position{line: 144, col: 24, offset: 3915}, val: "[a-zA-Z0-9_/]", chars: []rune{'_', '/'}, ranges: []rune{'a', 'z', 'A', 'Z', '0', '9'}, @@ -1396,27 +1085,27 @@ var g = &grammar{ }, { name: "SelectorOrIndex", - pos: position{line: 190, col: 1, offset: 5155}, + pos: position{line: 148, col: 1, offset: 3965}, expr: &choiceExpr{ - pos: position{line: 190, col: 20, offset: 5174}, - alternatives: []any{ + pos: position{line: 148, col: 20, offset: 3984}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 190, col: 20, offset: 5174}, + pos: position{line: 148, col: 20, offset: 3984}, run: (*parser).callonSelectorOrIndex2, expr: &seqExpr{ - pos: position{line: 190, col: 20, offset: 5174}, - exprs: []any{ + pos: position{line: 148, col: 20, offset: 3984}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 190, col: 20, offset: 5174}, + pos: position{line: 148, col: 20, offset: 3984}, val: ".", ignoreCase: false, want: "\".\"", }, &labeledExpr{ - pos: position{line: 190, col: 24, offset: 5178}, + pos: position{line: 148, col: 24, offset: 3988}, label: "ident", expr: &ruleRefExpr{ - pos: position{line: 190, col: 30, offset: 5184}, + pos: position{line: 148, col: 30, offset: 3994}, name: "Identifier", }, }, @@ -1424,36 +1113,36 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 192, col: 5, offset: 5222}, + pos: position{line: 150, col: 5, offset: 4032}, run: (*parser).callonSelectorOrIndex7, expr: &labeledExpr{ - pos: position{line: 192, col: 5, offset: 5222}, + pos: position{line: 150, col: 5, offset: 4032}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 192, col: 10, offset: 5227}, + pos: position{line: 150, col: 10, offset: 4037}, name: "IndexExpression", }, }, }, &actionExpr{ - pos: position{line: 194, col: 5, offset: 5269}, + pos: position{line: 152, col: 5, offset: 4079}, run: (*parser).callonSelectorOrIndex10, expr: &seqExpr{ - pos: position{line: 194, col: 5, offset: 5269}, - exprs: []any{ + pos: position{line: 152, col: 5, offset: 4079}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 194, col: 5, offset: 5269}, + pos: position{line: 152, col: 5, offset: 4079}, val: ".", ignoreCase: false, want: "\".\"", }, &labeledExpr{ - pos: position{line: 194, col: 9, offset: 5273}, + pos: position{line: 152, col: 9, offset: 4083}, label: "idx", expr: &oneOrMoreExpr{ - pos: position{line: 194, col: 13, offset: 5277}, + pos: position{line: 152, col: 13, offset: 4087}, expr: &charClassMatcher{ - pos: position{line: 194, col: 13, offset: 5277}, + pos: position{line: 152, col: 13, offset: 4087}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1470,46 +1159,46 @@ var g = &grammar{ { name: "IndexExpression", displayName: "\"index\"", - pos: position{line: 198, col: 1, offset: 5323}, + pos: position{line: 156, col: 1, offset: 4133}, expr: &choiceExpr{ - pos: position{line: 198, col: 28, offset: 5350}, - alternatives: []any{ + pos: position{line: 156, col: 28, offset: 4160}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 198, col: 28, offset: 5350}, + pos: position{line: 156, col: 28, offset: 4160}, run: (*parser).callonIndexExpression2, expr: &seqExpr{ - pos: position{line: 198, col: 28, offset: 5350}, - exprs: []any{ + pos: position{line: 156, col: 28, offset: 4160}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 198, col: 28, offset: 5350}, + pos: position{line: 156, col: 28, offset: 4160}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 198, col: 32, offset: 5354}, + pos: position{line: 156, col: 32, offset: 4164}, expr: &ruleRefExpr{ - pos: position{line: 198, col: 32, offset: 5354}, + pos: position{line: 156, col: 32, offset: 4164}, name: "_", }, }, &labeledExpr{ - pos: position{line: 198, col: 35, offset: 5357}, + pos: position{line: 156, col: 35, offset: 4167}, label: "lit", expr: &ruleRefExpr{ - pos: position{line: 198, col: 39, offset: 5361}, + pos: position{line: 156, col: 39, offset: 4171}, name: "StringLiteral", }, }, &zeroOrOneExpr{ - pos: position{line: 198, col: 53, offset: 5375}, + pos: position{line: 156, col: 53, offset: 4185}, expr: &ruleRefExpr{ - pos: position{line: 198, col: 53, offset: 5375}, + pos: position{line: 156, col: 53, offset: 4185}, name: "_", }, }, &litMatcher{ - pos: position{line: 198, col: 56, offset: 5378}, + pos: position{line: 156, col: 56, offset: 4188}, val: "]", ignoreCase: false, want: "\"]\"", @@ -1518,72 +1207,72 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 200, col: 5, offset: 5407}, - exprs: []any{ + pos: position{line: 158, col: 5, offset: 4217}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 200, col: 5, offset: 5407}, + pos: position{line: 158, col: 5, offset: 4217}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 200, col: 9, offset: 5411}, + pos: position{line: 158, col: 9, offset: 4221}, expr: &ruleRefExpr{ - pos: position{line: 200, col: 9, offset: 5411}, + pos: position{line: 158, col: 9, offset: 4221}, name: "_", }, }, ¬Expr{ - pos: position{line: 200, col: 12, offset: 5414}, + pos: position{line: 158, col: 12, offset: 4224}, expr: &ruleRefExpr{ - pos: position{line: 200, col: 13, offset: 5415}, + pos: position{line: 158, col: 13, offset: 4225}, name: "StringLiteral", }, }, &andCodeExpr{ - pos: position{line: 200, col: 27, offset: 5429}, + pos: position{line: 158, col: 27, offset: 4239}, run: (*parser).callonIndexExpression18, }, }, }, &seqExpr{ - pos: position{line: 202, col: 5, offset: 5481}, - exprs: []any{ + pos: position{line: 160, col: 5, offset: 4291}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 202, col: 5, offset: 5481}, + pos: position{line: 160, col: 5, offset: 4291}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 202, col: 9, offset: 5485}, + pos: position{line: 160, col: 9, offset: 4295}, expr: &ruleRefExpr{ - pos: position{line: 202, col: 9, offset: 5485}, + pos: position{line: 160, col: 9, offset: 4295}, name: "_", }, }, &ruleRefExpr{ - pos: position{line: 202, col: 12, offset: 5488}, + pos: position{line: 160, col: 12, offset: 4298}, name: "StringLiteral", }, &zeroOrOneExpr{ - pos: position{line: 202, col: 26, offset: 5502}, + pos: position{line: 160, col: 26, offset: 4312}, expr: &ruleRefExpr{ - pos: position{line: 202, col: 26, offset: 5502}, + pos: position{line: 160, col: 26, offset: 4312}, name: "_", }, }, ¬Expr{ - pos: position{line: 202, col: 29, offset: 5505}, + pos: position{line: 160, col: 29, offset: 4315}, expr: &litMatcher{ - pos: position{line: 202, col: 30, offset: 5506}, + pos: position{line: 160, col: 30, offset: 4316}, val: "]", ignoreCase: false, want: "\"]\"", }, }, &andCodeExpr{ - pos: position{line: 202, col: 34, offset: 5510}, + pos: position{line: 160, col: 34, offset: 4320}, run: (*parser).callonIndexExpression28, }, }, @@ -1594,42 +1283,42 @@ var g = &grammar{ { name: "Value", displayName: "\"value\"", - pos: position{line: 206, col: 1, offset: 5573}, + pos: position{line: 164, col: 1, offset: 4383}, expr: &choiceExpr{ - pos: position{line: 206, col: 18, offset: 5590}, - alternatives: []any{ + pos: position{line: 164, col: 18, offset: 4400}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 206, col: 18, offset: 5590}, + pos: position{line: 164, col: 18, offset: 4400}, run: (*parser).callonValue2, expr: &labeledExpr{ - pos: position{line: 206, col: 18, offset: 5590}, + pos: position{line: 164, col: 18, offset: 4400}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 206, col: 27, offset: 5599}, + pos: position{line: 164, col: 27, offset: 4409}, name: "Selector", }, }, }, &actionExpr{ - pos: position{line: 208, col: 5, offset: 5675}, + pos: position{line: 166, col: 5, offset: 4485}, run: (*parser).callonValue5, expr: &labeledExpr{ - pos: position{line: 208, col: 5, offset: 5675}, + pos: position{line: 166, col: 5, offset: 4485}, label: "n", expr: &ruleRefExpr{ - pos: position{line: 208, col: 7, offset: 5677}, + pos: position{line: 166, col: 7, offset: 4487}, name: "NumberLiteral", }, }, }, &actionExpr{ - pos: position{line: 210, col: 5, offset: 5741}, + pos: position{line: 168, col: 5, offset: 4551}, run: (*parser).callonValue8, expr: &labeledExpr{ - pos: position{line: 210, col: 5, offset: 5741}, + pos: position{line: 168, col: 5, offset: 4551}, label: "s", expr: &ruleRefExpr{ - pos: position{line: 210, col: 7, offset: 5743}, + pos: position{line: 168, col: 7, offset: 4553}, name: "StringLiteral", }, }, @@ -1640,33 +1329,33 @@ var g = &grammar{ { name: "NumberLiteral", displayName: "\"number\"", - pos: position{line: 214, col: 1, offset: 5806}, + pos: position{line: 172, col: 1, offset: 4616}, expr: &choiceExpr{ - pos: position{line: 214, col: 27, offset: 5832}, - alternatives: []any{ + pos: position{line: 172, col: 27, offset: 4642}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 214, col: 27, offset: 5832}, + pos: position{line: 172, col: 27, offset: 4642}, run: (*parser).callonNumberLiteral2, expr: &seqExpr{ - pos: position{line: 214, col: 27, offset: 5832}, - exprs: []any{ + pos: position{line: 172, col: 27, offset: 4642}, + exprs: []interface{}{ &zeroOrOneExpr{ - pos: position{line: 214, col: 27, offset: 5832}, + pos: position{line: 172, col: 27, offset: 4642}, expr: &litMatcher{ - pos: position{line: 214, col: 27, offset: 5832}, + pos: position{line: 172, col: 27, offset: 4642}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &ruleRefExpr{ - pos: position{line: 214, col: 32, offset: 5837}, + pos: position{line: 172, col: 32, offset: 4647}, name: "IntegerOrFloat", }, &andExpr{ - pos: position{line: 214, col: 47, offset: 5852}, + pos: position{line: 172, col: 47, offset: 4662}, expr: &ruleRefExpr{ - pos: position{line: 214, col: 48, offset: 5853}, + pos: position{line: 172, col: 48, offset: 4663}, name: "AfterNumbers", }, }, @@ -1674,30 +1363,30 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 216, col: 5, offset: 5902}, - exprs: []any{ + pos: position{line: 174, col: 5, offset: 4712}, + exprs: []interface{}{ &zeroOrOneExpr{ - pos: position{line: 216, col: 5, offset: 5902}, + pos: position{line: 174, col: 5, offset: 4712}, expr: &litMatcher{ - pos: position{line: 216, col: 5, offset: 5902}, + pos: position{line: 174, col: 5, offset: 4712}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &ruleRefExpr{ - pos: position{line: 216, col: 10, offset: 5907}, + pos: position{line: 174, col: 10, offset: 4717}, name: "IntegerOrFloat", }, ¬Expr{ - pos: position{line: 216, col: 25, offset: 5922}, + pos: position{line: 174, col: 25, offset: 4732}, expr: &ruleRefExpr{ - pos: position{line: 216, col: 26, offset: 5923}, + pos: position{line: 174, col: 26, offset: 4733}, name: "AfterNumbers", }, }, &andCodeExpr{ - pos: position{line: 216, col: 39, offset: 5936}, + pos: position{line: 174, col: 39, offset: 4746}, run: (*parser).callonNumberLiteral15, }, }, @@ -1707,22 +1396,22 @@ var g = &grammar{ }, { name: "AfterNumbers", - pos: position{line: 220, col: 1, offset: 5996}, + pos: position{line: 178, col: 1, offset: 4806}, expr: &andExpr{ - pos: position{line: 220, col: 17, offset: 6012}, + pos: position{line: 178, col: 17, offset: 4822}, expr: &choiceExpr{ - pos: position{line: 220, col: 19, offset: 6014}, - alternatives: []any{ + pos: position{line: 178, col: 19, offset: 4824}, + alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 220, col: 19, offset: 6014}, + pos: position{line: 178, col: 19, offset: 4824}, name: "_", }, &ruleRefExpr{ - pos: position{line: 220, col: 23, offset: 6018}, + pos: position{line: 178, col: 23, offset: 4828}, name: "EOF", }, &litMatcher{ - pos: position{line: 220, col: 29, offset: 6024}, + pos: position{line: 178, col: 29, offset: 4834}, val: ")", ignoreCase: false, want: "\")\"", @@ -1733,33 +1422,33 @@ var g = &grammar{ }, { name: "IntegerOrFloat", - pos: position{line: 222, col: 1, offset: 6030}, + pos: position{line: 180, col: 1, offset: 4840}, expr: &seqExpr{ - pos: position{line: 222, col: 19, offset: 6048}, - exprs: []any{ + pos: position{line: 180, col: 19, offset: 4858}, + exprs: []interface{}{ &choiceExpr{ - pos: position{line: 222, col: 20, offset: 6049}, - alternatives: []any{ + pos: position{line: 180, col: 20, offset: 4859}, + alternatives: []interface{}{ &litMatcher{ - pos: position{line: 222, col: 20, offset: 6049}, + pos: position{line: 180, col: 20, offset: 4859}, val: "0", ignoreCase: false, want: "\"0\"", }, &seqExpr{ - pos: position{line: 222, col: 26, offset: 6055}, - exprs: []any{ + pos: position{line: 180, col: 26, offset: 4865}, + exprs: []interface{}{ &charClassMatcher{ - pos: position{line: 222, col: 26, offset: 6055}, + pos: position{line: 180, col: 26, offset: 4865}, val: "[1-9]", ranges: []rune{'1', '9'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 222, col: 31, offset: 6060}, + pos: position{line: 180, col: 31, offset: 4870}, expr: &charClassMatcher{ - pos: position{line: 222, col: 31, offset: 6060}, + pos: position{line: 180, col: 31, offset: 4870}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1771,20 +1460,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 222, col: 39, offset: 6068}, + pos: position{line: 180, col: 39, offset: 4878}, expr: &seqExpr{ - pos: position{line: 222, col: 40, offset: 6069}, - exprs: []any{ + pos: position{line: 180, col: 40, offset: 4879}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 222, col: 40, offset: 6069}, + pos: position{line: 180, col: 40, offset: 4879}, val: ".", ignoreCase: false, want: "\".\"", }, &oneOrMoreExpr{ - pos: position{line: 222, col: 44, offset: 6073}, + pos: position{line: 180, col: 44, offset: 4883}, expr: &charClassMatcher{ - pos: position{line: 222, col: 44, offset: 6073}, + pos: position{line: 180, col: 44, offset: 4883}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1800,34 +1489,34 @@ var g = &grammar{ { name: "StringLiteral", displayName: "\"string\"", - pos: position{line: 224, col: 1, offset: 6083}, + pos: position{line: 182, col: 1, offset: 4893}, expr: &choiceExpr{ - pos: position{line: 224, col: 27, offset: 6109}, - alternatives: []any{ + pos: position{line: 182, col: 27, offset: 4919}, + alternatives: []interface{}{ &actionExpr{ - pos: position{line: 224, col: 27, offset: 6109}, + pos: position{line: 182, col: 27, offset: 4919}, run: (*parser).callonStringLiteral2, expr: &choiceExpr{ - pos: position{line: 224, col: 28, offset: 6110}, - alternatives: []any{ + pos: position{line: 182, col: 28, offset: 4920}, + alternatives: []interface{}{ &seqExpr{ - pos: position{line: 224, col: 28, offset: 6110}, - exprs: []any{ + pos: position{line: 182, col: 28, offset: 4920}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 224, col: 28, offset: 6110}, + pos: position{line: 182, col: 28, offset: 4920}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 224, col: 32, offset: 6114}, + pos: position{line: 182, col: 32, offset: 4924}, expr: &ruleRefExpr{ - pos: position{line: 224, col: 32, offset: 6114}, + pos: position{line: 182, col: 32, offset: 4924}, name: "RawStringChar", }, }, &litMatcher{ - pos: position{line: 224, col: 47, offset: 6129}, + pos: position{line: 182, col: 47, offset: 4939}, val: "`", ignoreCase: false, want: "\"`\"", @@ -1835,23 +1524,23 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 224, col: 53, offset: 6135}, - exprs: []any{ + pos: position{line: 182, col: 53, offset: 4945}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 224, col: 53, offset: 6135}, + pos: position{line: 182, col: 53, offset: 4945}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 224, col: 57, offset: 6139}, + pos: position{line: 182, col: 57, offset: 4949}, expr: &ruleRefExpr{ - pos: position{line: 224, col: 57, offset: 6139}, + pos: position{line: 182, col: 57, offset: 4949}, name: "DoubleStringChar", }, }, &litMatcher{ - pos: position{line: 224, col: 75, offset: 6157}, + pos: position{line: 182, col: 75, offset: 4967}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -1862,42 +1551,42 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 226, col: 5, offset: 6209}, - exprs: []any{ + pos: position{line: 184, col: 5, offset: 5019}, + exprs: []interface{}{ &choiceExpr{ - pos: position{line: 226, col: 6, offset: 6210}, - alternatives: []any{ + pos: position{line: 184, col: 6, offset: 5020}, + alternatives: []interface{}{ &seqExpr{ - pos: position{line: 226, col: 6, offset: 6210}, - exprs: []any{ + pos: position{line: 184, col: 6, offset: 5020}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 226, col: 6, offset: 6210}, + pos: position{line: 184, col: 6, offset: 5020}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 226, col: 10, offset: 6214}, + pos: position{line: 184, col: 10, offset: 5024}, expr: &ruleRefExpr{ - pos: position{line: 226, col: 10, offset: 6214}, + pos: position{line: 184, col: 10, offset: 5024}, name: "RawStringChar", }, }, }, }, &seqExpr{ - pos: position{line: 226, col: 27, offset: 6231}, - exprs: []any{ + pos: position{line: 184, col: 27, offset: 5041}, + exprs: []interface{}{ &litMatcher{ - pos: position{line: 226, col: 27, offset: 6231}, + pos: position{line: 184, col: 27, offset: 5041}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 226, col: 31, offset: 6235}, + pos: position{line: 184, col: 31, offset: 5045}, expr: &ruleRefExpr{ - pos: position{line: 226, col: 31, offset: 6235}, + pos: position{line: 184, col: 31, offset: 5045}, name: "DoubleStringChar", }, }, @@ -1906,11 +1595,11 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 226, col: 50, offset: 6254}, + pos: position{line: 184, col: 50, offset: 5064}, name: "EOF", }, &andCodeExpr{ - pos: position{line: 226, col: 54, offset: 6258}, + pos: position{line: 184, col: 54, offset: 5068}, run: (*parser).callonStringLiteral25, }, }, @@ -1920,42 +1609,42 @@ var g = &grammar{ }, { name: "RawStringChar", - pos: position{line: 230, col: 1, offset: 6322}, + pos: position{line: 188, col: 1, offset: 5132}, expr: &seqExpr{ - pos: position{line: 230, col: 18, offset: 6339}, - exprs: []any{ + pos: position{line: 188, col: 18, offset: 5149}, + exprs: []interface{}{ ¬Expr{ - pos: position{line: 230, col: 18, offset: 6339}, + pos: position{line: 188, col: 18, offset: 5149}, expr: &litMatcher{ - pos: position{line: 230, col: 19, offset: 6340}, + pos: position{line: 188, col: 19, offset: 5150}, val: "`", ignoreCase: false, want: "\"`\"", }, }, &anyMatcher{ - line: 230, col: 23, offset: 6344, + line: 188, col: 23, offset: 5154, }, }, }, }, { name: "DoubleStringChar", - pos: position{line: 231, col: 1, offset: 6346}, + pos: position{line: 189, col: 1, offset: 5156}, expr: &seqExpr{ - pos: position{line: 231, col: 21, offset: 6366}, - exprs: []any{ + pos: position{line: 189, col: 21, offset: 5176}, + exprs: []interface{}{ ¬Expr{ - pos: position{line: 231, col: 21, offset: 6366}, + pos: position{line: 189, col: 21, offset: 5176}, expr: &litMatcher{ - pos: position{line: 231, col: 22, offset: 6367}, + pos: position{line: 189, col: 22, offset: 5177}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, }, &anyMatcher{ - line: 231, col: 26, offset: 6371, + line: 189, col: 26, offset: 5181, }, }, }, @@ -1963,11 +1652,11 @@ var g = &grammar{ { name: "_", displayName: "\"whitespace\"", - pos: position{line: 233, col: 1, offset: 6374}, + pos: position{line: 191, col: 1, offset: 5184}, expr: &oneOrMoreExpr{ - pos: position{line: 233, col: 19, offset: 6392}, + pos: position{line: 191, col: 19, offset: 5202}, expr: &charClassMatcher{ - pos: position{line: 233, col: 19, offset: 6392}, + pos: position{line: 191, col: 19, offset: 5202}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, @@ -1977,38 +1666,38 @@ var g = &grammar{ }, { name: "EOF", - pos: position{line: 235, col: 1, offset: 6404}, + pos: position{line: 193, col: 1, offset: 5214}, expr: ¬Expr{ - pos: position{line: 235, col: 8, offset: 6411}, + pos: position{line: 193, col: 8, offset: 5221}, expr: &anyMatcher{ - line: 235, col: 9, offset: 6412, + line: 193, col: 9, offset: 5222, }, }, }, }, } -func (c *current) onInput2(expr any) (any, error) { +func (c *current) onInput2(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonInput2() (any, error) { +func (p *parser) callonInput2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onInput2(stack["expr"]) } -func (c *current) onInput17(expr any) (any, error) { +func (c *current) onInput17(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonInput17() (any, error) { +func (p *parser) callonInput17() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onInput17(stack["expr"]) } -func (c *current) onOrExpression2(left, right any) (any, error) { +func (c *current) onOrExpression2(left, right interface{}) (interface{}, error) { return &BinaryExpression{ Operator: BinaryOpOr, Left: left.(Expression), @@ -2016,33 +1705,23 @@ func (c *current) onOrExpression2(left, right any) (any, error) { }, nil } -func (p *parser) callonOrExpression2() (any, error) { +func (p *parser) callonOrExpression2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onOrExpression2(stack["left"], stack["right"]) } -func (c *current) onOrExpression11(expr any) (any, error) { +func (c *current) onOrExpression11(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonOrExpression11() (any, error) { +func (p *parser) callonOrExpression11() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onOrExpression11(stack["expr"]) } -func (c *current) onOrExpression14(expr any) (any, error) { - return expr, nil -} - -func (p *parser) callonOrExpression14() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onOrExpression14(stack["expr"]) -} - -func (c *current) onAndExpression2(left, right any) (any, error) { +func (c *current) onAndExpression2(left, right interface{}) (interface{}, error) { return &BinaryExpression{ Operator: BinaryOpAnd, Left: left.(Expression), @@ -2050,23 +1729,23 @@ func (c *current) onAndExpression2(left, right any) (any, error) { }, nil } -func (p *parser) callonAndExpression2() (any, error) { +func (p *parser) callonAndExpression2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onAndExpression2(stack["left"], stack["right"]) } -func (c *current) onAndExpression11(expr any) (any, error) { +func (c *current) onAndExpression11(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonAndExpression11() (any, error) { +func (p *parser) callonAndExpression11() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onAndExpression11(stack["expr"]) } -func (c *current) onNotExpression2(expr any) (any, error) { +func (c *current) onNotExpression2(expr interface{}) (interface{}, error) { if unary, ok := expr.(*UnaryExpression); ok && unary.Operator == UnaryOpNot { // small optimization to get rid unnecessary levels of AST nodes // for things like: not not foo == 3 which is equivalent to foo == 3 @@ -2079,125 +1758,37 @@ func (c *current) onNotExpression2(expr any) (any, error) { }, nil } -func (p *parser) callonNotExpression2() (any, error) { +func (p *parser) callonNotExpression2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onNotExpression2(stack["expr"]) } -func (c *current) onNotExpression8(expr any) (any, error) { +func (c *current) onNotExpression8(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonNotExpression8() (any, error) { +func (p *parser) callonNotExpression8() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onNotExpression8(stack["expr"]) } -func (c *current) onCollectionExpression1(op, selector, binding, expr any) (any, error) { - return &CollectionExpression{ - Op: op.(CollectionOperator), - Selector: selector.(Selector), - NameBinding: binding.(CollectionNameBinding), - Inner: expr.(Expression), - }, nil -} - -func (p *parser) callonCollectionExpression1() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionExpression1(stack["op"], stack["selector"], stack["binding"], stack["expr"]) -} - -func (c *current) onCollectionIdentifiers2(id1, id2 any) (any, error) { - return CollectionNameBinding{ - Mode: CollectionBindIndexAndValue, - Index: id1.(string), - Value: id2.(string), - }, nil -} - -func (p *parser) callonCollectionIdentifiers2() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionIdentifiers2(stack["id1"], stack["id2"]) -} - -func (c *current) onCollectionIdentifiers13(id1 any) (any, error) { - return CollectionNameBinding{ - Mode: CollectionBindIndex, - Index: id1.(string), - }, nil -} - -func (p *parser) callonCollectionIdentifiers13() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionIdentifiers13(stack["id1"]) -} - -func (c *current) onCollectionIdentifiers23(id2 any) (any, error) { - return CollectionNameBinding{ - Mode: CollectionBindValue, - Value: id2.(string), - }, nil -} - -func (p *parser) callonCollectionIdentifiers23() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionIdentifiers23(stack["id2"]) -} - -func (c *current) onCollectionIdentifiers33(id any) (any, error) { - return CollectionNameBinding{ - Mode: CollectionBindDefault, - Default: id.(string), - }, nil -} - -func (p *parser) callonCollectionIdentifiers33() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionIdentifiers33(stack["id"]) -} - -func (c *current) onCollectionOpAny1() (any, error) { - return CollectionOpAny, nil -} - -func (p *parser) callonCollectionOpAny1() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionOpAny1() -} - -func (c *current) onCollectionOpAll1() (any, error) { - return CollectionOpAll, nil -} - -func (p *parser) callonCollectionOpAll1() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onCollectionOpAll1() -} - -func (c *current) onParenthesizedExpression2(expr any) (any, error) { +func (c *current) onParenthesizedExpression2(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonParenthesizedExpression2() (any, error) { +func (p *parser) callonParenthesizedExpression2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onParenthesizedExpression2(stack["expr"]) } -func (c *current) onParenthesizedExpression12(expr any) (any, error) { +func (c *current) onParenthesizedExpression12(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonParenthesizedExpression12() (any, error) { +func (p *parser) callonParenthesizedExpression12() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onParenthesizedExpression12(stack["expr"]) @@ -2213,37 +1804,37 @@ func (p *parser) callonParenthesizedExpression24() (bool, error) { return p.cur.onParenthesizedExpression24() } -func (c *current) onMatchSelectorOpValue1(selector, operator, value any) (any, error) { +func (c *current) onMatchSelectorOpValue1(selector, operator, value interface{}) (interface{}, error) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: value.(*MatchValue)}, nil } -func (p *parser) callonMatchSelectorOpValue1() (any, error) { +func (p *parser) callonMatchSelectorOpValue1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchSelectorOpValue1(stack["selector"], stack["operator"], stack["value"]) } -func (c *current) onMatchSelectorOp1(selector, operator any) (any, error) { +func (c *current) onMatchSelectorOp1(selector, operator interface{}) (interface{}, error) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: nil}, nil } -func (p *parser) callonMatchSelectorOp1() (any, error) { +func (p *parser) callonMatchSelectorOp1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchSelectorOp1(stack["selector"], stack["operator"]) } -func (c *current) onMatchValueOpSelector2(value, operator, selector any) (any, error) { +func (c *current) onMatchValueOpSelector2(value, operator, selector interface{}) (interface{}, error) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: value.(*MatchValue)}, nil } -func (p *parser) callonMatchValueOpSelector2() (any, error) { +func (p *parser) callonMatchValueOpSelector2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchValueOpSelector2(stack["value"], stack["operator"], stack["selector"]) } -func (c *current) onMatchValueOpSelector20(operator any) (bool, error) { +func (c *current) onMatchValueOpSelector20(operator interface{}) (bool, error) { return false, errors.New("Invalid selector") } @@ -2253,107 +1844,107 @@ func (p *parser) callonMatchValueOpSelector20() (bool, error) { return p.cur.onMatchValueOpSelector20(stack["operator"]) } -func (c *current) onMatchEqual1() (any, error) { +func (c *current) onMatchEqual1() (interface{}, error) { return MatchEqual, nil } -func (p *parser) callonMatchEqual1() (any, error) { +func (p *parser) callonMatchEqual1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchEqual1() } -func (c *current) onMatchNotEqual1() (any, error) { +func (c *current) onMatchNotEqual1() (interface{}, error) { return MatchNotEqual, nil } -func (p *parser) callonMatchNotEqual1() (any, error) { +func (p *parser) callonMatchNotEqual1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotEqual1() } -func (c *current) onMatchIsEmpty1() (any, error) { +func (c *current) onMatchIsEmpty1() (interface{}, error) { return MatchIsEmpty, nil } -func (p *parser) callonMatchIsEmpty1() (any, error) { +func (p *parser) callonMatchIsEmpty1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchIsEmpty1() } -func (c *current) onMatchIsNotEmpty1() (any, error) { +func (c *current) onMatchIsNotEmpty1() (interface{}, error) { return MatchIsNotEmpty, nil } -func (p *parser) callonMatchIsNotEmpty1() (any, error) { +func (p *parser) callonMatchIsNotEmpty1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchIsNotEmpty1() } -func (c *current) onMatchIn1() (any, error) { +func (c *current) onMatchIn1() (interface{}, error) { return MatchIn, nil } -func (p *parser) callonMatchIn1() (any, error) { +func (p *parser) callonMatchIn1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchIn1() } -func (c *current) onMatchNotIn1() (any, error) { +func (c *current) onMatchNotIn1() (interface{}, error) { return MatchNotIn, nil } -func (p *parser) callonMatchNotIn1() (any, error) { +func (p *parser) callonMatchNotIn1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotIn1() } -func (c *current) onMatchContains1() (any, error) { +func (c *current) onMatchContains1() (interface{}, error) { return MatchIn, nil } -func (p *parser) callonMatchContains1() (any, error) { +func (p *parser) callonMatchContains1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchContains1() } -func (c *current) onMatchNotContains1() (any, error) { +func (c *current) onMatchNotContains1() (interface{}, error) { return MatchNotIn, nil } -func (p *parser) callonMatchNotContains1() (any, error) { +func (p *parser) callonMatchNotContains1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotContains1() } -func (c *current) onMatchMatches1() (any, error) { +func (c *current) onMatchMatches1() (interface{}, error) { return MatchMatches, nil } -func (p *parser) callonMatchMatches1() (any, error) { +func (p *parser) callonMatchMatches1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchMatches1() } -func (c *current) onMatchNotMatches1() (any, error) { +func (c *current) onMatchNotMatches1() (interface{}, error) { return MatchNotMatches, nil } -func (p *parser) callonMatchNotMatches1() (any, error) { +func (p *parser) callonMatchNotMatches1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotMatches1() } -func (c *current) onSelector2(first, rest any) (any, error) { +func (c *current) onSelector2(first, rest interface{}) (interface{}, error) { sel := Selector{ Type: SelectorTypeBexpr, Path: []string{first.(string)}, @@ -2366,13 +1957,13 @@ func (c *current) onSelector2(first, rest any) (any, error) { return sel, nil } -func (p *parser) callonSelector2() (any, error) { +func (p *parser) callonSelector2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelector2(stack["first"], stack["rest"]) } -func (c *current) onSelector9(ptrsegs any) (any, error) { +func (c *current) onSelector9(ptrsegs interface{}) (interface{}, error) { sel := Selector{ Type: SelectorTypeJsonPointer, } @@ -2393,67 +1984,67 @@ func (c *current) onSelector9(ptrsegs any) (any, error) { return sel, nil } -func (p *parser) callonSelector9() (any, error) { +func (p *parser) callonSelector9() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelector9(stack["ptrsegs"]) } -func (c *current) onJsonPointerSegment1(ident any) (any, error) { +func (c *current) onJsonPointerSegment1(ident interface{}) (interface{}, error) { return string(c.text)[1:], nil } -func (p *parser) callonJsonPointerSegment1() (any, error) { +func (p *parser) callonJsonPointerSegment1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onJsonPointerSegment1(stack["ident"]) } -func (c *current) onIdentifier1() (any, error) { +func (c *current) onIdentifier1() (interface{}, error) { return string(c.text), nil } -func (p *parser) callonIdentifier1() (any, error) { +func (p *parser) callonIdentifier1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onIdentifier1() } -func (c *current) onSelectorOrIndex2(ident any) (any, error) { +func (c *current) onSelectorOrIndex2(ident interface{}) (interface{}, error) { return ident, nil } -func (p *parser) callonSelectorOrIndex2() (any, error) { +func (p *parser) callonSelectorOrIndex2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelectorOrIndex2(stack["ident"]) } -func (c *current) onSelectorOrIndex7(expr any) (any, error) { +func (c *current) onSelectorOrIndex7(expr interface{}) (interface{}, error) { return expr, nil } -func (p *parser) callonSelectorOrIndex7() (any, error) { +func (p *parser) callonSelectorOrIndex7() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelectorOrIndex7(stack["expr"]) } -func (c *current) onSelectorOrIndex10(idx any) (any, error) { +func (c *current) onSelectorOrIndex10(idx interface{}) (interface{}, error) { return string(c.text)[1:], nil } -func (p *parser) callonSelectorOrIndex10() (any, error) { +func (p *parser) callonSelectorOrIndex10() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelectorOrIndex10(stack["idx"]) } -func (c *current) onIndexExpression2(lit any) (any, error) { +func (c *current) onIndexExpression2(lit interface{}) (interface{}, error) { return lit, nil } -func (p *parser) callonIndexExpression2() (any, error) { +func (p *parser) callonIndexExpression2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onIndexExpression2(stack["lit"]) @@ -2479,41 +2070,41 @@ func (p *parser) callonIndexExpression28() (bool, error) { return p.cur.onIndexExpression28() } -func (c *current) onValue2(selector any) (any, error) { +func (c *current) onValue2(selector interface{}) (interface{}, error) { return &MatchValue{Raw: selector.(Selector).String()}, nil } -func (p *parser) callonValue2() (any, error) { +func (p *parser) callonValue2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onValue2(stack["selector"]) } -func (c *current) onValue5(n any) (any, error) { +func (c *current) onValue5(n interface{}) (interface{}, error) { return &MatchValue{Raw: n.(string)}, nil } -func (p *parser) callonValue5() (any, error) { +func (p *parser) callonValue5() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onValue5(stack["n"]) } -func (c *current) onValue8(s any) (any, error) { +func (c *current) onValue8(s interface{}) (interface{}, error) { return &MatchValue{Raw: s.(string)}, nil } -func (p *parser) callonValue8() (any, error) { +func (p *parser) callonValue8() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onValue8(stack["s"]) } -func (c *current) onNumberLiteral2() (any, error) { +func (c *current) onNumberLiteral2() (interface{}, error) { return string(c.text), nil } -func (p *parser) callonNumberLiteral2() (any, error) { +func (p *parser) callonNumberLiteral2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onNumberLiteral2() @@ -2529,11 +2120,11 @@ func (p *parser) callonNumberLiteral15() (bool, error) { return p.cur.onNumberLiteral15() } -func (c *current) onStringLiteral2() (any, error) { +func (c *current) onStringLiteral2() (interface{}, error) { return strconv.Unquote(string(c.text)) } -func (p *parser) callonStringLiteral2() (any, error) { +func (p *parser) callonStringLiteral2() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onStringLiteral2() @@ -2631,7 +2222,7 @@ func Recover(b bool) Option { // GlobalStore creates an Option to set a key to a certain value in // the globalStore. -func GlobalStore(key string, value any) Option { +func GlobalStore(key string, value interface{}) Option { return func(p *parser) Option { old := p.cur.globalStore[key] p.cur.globalStore[key] = value @@ -2640,7 +2231,7 @@ func GlobalStore(key string, value any) Option { } // ParseFile parses the file identified by filename. -func ParseFile(filename string, opts ...Option) (i any, err error) { +func ParseFile(filename string, opts ...Option) (i interface{}, err error) { f, err := os.Open(filename) if err != nil { return nil, err @@ -2655,8 +2246,8 @@ func ParseFile(filename string, opts ...Option) (i any, err error) { // ParseReader parses the data from r using filename as information in the // error messages. -func ParseReader(filename string, r io.Reader, opts ...Option) (any, error) { - b, err := io.ReadAll(r) +func ParseReader(filename string, r io.Reader, opts ...Option) (interface{}, error) { + b, err := ioutil.ReadAll(r) if err != nil { return nil, err } @@ -2666,7 +2257,7 @@ func ParseReader(filename string, r io.Reader, opts ...Option) (any, error) { // Parse parses the data from b using filename as information in the // error messages. -func Parse(filename string, b []byte, opts ...Option) (any, error) { +func Parse(filename string, b []byte, opts ...Option) (interface{}, error) { return newParser(filename, b, opts...).parse(g) } @@ -2699,7 +2290,7 @@ type current struct { globalStore storeDict } -type storeDict map[string]any +type storeDict map[string]interface{} // the AST types... @@ -2712,30 +2303,30 @@ type rule struct { pos position name string displayName string - expr any + expr interface{} } type choiceExpr struct { pos position - alternatives []any + alternatives []interface{} } type actionExpr struct { pos position - expr any - run func(*parser) (any, error) + expr interface{} + run func(*parser) (interface{}, error) } type recoveryExpr struct { pos position - expr any - recoverExpr any + expr interface{} + recoverExpr interface{} failureLabel []string } type seqExpr struct { pos position - exprs []any + exprs []interface{} } type throwExpr struct { @@ -2746,21 +2337,19 @@ type throwExpr struct { type labeledExpr struct { pos position label string - expr any + expr interface{} } type expr struct { pos position - expr any + expr interface{} } -type ( - andExpr expr - notExpr expr - zeroOrOneExpr expr - zeroOrMoreExpr expr - oneOrMoreExpr expr -) +type andExpr expr +type notExpr expr +type zeroOrOneExpr expr +type zeroOrMoreExpr expr +type oneOrMoreExpr expr type ruleRefExpr struct { pos position @@ -2895,7 +2484,7 @@ func (p *parser) setOptions(opts []Option) { } type resultTuple struct { - v any + v interface{} b bool end savepoint } @@ -2938,7 +2527,7 @@ type parser struct { // rules table, maps the rule identifier to the rule node rules map[string]*rule // variables stack, map of label to value - vstack []map[string]any + vstack []map[string]interface{} // rule stack, allows identification of the current rule in errors rstack []*rule @@ -2958,7 +2547,7 @@ type parser struct { choiceNoMatch string // recovery expression stack, keeps track of the currently available recovery expression, these are traversed in reverse - recoveryStack []map[string]any + recoveryStack []map[string]interface{} } // push a variable set on the vstack. @@ -2978,7 +2567,7 @@ func (p *parser) pushV() { return } - m = make(map[string]any) + m = make(map[string]interface{}) p.vstack[len(p.vstack)-1] = m } @@ -2994,7 +2583,7 @@ func (p *parser) popV() { } // push a recovery expression with its labels to the recoveryStack -func (p *parser) pushRecovery(labels []string, expr any) { +func (p *parser) pushRecovery(labels []string, expr interface{}) { if cap(p.recoveryStack) == len(p.recoveryStack) { // create new empty slot in the stack p.recoveryStack = append(p.recoveryStack, nil) @@ -3003,7 +2592,7 @@ func (p *parser) pushRecovery(labels []string, expr any) { p.recoveryStack = p.recoveryStack[:len(p.recoveryStack)+1] } - m := make(map[string]any, len(labels)) + m := make(map[string]interface{}, len(labels)) for _, fl := range labels { m[fl] = expr } @@ -3104,7 +2693,7 @@ func (p *parser) buildRulesTable(g *grammar) { } } -func (p *parser) parse(g *grammar) (val any, err error) { +func (p *parser) parse(g *grammar) (val interface{}, err error) { if len(g.rules) == 0 { p.addErr(errNoRule) return nil, p.errs.err() @@ -3178,7 +2767,7 @@ func listJoin(list []string, sep string, lastSep string) string { } } -func (p *parser) parseRule(rule *rule) (any, bool) { +func (p *parser) parseRule(rule *rule) (interface{}, bool) { p.rstack = append(p.rstack, rule) p.pushV() val, ok := p.parseExpr(rule.expr) @@ -3187,14 +2776,14 @@ func (p *parser) parseRule(rule *rule) (any, bool) { return val, ok } -func (p *parser) parseExpr(expr any) (any, bool) { +func (p *parser) parseExpr(expr interface{}) (interface{}, bool) { p.ExprCnt++ if p.ExprCnt > p.maxExprCnt { panic(errMaxExprCnt) } - var val any + var val interface{} var ok bool switch expr := expr.(type) { case *actionExpr: @@ -3237,7 +2826,7 @@ func (p *parser) parseExpr(expr any) (any, bool) { return val, ok } -func (p *parser) parseActionExpr(act *actionExpr) (any, bool) { +func (p *parser) parseActionExpr(act *actionExpr) (interface{}, bool) { start := p.pt val, ok := p.parseExpr(act.expr) if ok { @@ -3253,7 +2842,7 @@ func (p *parser) parseActionExpr(act *actionExpr) (any, bool) { return val, ok } -func (p *parser) parseAndCodeExpr(and *andCodeExpr) (any, bool) { +func (p *parser) parseAndCodeExpr(and *andCodeExpr) (interface{}, bool) { ok, err := and.run(p) if err != nil { @@ -3263,7 +2852,7 @@ func (p *parser) parseAndCodeExpr(and *andCodeExpr) (any, bool) { return nil, ok } -func (p *parser) parseAndExpr(and *andExpr) (any, bool) { +func (p *parser) parseAndExpr(and *andExpr) (interface{}, bool) { pt := p.pt p.pushV() _, ok := p.parseExpr(and.expr) @@ -3273,7 +2862,7 @@ func (p *parser) parseAndExpr(and *andExpr) (any, bool) { return nil, ok } -func (p *parser) parseAnyMatcher(any *anyMatcher) (any, bool) { +func (p *parser) parseAnyMatcher(any *anyMatcher) (interface{}, bool) { if p.pt.rn == utf8.RuneError && p.pt.w == 0 { // EOF - see utf8.DecodeRune p.failAt(false, p.pt.position, ".") @@ -3285,7 +2874,7 @@ func (p *parser) parseAnyMatcher(any *anyMatcher) (any, bool) { return p.sliceFrom(start), true } -func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (any, bool) { +func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (interface{}, bool) { cur := p.pt.rn start := p.pt @@ -3347,7 +2936,7 @@ func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (any, bool) { return nil, false } -func (p *parser) parseChoiceExpr(ch *choiceExpr) (any, bool) { +func (p *parser) parseChoiceExpr(ch *choiceExpr) (interface{}, bool) { for altI, alt := range ch.alternatives { // dummy assignment to prevent compile error if optimized _ = altI @@ -3362,7 +2951,7 @@ func (p *parser) parseChoiceExpr(ch *choiceExpr) (any, bool) { return nil, false } -func (p *parser) parseLabeledExpr(lab *labeledExpr) (any, bool) { +func (p *parser) parseLabeledExpr(lab *labeledExpr) (interface{}, bool) { p.pushV() val, ok := p.parseExpr(lab.expr) p.popV() @@ -3373,7 +2962,7 @@ func (p *parser) parseLabeledExpr(lab *labeledExpr) (any, bool) { return val, ok } -func (p *parser) parseLitMatcher(lit *litMatcher) (any, bool) { +func (p *parser) parseLitMatcher(lit *litMatcher) (interface{}, bool) { start := p.pt for _, want := range lit.val { cur := p.pt.rn @@ -3391,7 +2980,7 @@ func (p *parser) parseLitMatcher(lit *litMatcher) (any, bool) { return p.sliceFrom(start), true } -func (p *parser) parseNotCodeExpr(not *notCodeExpr) (any, bool) { +func (p *parser) parseNotCodeExpr(not *notCodeExpr) (interface{}, bool) { ok, err := not.run(p) if err != nil { p.addErr(err) @@ -3400,7 +2989,7 @@ func (p *parser) parseNotCodeExpr(not *notCodeExpr) (any, bool) { return nil, !ok } -func (p *parser) parseNotExpr(not *notExpr) (any, bool) { +func (p *parser) parseNotExpr(not *notExpr) (interface{}, bool) { pt := p.pt p.pushV() p.maxFailInvertExpected = !p.maxFailInvertExpected @@ -3412,8 +3001,8 @@ func (p *parser) parseNotExpr(not *notExpr) (any, bool) { return nil, !ok } -func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (any, bool) { - var vals []any +func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (interface{}, bool) { + var vals []interface{} for { p.pushV() @@ -3430,7 +3019,7 @@ func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (any, bool) { } } -func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (any, bool) { +func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (interface{}, bool) { p.pushRecovery(recover.failureLabel, recover.recoverExpr) val, ok := p.parseExpr(recover.expr) @@ -3439,7 +3028,7 @@ func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (any, bool) { return val, ok } -func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (any, bool) { +func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (interface{}, bool) { if ref.name == "" { panic(fmt.Sprintf("%s: invalid rule: missing name", ref.pos)) } @@ -3452,8 +3041,8 @@ func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (any, bool) { return p.parseRule(rule) } -func (p *parser) parseSeqExpr(seq *seqExpr) (any, bool) { - vals := make([]any, 0, len(seq.exprs)) +func (p *parser) parseSeqExpr(seq *seqExpr) (interface{}, bool) { + vals := make([]interface{}, 0, len(seq.exprs)) pt := p.pt for _, expr := range seq.exprs { @@ -3467,7 +3056,7 @@ func (p *parser) parseSeqExpr(seq *seqExpr) (any, bool) { return vals, true } -func (p *parser) parseThrowExpr(expr *throwExpr) (any, bool) { +func (p *parser) parseThrowExpr(expr *throwExpr) (interface{}, bool) { for i := len(p.recoveryStack) - 1; i >= 0; i-- { if recoverExpr, ok := p.recoveryStack[i][expr.label]; ok { @@ -3480,8 +3069,8 @@ func (p *parser) parseThrowExpr(expr *throwExpr) (any, bool) { return nil, false } -func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (any, bool) { - var vals []any +func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (interface{}, bool) { + var vals []interface{} for { p.pushV() @@ -3494,7 +3083,7 @@ func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (any, bool) { } } -func (p *parser) parseZeroOrOneExpr(expr *zeroOrOneExpr) (any, bool) { +func (p *parser) parseZeroOrOneExpr(expr *zeroOrOneExpr) (interface{}, bool) { p.pushV() val, _ := p.parseExpr(expr.expr) p.popV() diff --git a/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.peg b/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.peg index d2ff1e26..728fc7e8 100644 --- a/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.peg +++ b/vendor/github.com/hashicorp/go-bexpr/grammar/grammar.peg @@ -23,8 +23,6 @@ OrExpression <- left:AndExpression _ "or" _ right:OrExpression { }, nil } / expr:AndExpression { return expr, nil -} / expr:CollectionExpression { - return expr, nil } AndExpression <- left:NotExpression _ "and" _ right:AndExpression { @@ -52,46 +50,6 @@ NotExpression <- "not" _ expr:NotExpression { return expr, nil } -CollectionExpression <- op:(CollectionOpAny / CollectionOpAll) selector:Selector _ "as" _ binding:CollectionIdentifiers _? "{" _? expr:OrExpression _? "}" { - return &CollectionExpression{ - Op: op.(CollectionOperator), - Selector: selector.(Selector), - NameBinding: binding.(CollectionNameBinding), - Inner: expr.(Expression), - }, nil -} - -CollectionIdentifiers "collection-identifiers" <- id1:Identifier _? "," _? id2:Identifier { - return CollectionNameBinding{ - Mode: CollectionBindIndexAndValue, - Index: id1.(string), - Value: id2.(string), - }, nil -} / id1:Identifier _? "," _? "_" { - return CollectionNameBinding{ - Mode: CollectionBindIndex, - Index: id1.(string), - }, nil -} / "_" _? "," _? id2:Identifier { - return CollectionNameBinding{ - Mode: CollectionBindValue, - Value: id2.(string), - }, nil -} / id:Identifier { - return CollectionNameBinding{ - Mode: CollectionBindDefault, - Default: id.(string), - }, nil -} - -CollectionOpAny <- "any" _ { - return CollectionOpAny, nil -} - -CollectionOpAll <- "all" _ { - return CollectionOpAll, nil -} - ParenthesizedExpression "grouping" <- "(" _? expr:OrExpression _? ")" { return expr, nil } / expr:MatchExpression { diff --git a/vendor/github.com/hashicorp/go-bexpr/options.go b/vendor/github.com/hashicorp/go-bexpr/options.go index e39c1355..ca682507 100644 --- a/vendor/github.com/hashicorp/go-bexpr/options.go +++ b/vendor/github.com/hashicorp/go-bexpr/options.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package bexpr // getOpts - iterate the inbound Options and return a struct @@ -14,14 +11,6 @@ func getOpts(opt ...Option) options { return opts } -// a localVariable can either point to a known value or replace another JSON -// Pointer path -type localVariable struct { - name string - path []string - value any -} - // Option - how Options are passed as arguments type Option func(*options) @@ -30,8 +19,6 @@ type options struct { withMaxExpressions uint64 withTagName string withHookFn ValueTransformationHookFn - withUnknown *interface{} - withLocalVariables []localVariable } func WithMaxExpressions(maxExprCnt uint64) Option { @@ -57,33 +44,9 @@ func WithHookFn(fn ValueTransformationHookFn) Option { } } -// WithUnknownValue sets a value that is used for any unknown keys. Normally, -// bexpr will error on any expressions with unknown keys. This can be set to -// instead use a specificed value whenever an unknown key is found. For example, -// this might be set to the empty string "". -func WithUnknownValue(val interface{}) Option { - return func(o *options) { - o.withUnknown = &val - } -} - -// WithLocalVariable add a local variable that can either point to another path -// that will be resolved when the local variable is referenced or to a known -// value that will be used directly. -func WithLocalVariable(name string, path []string, value any) Option { - return func(o *options) { - o.withLocalVariables = append(o.withLocalVariables, localVariable{ - name: name, - path: path, - value: value, - }) - } -} - func getDefaultOptions() options { return options{ withMaxExpressions: 0, withTagName: "bexpr", - withUnknown: nil, } } diff --git a/vendor/github.com/holiman/billy/shelf.go b/vendor/github.com/holiman/billy/shelf.go index 51024366..8726fb07 100644 --- a/vendor/github.com/holiman/billy/shelf.go +++ b/vendor/github.com/holiman/billy/shelf.go @@ -89,18 +89,16 @@ func openShelf(path string, slotSize uint32, onData onShelfDataFn, readonly bool flags = os.O_RDONLY } var ( - f store - err error - n int - fileName = filepath.Join(path, fname) + f store + err error + n int ) if path != "" { - f, err = os.OpenFile(fileName, flags, 0666) + f, err = os.OpenFile(filepath.Join(path, fname), flags, 0666) if err != nil { return nil, err } } else { - fileName = "" f = new(memoryStore) } if stat, err := f.Stat(); err != nil { @@ -126,7 +124,7 @@ func openShelf(path string, slotSize uint32, onData onShelfDataFn, readonly bool } if err != nil { _ = f.Close() - return nil, fmt.Errorf("%w, file %v", err, fileName) + return nil, err } switch { case h.Magic != Magic: @@ -138,7 +136,7 @@ func openShelf(path string, slotSize uint32, onData onShelfDataFn, readonly bool } if err != nil { _ = f.Close() - return nil, fmt.Errorf("%w, file %v", err, fileName) + return nil, err } dataSize := fileSize - ShelfHeaderSize if extra := dataSize % int(slotSize); extra != 0 { @@ -152,7 +150,7 @@ func openShelf(path string, slotSize uint32, onData onShelfDataFn, readonly bool } if err != nil { _ = f.Close() - return nil, fmt.Errorf("%w, file %v", err, fileName) + return nil, err } sh := &shelf{ slotSize: slotSize, @@ -163,7 +161,7 @@ func openShelf(path string, slotSize uint32, onData onShelfDataFn, readonly bool // Compact + iterate if err := sh.compact(onData, repair); err != nil { _ = f.Close() - return nil, fmt.Errorf("%w, file %v", err, fileName) + return nil, err } return sh, nil } diff --git a/vendor/github.com/jackc/pgservicefile/.travis.yml b/vendor/github.com/jackc/pgservicefile/.travis.yml new file mode 100644 index 00000000..e176228e --- /dev/null +++ b/vendor/github.com/jackc/pgservicefile/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.x + - tip + +matrix: + allow_failures: + - go: tip diff --git a/vendor/github.com/jackc/pgservicefile/README.md b/vendor/github.com/jackc/pgservicefile/README.md index 2fc7e012..e50ca126 100644 --- a/vendor/github.com/jackc/pgservicefile/README.md +++ b/vendor/github.com/jackc/pgservicefile/README.md @@ -1,6 +1,5 @@ -[![Go Reference](https://pkg.go.dev/badge/github.com/jackc/pgservicefile.svg)](https://pkg.go.dev/github.com/jackc/pgservicefile) -[![Build Status](https://github.com/jackc/pgservicefile/actions/workflows/ci.yml/badge.svg)](https://github.com/jackc/pgservicefile/actions/workflows/ci.yml) - +[![](https://godoc.org/github.com/jackc/pgservicefile?status.svg)](https://godoc.org/github.com/jackc/pgservicefile) +[![Build Status](https://travis-ci.org/jackc/pgservicefile.svg)](https://travis-ci.org/jackc/pgservicefile) # pgservicefile diff --git a/vendor/github.com/jackc/pgservicefile/pgservicefile.go b/vendor/github.com/jackc/pgservicefile/pgservicefile.go index c62caa7f..797bbab9 100644 --- a/vendor/github.com/jackc/pgservicefile/pgservicefile.go +++ b/vendor/github.com/jackc/pgservicefile/pgservicefile.go @@ -57,7 +57,7 @@ func ParseServicefile(r io.Reader) (*Servicefile, error) { } else if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { service = &Service{Name: line[1 : len(line)-1], Settings: make(map[string]string)} servicefile.Services = append(servicefile.Services, service) - } else if service != nil { + } else { parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { return nil, fmt.Errorf("unable to parse line %d", lineNum) @@ -67,8 +67,6 @@ func ParseServicefile(r io.Reader) (*Servicefile, error) { value := strings.TrimSpace(parts[1]) service.Settings[key] = value - } else { - return nil, fmt.Errorf("line %d is not in a section", lineNum) } } diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml index a2295380..4c28dff4 100644 --- a/vendor/github.com/klauspost/compress/.goreleaser.yml +++ b/vendor/github.com/klauspost/compress/.goreleaser.yml @@ -3,6 +3,7 @@ before: hooks: - ./gen.sh + - go install mvdan.cc/garble@v0.10.1 builds: - @@ -31,6 +32,7 @@ builds: - mips64le goarm: - 7 + gobinary: garble - id: "s2d" binary: s2d @@ -57,6 +59,7 @@ builds: - mips64le goarm: - 7 + gobinary: garble - id: "s2sx" binary: s2sx @@ -84,6 +87,7 @@ builds: - mips64le goarm: - 7 + gobinary: garble archives: - diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 05c7359e..dde75389 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -16,50 +16,6 @@ This package provides various compression algorithms. # changelog -* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6) - * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923 - * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925 - -* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5) - * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912 - * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908 - * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913 - * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910 - * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917 -https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918 - -* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4) - * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887 - * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886 - * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892 - * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890 - * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891 - -* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3) - * fse: Fix max header size https://github.com/klauspost/compress/pull/881 - * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877 - * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883 - -* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2) - * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876 - -* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1) - * s2: Fix S2 "best" dictionary wrong encoding by @klauspost in https://github.com/klauspost/compress/pull/871 - * flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869 - * s2: Fix EstimateBlockSize on 6&7 length input by @klauspost in https://github.com/klauspost/compress/pull/867 - -* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0) - * Add experimental dictionary builder https://github.com/klauspost/compress/pull/853 - * Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838 - * flate: Add limited window compression https://github.com/klauspost/compress/pull/843 - * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839 - * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837 - * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860 - -
- See changes to v1.16.x - - * July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7) * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829 * s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832 @@ -97,7 +53,6 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748 * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747 * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746 -
See changes to v1.15.x @@ -565,8 +520,6 @@ the stateless compress described below. For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing). -To disable all assembly add `-tags=noasm`. This works across all packages. - # Stateless compression This package offers stateless compression as a special option for gzip/deflate. @@ -585,7 +538,7 @@ For direct deflate use, NewStatelessWriter and StatelessDeflate are available. S A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer: -```go +``` // replace 'ioutil.Discard' with your output. gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression) if err != nil { @@ -693,7 +646,6 @@ Here are other packages of good quality and pure Go (no cgo wrappers or autoconv * [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression. * [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression. * [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index. -* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor. # license diff --git a/vendor/github.com/klauspost/compress/fse/compress.go b/vendor/github.com/klauspost/compress/fse/compress.go index 074018d8..65d77735 100644 --- a/vendor/github.com/klauspost/compress/fse/compress.go +++ b/vendor/github.com/klauspost/compress/fse/compress.go @@ -212,7 +212,7 @@ func (s *Scratch) writeCount() error { previous0 bool charnum uint16 - maxHeaderSize = ((int(s.symbolLen)*int(tableLog) + 4 + 2) >> 3) + 3 + maxHeaderSize = ((int(s.symbolLen) * int(tableLog)) >> 3) + 3 // Write Table Size bitStream = uint32(tableLog - minTablelog) diff --git a/vendor/github.com/klauspost/compress/huff0/bytereader.go b/vendor/github.com/klauspost/compress/huff0/bytereader.go new file mode 100644 index 00000000..4dcab8d2 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/bytereader.go @@ -0,0 +1,44 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package huff0 + +// byteReader provides a byte reader that reads +// little endian values from a byte stream. +// The input stream is manually advanced. +// The reader performs no bounds checks. +type byteReader struct { + b []byte + off int +} + +// init will initialize the reader and set the input. +func (b *byteReader) init(in []byte) { + b.b = in + b.off = 0 +} + +// Int32 returns a little endian int32 starting at current offset. +func (b byteReader) Int32() int32 { + v3 := int32(b.b[b.off+3]) + v2 := int32(b.b[b.off+2]) + v1 := int32(b.b[b.off+1]) + v0 := int32(b.b[b.off]) + return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0 +} + +// Uint32 returns a little endian uint32 starting at current offset. +func (b byteReader) Uint32() uint32 { + v3 := uint32(b.b[b.off+3]) + v2 := uint32(b.b[b.off+2]) + v1 := uint32(b.b[b.off+1]) + v0 := uint32(b.b[b.off]) + return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0 +} + +// remain will return the number of bytes remaining. +func (b byteReader) remain() int { + return len(b.b) - b.off +} diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go index 84aa3d12..518436cf 100644 --- a/vendor/github.com/klauspost/compress/huff0/compress.go +++ b/vendor/github.com/klauspost/compress/huff0/compress.go @@ -350,7 +350,6 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) { // Does not update s.clearCount. func (s *Scratch) countSimple(in []byte) (max int, reuse bool) { reuse = true - _ = s.count // Assert that s != nil to speed up the following loop. for _, v := range in { s.count[v]++ } @@ -416,7 +415,7 @@ func (s *Scratch) validateTable(c cTable) bool { // minTableLog provides the minimum logSize to safely represent a distribution. func (s *Scratch) minTableLog() uint8 { - minBitsSrc := highBit32(uint32(s.srcLen)) + 1 + minBitsSrc := highBit32(uint32(s.br.remain())) + 1 minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2 if minBitsSrc < minBitsSymbols { return uint8(minBitsSrc) @@ -428,7 +427,7 @@ func (s *Scratch) minTableLog() uint8 { func (s *Scratch) optimalTableLog() { tableLog := s.TableLog minBits := s.minTableLog() - maxBitsSrc := uint8(highBit32(uint32(s.srcLen-1))) - 1 + maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 1 if maxBitsSrc < tableLog { // Accuracy can be reduced tableLog = maxBitsSrc diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go index 77ecd68e..e8ad17ad 100644 --- a/vendor/github.com/klauspost/compress/huff0/huff0.go +++ b/vendor/github.com/klauspost/compress/huff0/huff0.go @@ -88,7 +88,7 @@ type Scratch struct { // Decoders will return ErrMaxDecodedSizeExceeded is this limit is exceeded. MaxDecodedSize int - srcLen int + br byteReader // MaxSymbolValue will override the maximum symbol value of the next block. MaxSymbolValue uint8 @@ -170,7 +170,7 @@ func (s *Scratch) prepare(in []byte) (*Scratch, error) { if s.fse == nil { s.fse = &fse.Scratch{} } - s.srcLen = len(in) + s.br.init(in) return s, nil } diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go index 2754bac6..2aa6a95a 100644 --- a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go +++ b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go @@ -51,7 +51,7 @@ func emitCopy(dst []byte, offset, length int) int { i := 0 // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The // threshold for this loop is a little higher (at 68 = 64 + 4), and the - // length emitted down below is a little lower (at 60 = 64 - 4), because + // length emitted down below is is a little lower (at 60 = 64 - 4), because // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as diff --git a/vendor/github.com/klauspost/compress/s2sx.mod b/vendor/github.com/klauspost/compress/s2sx.mod index 5a4412f9..2263853f 100644 --- a/vendor/github.com/klauspost/compress/s2sx.mod +++ b/vendor/github.com/klauspost/compress/s2sx.mod @@ -1,4 +1,4 @@ module github.com/klauspost/compress -go 1.19 +go 1.16 diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md index 92e2347b..bdd49c8b 100644 --- a/vendor/github.com/klauspost/compress/zstd/README.md +++ b/vendor/github.com/klauspost/compress/zstd/README.md @@ -259,7 +259,7 @@ nyc-taxi-data-10M.csv gzkp 1 3325605752 922273214 13929 227.68 ## Decompressor -Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested. +Staus: STABLE - there may still be subtle bugs, but a wide variety of content has been tested. This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz), kindly supplied by [fuzzit.dev](https://fuzzit.dev/). diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go index 03744fbc..9f17ce60 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockdec.go +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -554,9 +554,6 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) { if debugDecoder { printf("Compression modes: 0b%b", compMode) } - if compMode&3 != 0 { - return errors.New("corrupt block: reserved bits not zero") - } for i := uint(0); i < 3; i++ { mode := seqCompMode((compMode >> (6 - i*2)) & 3) if debugDecoder { diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go index 32a7f401..2cfe925a 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockenc.go +++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go @@ -427,16 +427,6 @@ func (b *blockEnc) encodeLits(lits []byte, raw bool) error { return nil } -// encodeRLE will encode an RLE block. -func (b *blockEnc) encodeRLE(val byte, length uint32) { - var bh blockHeader - bh.setLast(b.last) - bh.setSize(length) - bh.setType(blockTypeRLE) - b.output = bh.appendTo(b.output) - b.output = append(b.output, val) -} - // fuzzFseEncoder can be used to fuzz the FSE encoder. func fuzzFseEncoder(data []byte) int { if len(data) > maxSequences || len(data) < 2 { @@ -489,16 +479,6 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { if len(b.sequences) == 0 { return b.encodeLits(b.literals, rawAllLits) } - if len(b.sequences) == 1 && len(org) > 0 && len(b.literals) <= 1 { - // Check common RLE cases. - seq := b.sequences[0] - if seq.litLen == uint32(len(b.literals)) && seq.offset-3 == 1 { - // Offset == 1 and 0 or 1 literals. - b.encodeRLE(org[0], b.sequences[0].matchLen+zstdMinMatch+seq.litLen) - return nil - } - } - // We want some difference to at least account for the headers. saved := b.size - len(b.literals) - (b.size >> 6) if saved < 16 { diff --git a/vendor/github.com/klauspost/compress/zstd/decodeheader.go b/vendor/github.com/klauspost/compress/zstd/decodeheader.go index 6a5a2988..f6a24097 100644 --- a/vendor/github.com/klauspost/compress/zstd/decodeheader.go +++ b/vendor/github.com/klauspost/compress/zstd/decodeheader.go @@ -95,54 +95,42 @@ type Header struct { // If there isn't enough input, io.ErrUnexpectedEOF is returned. // The FirstBlock.OK will indicate if enough information was available to decode the first block header. func (h *Header) Decode(in []byte) error { - _, err := h.DecodeAndStrip(in) - return err -} - -// DecodeAndStrip will decode the header from the beginning of the stream -// and on success return the remaining bytes. -// This will decode the frame header and the first block header if enough bytes are provided. -// It is recommended to provide at least HeaderMaxSize bytes. -// If the frame header cannot be read an error will be returned. -// If there isn't enough input, io.ErrUnexpectedEOF is returned. -// The FirstBlock.OK will indicate if enough information was available to decode the first block header. -func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { *h = Header{} if len(in) < 4 { - return nil, io.ErrUnexpectedEOF + return io.ErrUnexpectedEOF } h.HeaderSize += 4 b, in := in[:4], in[4:] if string(b) != frameMagic { if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 { - return nil, ErrMagicMismatch + return ErrMagicMismatch } if len(in) < 4 { - return nil, io.ErrUnexpectedEOF + return io.ErrUnexpectedEOF } h.HeaderSize += 4 h.Skippable = true h.SkippableID = int(b[0] & 0xf) h.SkippableSize = binary.LittleEndian.Uint32(in) - return in[4:], nil + return nil } // Read Window_Descriptor // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor if len(in) < 1 { - return nil, io.ErrUnexpectedEOF + return io.ErrUnexpectedEOF } fhd, in := in[0], in[1:] h.HeaderSize++ h.SingleSegment = fhd&(1<<5) != 0 h.HasCheckSum = fhd&(1<<2) != 0 if fhd&(1<<3) != 0 { - return nil, errors.New("reserved bit set on frame header") + return errors.New("reserved bit set on frame header") } if !h.SingleSegment { if len(in) < 1 { - return nil, io.ErrUnexpectedEOF + return io.ErrUnexpectedEOF } var wd byte wd, in = in[0], in[1:] @@ -160,7 +148,7 @@ func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { size = 4 } if len(in) < int(size) { - return nil, io.ErrUnexpectedEOF + return io.ErrUnexpectedEOF } b, in = in[:size], in[size:] h.HeaderSize += int(size) @@ -190,7 +178,7 @@ func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { if fcsSize > 0 { h.HasFCS = true if len(in) < fcsSize { - return nil, io.ErrUnexpectedEOF + return io.ErrUnexpectedEOF } b, in = in[:fcsSize], in[fcsSize:] h.HeaderSize += int(fcsSize) @@ -211,7 +199,7 @@ func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { // Frame Header done, we will not fail from now on. if len(in) < 3 { - return in, nil + return nil } tmp := in[:3] bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16) @@ -221,7 +209,7 @@ func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { cSize := int(bh >> 3) switch blockType { case blockTypeReserved: - return in, nil + return nil case blockTypeRLE: h.FirstBlock.Compressed = true h.FirstBlock.DecompressedSize = cSize @@ -237,25 +225,5 @@ func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { } h.FirstBlock.OK = true - return in, nil -} - -// AppendTo will append the encoded header to the dst slice. -// There is no error checking performed on the header values. -func (h *Header) AppendTo(dst []byte) ([]byte, error) { - if h.Skippable { - magic := [4]byte{0x50, 0x2a, 0x4d, 0x18} - magic[0] |= byte(h.SkippableID & 0xf) - dst = append(dst, magic[:]...) - f := h.SkippableSize - return append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)), nil - } - f := frameHeader{ - ContentSize: h.FrameContentSize, - WindowSize: uint32(h.WindowSize), - SingleSegment: h.SingleSegment, - Checksum: h.HasCheckSum, - DictID: h.DictionaryID, - } - return f.appendTo(dst), nil + return nil } diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go index bbca1723..f04aaa21 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -82,7 +82,7 @@ var ( // can run multiple concurrent stateless decodes. It is even possible to // use stateless decodes while a stream is being decoded. // -// The Reset function can be used to initiate a new stream, which will considerably +// The Reset function can be used to initiate a new stream, which is will considerably // reduce the allocations normally caused by NewReader. func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) { initPredefined() diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go index b7b83164..8d5567fe 100644 --- a/vendor/github.com/klauspost/compress/zstd/dict.go +++ b/vendor/github.com/klauspost/compress/zstd/dict.go @@ -273,9 +273,6 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { enc.Encode(&block, b) addValues(&remain, block.literals) litTotal += len(block.literals) - if len(block.sequences) == 0 { - continue - } seqs += len(block.sequences) block.genCodes() addHist(&ll, block.coders.llEnc.Histogram()) @@ -289,9 +286,6 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if offset == 0 { continue } - if int(offset) >= len(o.History) { - continue - } if offset > 3 { newOffsets[offset-3]++ } else { @@ -342,9 +336,6 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if seqs/nUsed < 512 { // Use 512 as minimum. nUsed = seqs / 512 - if nUsed == 0 { - nUsed = 1 - } } copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) { hist := dst.Histogram() @@ -367,28 +358,6 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { fakeLength += v hist[i] = uint32(v) } - - // Ensure we aren't trying to represent RLE. - if maxCount == fakeLength { - for i := range hist { - if uint8(i) == maxSym { - fakeLength++ - maxSym++ - hist[i+1] = 1 - if maxSym > 1 { - break - } - } - if hist[0] == 0 { - fakeLength++ - hist[i] = 1 - if maxSym > 1 { - break - } - } - } - } - dst.HistogramFinished(maxSym, maxCount) dst.reUsed = false dst.useRLE = false diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go index 4613724e..9819d414 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_best.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go @@ -43,7 +43,7 @@ func (m *match) estBits(bitsPerByte int32) { if m.rep < 0 { ofc = ofCode(uint32(m.s-m.offset) + 3) } else { - ofc = ofCode(uint32(m.rep) & 3) + ofc = ofCode(uint32(m.rep)) } // Cost, excluding ofTT, mlTT := fsePredefEnc[tableOffsets].ct.symbolTT[ofc], fsePredefEnc[tableMatchLengths].ct.symbolTT[mlc] @@ -135,20 +135,8 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) { break } - // Add block to history s := e.addBlock(src) blk.size = len(src) - - // Check RLE first - if len(src) > zstdMinMatch { - ml := matchLen(src[1:], src) - if ml == len(src)-1 { - blk.literals = append(blk.literals, src[0]) - blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3}) - return - } - } - if len(src) < minNonLiteralBlockSize { blk.extraLits = len(src) blk.literals = blk.literals[:len(src)] @@ -209,10 +197,17 @@ encodeLoop: // Set m to a match at offset if it looks like that will improve compression. improve := func(m *match, offset int32, s int32, first uint32, rep int32) { - delta := s - offset - if delta >= e.maxMatchOff || delta <= 0 || load3232(src, offset) != first { + if s-offset >= e.maxMatchOff || load3232(src, offset) != first { return } + if debugAsserts { + if offset <= 0 { + panic(offset) + } + if !bytes.Equal(src[s:s+4], src[offset:offset+4]) { + panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) + } + } // Try to quick reject if we already have a long match. if m.length > 16 { left := len(src) - int(m.s+m.length) @@ -231,10 +226,8 @@ encodeLoop: } } l := 4 + e.matchlen(s+4, offset+4, src) - if m.rep <= 0 { + if rep < 0 { // Extend candidate match backwards as far as possible. - // Do not extend repeats as we can assume they are optimal - // and offsets change if s == nextEmit. tMin := s - e.maxMatchOff if tMin < 0 { tMin = 0 @@ -245,14 +238,7 @@ encodeLoop: l++ } } - if debugAsserts { - if offset >= s { - panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff)) - } - if !bytes.Equal(src[s:s+l], src[offset:offset+l]) { - panic(fmt.Sprintf("second match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) - } - } + cand := match{offset: offset, s: s, length: l, rep: rep} cand.estBits(bitsPerByte) if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 { @@ -295,7 +281,6 @@ encodeLoop: // Load next and check... e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: candidateL.offset} e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: candidateS.offset} - index0 := s + 1 // Look far ahead, unless we have a really long match already... if best.length < goodEnough { @@ -349,45 +334,41 @@ encodeLoop: } if debugAsserts { - if best.offset >= best.s { - panic(fmt.Sprintf("best.offset > s: %d >= %d", best.offset, best.s)) - } - if best.s < nextEmit { - panic(fmt.Sprintf("s %d < nextEmit %d", best.s, nextEmit)) - } - if best.offset < s-e.maxMatchOff { - panic(fmt.Sprintf("best.offset < s-e.maxMatchOff: %d < %d", best.offset, s-e.maxMatchOff)) - } if !bytes.Equal(src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]) { panic(fmt.Sprintf("match mismatch: %v != %v", src[best.s:best.s+best.length], src[best.offset:best.offset+best.length])) } } // We have a match, we can store the forward value - s = best.s if best.rep > 0 { var seq seq seq.matchLen = uint32(best.length - zstdMinMatch) + if debugAsserts && s <= nextEmit { + panic("s <= nextEmit") + } addLiterals(&seq, best.s) // Repeat. If bit 4 is set, this is a non-lit repeat. seq.offset = uint32(best.rep & 3) if debugSequences { - println("repeat sequence", seq, "next s:", best.s, "off:", best.s-best.offset) + println("repeat sequence", seq, "next s:", s) } blk.sequences = append(blk.sequences, seq) // Index old s + 1 -> s - 1 + index0 := s + 1 s = best.s + best.length - nextEmit = s - // Index skipped... - end := s - if s > sLimit+4 { - end = sLimit + 4 + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, best.length) + } + break encodeLoop } + // Index skipped... off := index0 + e.cur - for index0 < end { + for index0 < s { cv0 := load6432(src, index0) h0 := hashLen(cv0, bestLongTableBits, bestLongLen) h1 := hashLen(cv0, bestShortTableBits, bestShortLen) @@ -396,7 +377,6 @@ encodeLoop: off++ index0++ } - switch best.rep { case 2, 4 | 1: offset1, offset2 = offset2, offset1 @@ -405,17 +385,13 @@ encodeLoop: case 4 | 3: offset1, offset2, offset3 = offset1-1, offset1, offset2 } - if s >= sLimit { - if debugEncoder { - println("repeat ended", s, best.length) - } - break encodeLoop - } continue } // A 4-byte match has been found. Update recent offsets. // We'll later see if more than 4 bytes. + index0 := s + 1 + s = best.s t := best.offset offset1, offset2, offset3 = s-t, offset1, offset2 @@ -442,25 +418,19 @@ encodeLoop: } blk.sequences = append(blk.sequences, seq) nextEmit = s - - // Index old s + 1 -> s - 1 or sLimit - end := s - if s > sLimit-4 { - end = sLimit - 4 + if s >= sLimit { + break encodeLoop } - off := index0 + e.cur - for index0 < end { + // Index old s + 1 -> s - 1 + for index0 < s { cv0 := load6432(src, index0) h0 := hashLen(cv0, bestLongTableBits, bestLongLen) h1 := hashLen(cv0, bestShortTableBits, bestShortLen) + off := index0 + e.cur e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset} index0++ - off++ - } - if s >= sLimit { - break encodeLoop } } diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go index a4f5bf91..8582f31a 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_better.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go @@ -102,20 +102,9 @@ func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) { e.cur = e.maxMatchOff break } - // Add block to history + s := e.addBlock(src) blk.size = len(src) - - // Check RLE first - if len(src) > zstdMinMatch { - ml := matchLen(src[1:], src) - if ml == len(src)-1 { - blk.literals = append(blk.literals, src[0]) - blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3}) - return - } - } - if len(src) < minNonLiteralBlockSize { blk.extraLits = len(src) blk.literals = blk.literals[:len(src)] @@ -156,7 +145,7 @@ encodeLoop: var t int32 // We allow the encoder to optionally turn off repeat offsets across blocks canRepeat := len(blk.sequences) > 2 - var matched, index0 int32 + var matched int32 for { if debugAsserts && canRepeat && offset1 == 0 { @@ -173,7 +162,6 @@ encodeLoop: off := s + e.cur e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset} e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)} - index0 = s + 1 if canRepeat { if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { @@ -270,6 +258,7 @@ encodeLoop: } blk.sequences = append(blk.sequences, seq) + index0 := s + repOff2 s += lenght + repOff2 nextEmit = s if s >= sLimit { @@ -509,15 +498,15 @@ encodeLoop: } // Index match start+1 (long) -> s - 1 - off := index0 + e.cur + index0 := s - l + 1 for index0 < s-1 { cv0 := load6432(src, index0) cv1 := cv0 >> 8 h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + off := index0 + e.cur e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)} index0 += 2 - off += 2 } cv = load6432(src, s) @@ -683,7 +672,7 @@ encodeLoop: var t int32 // We allow the encoder to optionally turn off repeat offsets across blocks canRepeat := len(blk.sequences) > 2 - var matched, index0 int32 + var matched int32 for { if debugAsserts && canRepeat && offset1 == 0 { @@ -702,7 +691,6 @@ encodeLoop: e.markLongShardDirty(nextHashL) e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)} e.markShortShardDirty(nextHashS) - index0 = s + 1 if canRepeat { if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { @@ -738,6 +726,7 @@ encodeLoop: blk.sequences = append(blk.sequences, seq) // Index match start+1 (long) -> s - 1 + index0 := s + repOff s += lenght + repOff nextEmit = s @@ -801,6 +790,7 @@ encodeLoop: } blk.sequences = append(blk.sequences, seq) + index0 := s + repOff2 s += lenght + repOff2 nextEmit = s if s >= sLimit { @@ -1034,18 +1024,18 @@ encodeLoop: } // Index match start+1 (long) -> s - 1 - off := index0 + e.cur + index0 := s - l + 1 for index0 < s-1 { cv0 := load6432(src, index0) cv1 := cv0 >> 8 h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + off := index0 + e.cur e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} e.markLongShardDirty(h0) h1 := hashLen(cv1, betterShortTableBits, betterShortLen) e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)} e.markShortShardDirty(h1) index0 += 2 - off += 2 } cv = load6432(src, s) diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go index 20671dcb..faaf8192 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go @@ -94,7 +94,7 @@ func WithEncoderConcurrency(n int) EOption { // The value must be a power of two between MinWindowSize and MaxWindowSize. // A larger value will enable better compression but allocate more memory and, // for above-default values, take considerably longer. -// The default value is determined by the compression level and max 8MB. +// The default value is determined by the compression level. func WithWindowSize(n int) EOption { return func(o *encoderOptions) error { switch { @@ -232,9 +232,9 @@ func WithEncoderLevel(l EncoderLevel) EOption { case SpeedDefault: o.windowSize = 8 << 20 case SpeedBetterCompression: - o.windowSize = 8 << 20 + o.windowSize = 16 << 20 case SpeedBestCompression: - o.windowSize = 8 << 20 + o.windowSize = 32 << 20 } } if !o.customALEntropy { diff --git a/vendor/github.com/klauspost/compress/zstd/frameenc.go b/vendor/github.com/klauspost/compress/zstd/frameenc.go index 667ca067..2f5d5ed4 100644 --- a/vendor/github.com/klauspost/compress/zstd/frameenc.go +++ b/vendor/github.com/klauspost/compress/zstd/frameenc.go @@ -76,7 +76,7 @@ func (f frameHeader) appendTo(dst []byte) []byte { if f.SingleSegment { dst = append(dst, uint8(f.ContentSize)) } - // Unless SingleSegment is set, framessizes < 256 are not stored. + // Unless SingleSegment is set, framessizes < 256 are nto stored. case 1: f.ContentSize -= 256 dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8)) diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go index 8adfebb0..332e51fe 100644 --- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go @@ -20,9 +20,10 @@ func (s *fseDecoder) buildDtable() error { if v == -1 { s.dt[highThreshold].setAddBits(uint8(i)) highThreshold-- - v = 1 + symbolNext[i] = 1 + } else { + symbolNext[i] = uint16(v) } - symbolNext[i] = uint16(v) } } @@ -34,12 +35,10 @@ func (s *fseDecoder) buildDtable() error { for ss, v := range s.norm[:s.symbolLen] { for i := 0; i < int(v); i++ { s.dt[position].setAddBits(uint8(ss)) - for { + position = (position + step) & tableMask + for position > highThreshold { // lowprob area position = (position + step) & tableMask - if position <= highThreshold { - break - } } } } diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s index ae7d4d32..17901e08 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s @@ -162,12 +162,12 @@ finalize: MOVD h, ret+24(FP) RET -// func writeBlocks(s *Digest, b []byte) int +// func writeBlocks(d *Digest, b []byte) int TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 LDP ·primes+0(SB), (prime1, prime2) // Load state. Assume v[1-4] are stored contiguously. - MOVD s+0(FP), digest + MOVD d+0(FP), digest LDP 0(digest), (v1, v2) LDP 16(digest), (v3, v4) diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s index 0782b86e..9a7655c0 100644 --- a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s @@ -5,6 +5,7 @@ #include "textflag.h" // func matchLen(a []byte, b []byte) int +// Requires: BMI TEXT ·matchLen(SB), NOSPLIT, $0-56 MOVQ a_base+0(FP), AX MOVQ b_base+24(FP), CX @@ -16,16 +17,17 @@ TEXT ·matchLen(SB), NOSPLIT, $0-56 JB matchlen_match4_standalone matchlen_loopback_standalone: - MOVQ (AX)(SI*1), BX - XORQ (CX)(SI*1), BX - JZ matchlen_loop_standalone + MOVQ (AX)(SI*1), BX + XORQ (CX)(SI*1), BX + TESTQ BX, BX + JZ matchlen_loop_standalone #ifdef GOAMD64_v3 TZCNTQ BX, BX #else BSFQ BX, BX #endif - SHRL $0x03, BX + SARQ $0x03, BX LEAL (SI)(BX*1), SI JMP gen_match_len_end diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s index 5b06174b..974b9972 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -157,7 +157,8 @@ sequenceDecs_decode_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R14 - SHRL $0x10, DI + SHRQ $0x10, DI + MOVWQZX DI, DI LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -176,7 +177,8 @@ sequenceDecs_decode_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R14 - SHRL $0x10, R8 + SHRQ $0x10, R8 + MOVWQZX R8, R8 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -195,7 +197,8 @@ sequenceDecs_decode_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R14 - SHRL $0x10, R9 + SHRQ $0x10, R9 + MOVWQZX R9, R9 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -456,7 +459,8 @@ sequenceDecs_decode_56_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R14 - SHRL $0x10, DI + SHRQ $0x10, DI + MOVWQZX DI, DI LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -475,7 +479,8 @@ sequenceDecs_decode_56_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R14 - SHRL $0x10, R8 + SHRQ $0x10, R8 + MOVWQZX R8, R8 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -494,7 +499,8 @@ sequenceDecs_decode_56_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R14 - SHRL $0x10, R9 + SHRQ $0x10, R9 + MOVWQZX R9, R9 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -766,10 +772,11 @@ sequenceDecs_decode_bmi2_fill_2_end: BZHIQ R14, R15, R15 // Update Offset State - BZHIQ R8, R15, CX - SHRXQ R8, R15, R15 - SHRL $0x10, R8 - ADDQ CX, R8 + BZHIQ R8, R15, CX + SHRXQ R8, R15, R15 + MOVQ $0x00001010, R14 + BEXTRQ R14, R8, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -777,10 +784,11 @@ sequenceDecs_decode_bmi2_fill_2_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R15, CX - SHRXQ DI, R15, R15 - SHRL $0x10, DI - ADDQ CX, DI + BZHIQ DI, R15, CX + SHRXQ DI, R15, R15 + MOVQ $0x00001010, R14 + BEXTRQ R14, DI, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -788,9 +796,10 @@ sequenceDecs_decode_bmi2_fill_2_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R15, CX - SHRL $0x10, SI - ADDQ CX, SI + BZHIQ SI, R15, CX + MOVQ $0x00001010, R14 + BEXTRQ R14, SI, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX @@ -1023,10 +1032,11 @@ sequenceDecs_decode_56_bmi2_fill_end: BZHIQ R14, R15, R15 // Update Offset State - BZHIQ R8, R15, CX - SHRXQ R8, R15, R15 - SHRL $0x10, R8 - ADDQ CX, R8 + BZHIQ R8, R15, CX + SHRXQ R8, R15, R15 + MOVQ $0x00001010, R14 + BEXTRQ R14, R8, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -1034,10 +1044,11 @@ sequenceDecs_decode_56_bmi2_fill_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R15, CX - SHRXQ DI, R15, R15 - SHRL $0x10, DI - ADDQ CX, DI + BZHIQ DI, R15, CX + SHRXQ DI, R15, R15 + MOVQ $0x00001010, R14 + BEXTRQ R14, DI, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -1045,9 +1056,10 @@ sequenceDecs_decode_56_bmi2_fill_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R15, CX - SHRL $0x10, SI - ADDQ CX, SI + BZHIQ SI, R15, CX + MOVQ $0x00001010, R14 + BEXTRQ R14, SI, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX @@ -1955,7 +1967,8 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R13 - SHRL $0x10, DI + SHRQ $0x10, DI + MOVWQZX DI, DI LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -1974,7 +1987,8 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R13 - SHRL $0x10, R8 + SHRQ $0x10, R8 + MOVWQZX R8, R8 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -1993,7 +2007,8 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R13 - SHRL $0x10, R9 + SHRQ $0x10, R9 + MOVWQZX R9, R9 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -2499,10 +2514,11 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: BZHIQ R13, R14, R14 // Update Offset State - BZHIQ R8, R14, CX - SHRXQ R8, R14, R14 - SHRL $0x10, R8 - ADDQ CX, R8 + BZHIQ R8, R14, CX + SHRXQ R8, R14, R14 + MOVQ $0x00001010, R13 + BEXTRQ R13, R8, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -2510,10 +2526,11 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R14, CX - SHRXQ DI, R14, R14 - SHRL $0x10, DI - ADDQ CX, DI + BZHIQ DI, R14, CX + SHRXQ DI, R14, R14 + MOVQ $0x00001010, R13 + BEXTRQ R13, DI, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -2521,9 +2538,10 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R14, CX - SHRL $0x10, SI - ADDQ CX, SI + BZHIQ SI, R14, CX + MOVQ $0x00001010, R13 + BEXTRQ R13, SI, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX @@ -3037,7 +3055,8 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R13 - SHRL $0x10, DI + SHRQ $0x10, DI + MOVWQZX DI, DI LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -3056,7 +3075,8 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R13 - SHRL $0x10, R8 + SHRQ $0x10, R8 + MOVWQZX R8, R8 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -3075,7 +3095,8 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R13 - SHRL $0x10, R9 + SHRQ $0x10, R9 + MOVWQZX R9, R9 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -3683,10 +3704,11 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: BZHIQ R13, R14, R14 // Update Offset State - BZHIQ R8, R14, CX - SHRXQ R8, R14, R14 - SHRL $0x10, R8 - ADDQ CX, R8 + BZHIQ R8, R14, CX + SHRXQ R8, R14, R14 + MOVQ $0x00001010, R13 + BEXTRQ R13, R8, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -3694,10 +3716,11 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R14, CX - SHRXQ DI, R14, R14 - SHRL $0x10, DI - ADDQ CX, DI + BZHIQ DI, R14, CX + SHRXQ DI, R14, R14 + MOVQ $0x00001010, R13 + BEXTRQ R13, DI, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -3705,9 +3728,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R14, CX - SHRL $0x10, SI - ADDQ CX, SI + BZHIQ SI, R14, CX + MOVQ $0x00001010, R13 + BEXTRQ R13, SI, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_table.go b/vendor/github.com/mattn/go-runewidth/runewidth_table.go index e5d890c2..ad025ad5 100644 --- a/vendor/github.com/mattn/go-runewidth/runewidth_table.go +++ b/vendor/github.com/mattn/go-runewidth/runewidth_table.go @@ -4,20 +4,21 @@ package runewidth var combining = table{ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x07EB, 0x07F3}, - {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0D00, 0x0D01}, - {0x135D, 0x135F}, {0x1A7F, 0x1A7F}, {0x1AB0, 0x1AC0}, - {0x1B6B, 0x1B73}, {0x1DC0, 0x1DF9}, {0x1DFB, 0x1DFF}, + {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0CF3, 0x0CF3}, + {0x0D00, 0x0D01}, {0x135D, 0x135F}, {0x1A7F, 0x1A7F}, + {0x1AB0, 0x1ACE}, {0x1B6B, 0x1B73}, {0x1DC0, 0x1DFF}, {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2DE0, 0x2DFF}, {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA8E0, 0xA8F1}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, {0x10376, 0x1037A}, - {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x11300, 0x11301}, - {0x1133B, 0x1133C}, {0x11366, 0x1136C}, {0x11370, 0x11374}, - {0x16AF0, 0x16AF4}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172}, + {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x10F82, 0x10F85}, + {0x11300, 0x11301}, {0x1133B, 0x1133C}, {0x11366, 0x1136C}, + {0x11370, 0x11374}, {0x16AF0, 0x16AF4}, {0x1CF00, 0x1CF2D}, + {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, - {0x1E8D0, 0x1E8D6}, + {0x1E08F, 0x1E08F}, {0x1E8D0, 0x1E8D6}, } var doublewidth = table{ @@ -33,33 +34,34 @@ var doublewidth = table{ {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797}, {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C}, {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99}, - {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, - {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF}, - {0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E3}, - {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x4DBF}, - {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C}, - {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, - {0xFE30, 0xFE52}, {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, - {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE4}, - {0x16FF0, 0x16FF1}, {0x17000, 0x187F7}, {0x18800, 0x18CD5}, - {0x18D00, 0x18D08}, {0x1B000, 0x1B11E}, {0x1B150, 0x1B152}, - {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1F004, 0x1F004}, - {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A}, - {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248}, - {0x1F250, 0x1F251}, {0x1F260, 0x1F265}, {0x1F300, 0x1F320}, - {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393}, - {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0}, - {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440}, - {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E}, - {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596}, - {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5}, - {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2}, {0x1F6D5, 0x1F6D7}, - {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB}, - {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F978}, - {0x1F97A, 0x1F9CB}, {0x1F9CD, 0x1F9FF}, {0x1FA70, 0x1FA74}, - {0x1FA78, 0x1FA7A}, {0x1FA80, 0x1FA86}, {0x1FA90, 0x1FAA8}, - {0x1FAB0, 0x1FAB6}, {0x1FAC0, 0x1FAC2}, {0x1FAD0, 0x1FAD6}, - {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}, + {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x303E}, + {0x3041, 0x3096}, {0x3099, 0x30FF}, {0x3105, 0x312F}, + {0x3131, 0x318E}, {0x3190, 0x31E3}, {0x31EF, 0x321E}, + {0x3220, 0x3247}, {0x3250, 0x4DBF}, {0x4E00, 0xA48C}, + {0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE4}, {0x16FF0, 0x16FF1}, + {0x17000, 0x187F7}, {0x18800, 0x18CD5}, {0x18D00, 0x18D08}, + {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1AFFD, 0x1AFFE}, + {0x1B000, 0x1B122}, {0x1B132, 0x1B132}, {0x1B150, 0x1B152}, + {0x1B155, 0x1B155}, {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, + {0x1F004, 0x1F004}, {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, + {0x1F240, 0x1F248}, {0x1F250, 0x1F251}, {0x1F260, 0x1F265}, + {0x1F300, 0x1F320}, {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F393}, {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E}, + {0x1F440, 0x1F440}, {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D}, + {0x1F54B, 0x1F54E}, {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A}, + {0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F}, + {0x1F680, 0x1F6C5}, {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2}, + {0x1F6D5, 0x1F6D7}, {0x1F6DC, 0x1F6DF}, {0x1F6EB, 0x1F6EC}, + {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB}, {0x1F7F0, 0x1F7F0}, + {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F9FF}, + {0x1FA70, 0x1FA7C}, {0x1FA80, 0x1FA88}, {0x1FA90, 0x1FABD}, + {0x1FABF, 0x1FAC5}, {0x1FACE, 0x1FADB}, {0x1FAE0, 0x1FAE8}, + {0x1FAF0, 0x1FAF8}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}, } var ambiguous = table{ @@ -154,43 +156,43 @@ var neutral = table{ {0x0402, 0x040F}, {0x0450, 0x0450}, {0x0452, 0x052F}, {0x0531, 0x0556}, {0x0559, 0x058A}, {0x058D, 0x058F}, {0x0591, 0x05C7}, {0x05D0, 0x05EA}, {0x05EF, 0x05F4}, - {0x0600, 0x061C}, {0x061E, 0x070D}, {0x070F, 0x074A}, - {0x074D, 0x07B1}, {0x07C0, 0x07FA}, {0x07FD, 0x082D}, - {0x0830, 0x083E}, {0x0840, 0x085B}, {0x085E, 0x085E}, - {0x0860, 0x086A}, {0x08A0, 0x08B4}, {0x08B6, 0x08C7}, - {0x08D3, 0x0983}, {0x0985, 0x098C}, {0x098F, 0x0990}, - {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, - {0x09B6, 0x09B9}, {0x09BC, 0x09C4}, {0x09C7, 0x09C8}, - {0x09CB, 0x09CE}, {0x09D7, 0x09D7}, {0x09DC, 0x09DD}, - {0x09DF, 0x09E3}, {0x09E6, 0x09FE}, {0x0A01, 0x0A03}, - {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, - {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, - {0x0A38, 0x0A39}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, - {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, - {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A76}, - {0x0A81, 0x0A83}, {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91}, - {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, - {0x0AB5, 0x0AB9}, {0x0ABC, 0x0AC5}, {0x0AC7, 0x0AC9}, - {0x0ACB, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE3}, - {0x0AE6, 0x0AF1}, {0x0AF9, 0x0AFF}, {0x0B01, 0x0B03}, - {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, - {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, {0x0B35, 0x0B39}, - {0x0B3C, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, - {0x0B55, 0x0B57}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B63}, - {0x0B66, 0x0B77}, {0x0B82, 0x0B83}, {0x0B85, 0x0B8A}, - {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, - {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4}, - {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BC2}, - {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0BD0, 0x0BD0}, - {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BFA}, {0x0C00, 0x0C0C}, - {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C39}, - {0x0C3D, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, - {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C63}, + {0x0600, 0x070D}, {0x070F, 0x074A}, {0x074D, 0x07B1}, + {0x07C0, 0x07FA}, {0x07FD, 0x082D}, {0x0830, 0x083E}, + {0x0840, 0x085B}, {0x085E, 0x085E}, {0x0860, 0x086A}, + {0x0870, 0x088E}, {0x0890, 0x0891}, {0x0898, 0x0983}, + {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8}, + {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9}, + {0x09BC, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CE}, + {0x09D7, 0x09D7}, {0x09DC, 0x09DD}, {0x09DF, 0x09E3}, + {0x09E6, 0x09FE}, {0x0A01, 0x0A03}, {0x0A05, 0x0A0A}, + {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, + {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39}, + {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, {0x0A47, 0x0A48}, + {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A59, 0x0A5C}, + {0x0A5E, 0x0A5E}, {0x0A66, 0x0A76}, {0x0A81, 0x0A83}, + {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, + {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, + {0x0ABC, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, + {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE3}, {0x0AE6, 0x0AF1}, + {0x0AF9, 0x0AFF}, {0x0B01, 0x0B03}, {0x0B05, 0x0B0C}, + {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, + {0x0B32, 0x0B33}, {0x0B35, 0x0B39}, {0x0B3C, 0x0B44}, + {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, {0x0B55, 0x0B57}, + {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B63}, {0x0B66, 0x0B77}, + {0x0B82, 0x0B83}, {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, + {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, + {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, + {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, + {0x0BCA, 0x0BCD}, {0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, + {0x0BE6, 0x0BFA}, {0x0C00, 0x0C0C}, {0x0C0E, 0x0C10}, + {0x0C12, 0x0C28}, {0x0C2A, 0x0C39}, {0x0C3C, 0x0C44}, + {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, + {0x0C58, 0x0C5A}, {0x0C5D, 0x0C5D}, {0x0C60, 0x0C63}, {0x0C66, 0x0C6F}, {0x0C77, 0x0C8C}, {0x0C8E, 0x0C90}, {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9}, {0x0CBC, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, - {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE3}, - {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, {0x0D00, 0x0D0C}, + {0x0CD5, 0x0CD6}, {0x0CDD, 0x0CDE}, {0x0CE0, 0x0CE3}, + {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF3}, {0x0D00, 0x0D0C}, {0x0D0E, 0x0D10}, {0x0D12, 0x0D44}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4F}, {0x0D54, 0x0D63}, {0x0D66, 0x0D7F}, {0x0D81, 0x0D83}, {0x0D85, 0x0D96}, {0x0D9A, 0x0DB1}, @@ -200,7 +202,7 @@ var neutral = table{ {0x0E01, 0x0E3A}, {0x0E3F, 0x0E5B}, {0x0E81, 0x0E82}, {0x0E84, 0x0E84}, {0x0E86, 0x0E8A}, {0x0E8C, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EBD}, {0x0EC0, 0x0EC4}, - {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, + {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECE}, {0x0ED0, 0x0ED9}, {0x0EDC, 0x0EDF}, {0x0F00, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F71, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FBE, 0x0FCC}, {0x0FCE, 0x0FDA}, {0x1000, 0x10C5}, {0x10C7, 0x10C7}, @@ -212,20 +214,19 @@ var neutral = table{ {0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A}, {0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x169C}, {0x16A0, 0x16F8}, - {0x1700, 0x170C}, {0x170E, 0x1714}, {0x1720, 0x1736}, - {0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770}, - {0x1772, 0x1773}, {0x1780, 0x17DD}, {0x17E0, 0x17E9}, - {0x17F0, 0x17F9}, {0x1800, 0x180E}, {0x1810, 0x1819}, - {0x1820, 0x1878}, {0x1880, 0x18AA}, {0x18B0, 0x18F5}, - {0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B}, - {0x1940, 0x1940}, {0x1944, 0x196D}, {0x1970, 0x1974}, - {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA}, - {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C}, - {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD}, - {0x1AB0, 0x1AC0}, {0x1B00, 0x1B4B}, {0x1B50, 0x1B7C}, - {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49}, - {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7}, - {0x1CD0, 0x1CFA}, {0x1D00, 0x1DF9}, {0x1DFB, 0x1F15}, + {0x1700, 0x1715}, {0x171F, 0x1736}, {0x1740, 0x1753}, + {0x1760, 0x176C}, {0x176E, 0x1770}, {0x1772, 0x1773}, + {0x1780, 0x17DD}, {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, + {0x1800, 0x1819}, {0x1820, 0x1878}, {0x1880, 0x18AA}, + {0x18B0, 0x18F5}, {0x1900, 0x191E}, {0x1920, 0x192B}, + {0x1930, 0x193B}, {0x1940, 0x1940}, {0x1944, 0x196D}, + {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9}, + {0x19D0, 0x19DA}, {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, + {0x1A60, 0x1A7C}, {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, + {0x1AA0, 0x1AAD}, {0x1AB0, 0x1ACE}, {0x1B00, 0x1B4C}, + {0x1B50, 0x1B7E}, {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, + {0x1C3B, 0x1C49}, {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA}, + {0x1CBD, 0x1CC7}, {0x1CD0, 0x1CFA}, {0x1D00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B}, {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, @@ -237,7 +238,7 @@ var neutral = table{ {0x2036, 0x203A}, {0x203C, 0x203D}, {0x203F, 0x2064}, {0x2066, 0x2071}, {0x2075, 0x207E}, {0x2080, 0x2080}, {0x2085, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8}, - {0x20AA, 0x20AB}, {0x20AD, 0x20BF}, {0x20D0, 0x20F0}, + {0x20AA, 0x20AB}, {0x20AD, 0x20C0}, {0x20D0, 0x20F0}, {0x2100, 0x2102}, {0x2104, 0x2104}, {0x2106, 0x2108}, {0x210A, 0x2112}, {0x2114, 0x2115}, {0x2117, 0x2120}, {0x2123, 0x2125}, {0x2127, 0x212A}, {0x212C, 0x2152}, @@ -275,15 +276,15 @@ var neutral = table{ {0x2780, 0x2794}, {0x2798, 0x27AF}, {0x27B1, 0x27BE}, {0x27C0, 0x27E5}, {0x27EE, 0x2984}, {0x2987, 0x2B1A}, {0x2B1D, 0x2B4F}, {0x2B51, 0x2B54}, {0x2B5A, 0x2B73}, - {0x2B76, 0x2B95}, {0x2B97, 0x2C2E}, {0x2C30, 0x2C5E}, - {0x2C60, 0x2CF3}, {0x2CF9, 0x2D25}, {0x2D27, 0x2D27}, - {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D70}, - {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, - {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, - {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, - {0x2DE0, 0x2E52}, {0x303F, 0x303F}, {0x4DC0, 0x4DFF}, - {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, {0xA700, 0xA7BF}, - {0xA7C2, 0xA7CA}, {0xA7F5, 0xA82C}, {0xA830, 0xA839}, + {0x2B76, 0x2B95}, {0x2B97, 0x2CF3}, {0x2CF9, 0x2D25}, + {0x2D27, 0x2D27}, {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, + {0x2D6F, 0x2D70}, {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6}, + {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, + {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, + {0x2DD8, 0x2DDE}, {0x2DE0, 0x2E5D}, {0x303F, 0x303F}, + {0x4DC0, 0x4DFF}, {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, + {0xA700, 0xA7CA}, {0xA7D0, 0xA7D1}, {0xA7D3, 0xA7D3}, + {0xA7D5, 0xA7D9}, {0xA7F2, 0xA82C}, {0xA830, 0xA839}, {0xA840, 0xA877}, {0xA880, 0xA8C5}, {0xA8CE, 0xA8D9}, {0xA8E0, 0xA953}, {0xA95F, 0xA95F}, {0xA980, 0xA9CD}, {0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36}, @@ -294,8 +295,8 @@ var neutral = table{ {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDFFF}, {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36}, {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41}, - {0xFB43, 0xFB44}, {0xFB46, 0xFBC1}, {0xFBD3, 0xFD3F}, - {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, {0xFDF0, 0xFDFD}, + {0xFB43, 0xFB44}, {0xFB46, 0xFBC2}, {0xFBD3, 0xFD8F}, + {0xFD92, 0xFDC7}, {0xFDCF, 0xFDCF}, {0xFDF0, 0xFDFF}, {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFC}, {0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003C, 0x1003D}, @@ -307,44 +308,48 @@ var neutral = table{ {0x10380, 0x1039D}, {0x1039F, 0x103C3}, {0x103C8, 0x103D5}, {0x10400, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3}, {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563}, - {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755}, - {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808}, - {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C}, - {0x1083F, 0x10855}, {0x10857, 0x1089E}, {0x108A7, 0x108AF}, - {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x1091B}, - {0x1091F, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x109B7}, - {0x109BC, 0x109CF}, {0x109D2, 0x10A03}, {0x10A05, 0x10A06}, - {0x10A0C, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A35}, - {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48}, {0x10A50, 0x10A58}, - {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, {0x10AEB, 0x10AF6}, - {0x10B00, 0x10B35}, {0x10B39, 0x10B55}, {0x10B58, 0x10B72}, - {0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF}, - {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2}, - {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, {0x10E60, 0x10E7E}, - {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD}, {0x10EB0, 0x10EB1}, - {0x10F00, 0x10F27}, {0x10F30, 0x10F59}, {0x10FB0, 0x10FCB}, - {0x10FE0, 0x10FF6}, {0x11000, 0x1104D}, {0x11052, 0x1106F}, - {0x1107F, 0x110C1}, {0x110CD, 0x110CD}, {0x110D0, 0x110E8}, - {0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11147}, - {0x11150, 0x11176}, {0x11180, 0x111DF}, {0x111E1, 0x111F4}, - {0x11200, 0x11211}, {0x11213, 0x1123E}, {0x11280, 0x11286}, - {0x11288, 0x11288}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, - {0x1129F, 0x112A9}, {0x112B0, 0x112EA}, {0x112F0, 0x112F9}, - {0x11300, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310}, - {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333}, - {0x11335, 0x11339}, {0x1133B, 0x11344}, {0x11347, 0x11348}, - {0x1134B, 0x1134D}, {0x11350, 0x11350}, {0x11357, 0x11357}, - {0x1135D, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374}, - {0x11400, 0x1145B}, {0x1145D, 0x11461}, {0x11480, 0x114C7}, - {0x114D0, 0x114D9}, {0x11580, 0x115B5}, {0x115B8, 0x115DD}, - {0x11600, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C}, - {0x11680, 0x116B8}, {0x116C0, 0x116C9}, {0x11700, 0x1171A}, - {0x1171D, 0x1172B}, {0x11730, 0x1173F}, {0x11800, 0x1183B}, - {0x118A0, 0x118F2}, {0x118FF, 0x11906}, {0x11909, 0x11909}, - {0x1190C, 0x11913}, {0x11915, 0x11916}, {0x11918, 0x11935}, - {0x11937, 0x11938}, {0x1193B, 0x11946}, {0x11950, 0x11959}, - {0x119A0, 0x119A7}, {0x119AA, 0x119D7}, {0x119DA, 0x119E4}, - {0x11A00, 0x11A47}, {0x11A50, 0x11AA2}, {0x11AC0, 0x11AF8}, + {0x1056F, 0x1057A}, {0x1057C, 0x1058A}, {0x1058C, 0x10592}, + {0x10594, 0x10595}, {0x10597, 0x105A1}, {0x105A3, 0x105B1}, + {0x105B3, 0x105B9}, {0x105BB, 0x105BC}, {0x10600, 0x10736}, + {0x10740, 0x10755}, {0x10760, 0x10767}, {0x10780, 0x10785}, + {0x10787, 0x107B0}, {0x107B2, 0x107BA}, {0x10800, 0x10805}, + {0x10808, 0x10808}, {0x1080A, 0x10835}, {0x10837, 0x10838}, + {0x1083C, 0x1083C}, {0x1083F, 0x10855}, {0x10857, 0x1089E}, + {0x108A7, 0x108AF}, {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, + {0x108FB, 0x1091B}, {0x1091F, 0x10939}, {0x1093F, 0x1093F}, + {0x10980, 0x109B7}, {0x109BC, 0x109CF}, {0x109D2, 0x10A03}, + {0x10A05, 0x10A06}, {0x10A0C, 0x10A13}, {0x10A15, 0x10A17}, + {0x10A19, 0x10A35}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48}, + {0x10A50, 0x10A58}, {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, + {0x10AEB, 0x10AF6}, {0x10B00, 0x10B35}, {0x10B39, 0x10B55}, + {0x10B58, 0x10B72}, {0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, + {0x10BA9, 0x10BAF}, {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, + {0x10CC0, 0x10CF2}, {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, + {0x10E60, 0x10E7E}, {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD}, + {0x10EB0, 0x10EB1}, {0x10EFD, 0x10F27}, {0x10F30, 0x10F59}, + {0x10F70, 0x10F89}, {0x10FB0, 0x10FCB}, {0x10FE0, 0x10FF6}, + {0x11000, 0x1104D}, {0x11052, 0x11075}, {0x1107F, 0x110C2}, + {0x110CD, 0x110CD}, {0x110D0, 0x110E8}, {0x110F0, 0x110F9}, + {0x11100, 0x11134}, {0x11136, 0x11147}, {0x11150, 0x11176}, + {0x11180, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211}, + {0x11213, 0x11241}, {0x11280, 0x11286}, {0x11288, 0x11288}, + {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A9}, + {0x112B0, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11303}, + {0x11305, 0x1130C}, {0x1130F, 0x11310}, {0x11313, 0x11328}, + {0x1132A, 0x11330}, {0x11332, 0x11333}, {0x11335, 0x11339}, + {0x1133B, 0x11344}, {0x11347, 0x11348}, {0x1134B, 0x1134D}, + {0x11350, 0x11350}, {0x11357, 0x11357}, {0x1135D, 0x11363}, + {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x1145B}, + {0x1145D, 0x11461}, {0x11480, 0x114C7}, {0x114D0, 0x114D9}, + {0x11580, 0x115B5}, {0x115B8, 0x115DD}, {0x11600, 0x11644}, + {0x11650, 0x11659}, {0x11660, 0x1166C}, {0x11680, 0x116B9}, + {0x116C0, 0x116C9}, {0x11700, 0x1171A}, {0x1171D, 0x1172B}, + {0x11730, 0x11746}, {0x11800, 0x1183B}, {0x118A0, 0x118F2}, + {0x118FF, 0x11906}, {0x11909, 0x11909}, {0x1190C, 0x11913}, + {0x11915, 0x11916}, {0x11918, 0x11935}, {0x11937, 0x11938}, + {0x1193B, 0x11946}, {0x11950, 0x11959}, {0x119A0, 0x119A7}, + {0x119AA, 0x119D7}, {0x119DA, 0x119E4}, {0x11A00, 0x11A47}, + {0x11A50, 0x11AA2}, {0x11AB0, 0x11AF8}, {0x11B00, 0x11B09}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, {0x11C38, 0x11C45}, {0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, {0x11D00, 0x11D06}, {0x11D08, 0x11D09}, @@ -352,30 +357,36 @@ var neutral = table{ {0x11D3F, 0x11D47}, {0x11D50, 0x11D59}, {0x11D60, 0x11D65}, {0x11D67, 0x11D68}, {0x11D6A, 0x11D8E}, {0x11D90, 0x11D91}, {0x11D93, 0x11D98}, {0x11DA0, 0x11DA9}, {0x11EE0, 0x11EF8}, + {0x11F00, 0x11F10}, {0x11F12, 0x11F3A}, {0x11F3E, 0x11F59}, {0x11FB0, 0x11FB0}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399}, {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543}, - {0x13000, 0x1342E}, {0x13430, 0x13438}, {0x14400, 0x14646}, + {0x12F90, 0x12FF2}, {0x13000, 0x13455}, {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, - {0x16A6E, 0x16A6F}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5}, - {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, - {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E9A}, - {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, {0x16F8F, 0x16F9F}, - {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, - {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3}, {0x1D000, 0x1D0F5}, - {0x1D100, 0x1D126}, {0x1D129, 0x1D1E8}, {0x1D200, 0x1D245}, - {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, {0x1D360, 0x1D378}, - {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F}, - {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC}, - {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3}, - {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, - {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, - {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550}, - {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B}, - {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, - {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, - {0x1E026, 0x1E02A}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D}, - {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E2C0, 0x1E2F9}, - {0x1E2FF, 0x1E2FF}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6}, + {0x16A6E, 0x16ABE}, {0x16AC0, 0x16AC9}, {0x16AD0, 0x16AED}, + {0x16AF0, 0x16AF5}, {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, + {0x16B5B, 0x16B61}, {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, + {0x16E40, 0x16E9A}, {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, + {0x16F8F, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, + {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3}, + {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1CF50, 0x1CFC3}, + {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D1EA}, + {0x1D200, 0x1D245}, {0x1D2C0, 0x1D2D3}, {0x1D2E0, 0x1D2F3}, + {0x1D300, 0x1D356}, {0x1D360, 0x1D378}, {0x1D400, 0x1D454}, + {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2}, + {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, + {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, + {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, + {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, + {0x1D546, 0x1D546}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, + {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, + {0x1DAA1, 0x1DAAF}, {0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A}, + {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, + {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E030, 0x1E06D}, + {0x1E08F, 0x1E08F}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D}, + {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E290, 0x1E2AE}, + {0x1E2C0, 0x1E2F9}, {0x1E2FF, 0x1E2FF}, {0x1E4D0, 0x1E4F9}, + {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7ED, 0x1E7EE}, + {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6}, {0x1E900, 0x1E94B}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F}, {0x1EC71, 0x1ECB4}, {0x1ED01, 0x1ED3D}, {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, {0x1EE24, 0x1EE24}, @@ -400,8 +411,8 @@ var neutral = table{ {0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594}, {0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F}, {0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6D3, 0x1F6D4}, - {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, - {0x1F780, 0x1F7D8}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, + {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F776}, + {0x1F77B, 0x1F7D9}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859}, {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0x1F8B0, 0x1F8B1}, {0x1F900, 0x1F90B}, {0x1F93B, 0x1F93B}, {0x1F946, 0x1F946}, {0x1FA00, 0x1FA53}, {0x1FA60, 0x1FA6D}, diff --git a/vendor/github.com/mitchellh/pointerstructure/get.go b/vendor/github.com/mitchellh/pointerstructure/get.go index 8d81f0ee..fad3856c 100644 --- a/vendor/github.com/mitchellh/pointerstructure/get.go +++ b/vendor/github.com/mitchellh/pointerstructure/get.go @@ -154,7 +154,7 @@ func (p *Pointer) getStruct(part string, m reflect.Value) (reflect.Value, error) } if !found { - return reflect.Value{}, fmt.Errorf("%w: struct field with name %q", ErrNotFound, part) + return reflect.Value{}, fmt.Errorf("couldn't find struct field with name %q", part) } if ignored { diff --git a/vendor/github.com/munnerz/goautoneg/LICENSE b/vendor/github.com/munnerz/goautoneg/LICENSE deleted file mode 100644 index bbc7b897..00000000 --- a/vendor/github.com/munnerz/goautoneg/LICENSE +++ /dev/null @@ -1,31 +0,0 @@ -Copyright (c) 2011, Open Knowledge Foundation Ltd. -All rights reserved. - -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. - - Neither the name of the Open Knowledge Foundation Ltd. nor the - names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - -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 --git a/vendor/github.com/munnerz/goautoneg/Makefile b/vendor/github.com/munnerz/goautoneg/Makefile deleted file mode 100644 index e33ee173..00000000 --- a/vendor/github.com/munnerz/goautoneg/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -include $(GOROOT)/src/Make.inc - -TARG=bitbucket.org/ww/goautoneg -GOFILES=autoneg.go - -include $(GOROOT)/src/Make.pkg - -format: - gofmt -w *.go - -docs: - gomake clean - godoc ${TARG} > README.txt diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go index 25cfaa21..b2b89b01 100644 --- a/vendor/github.com/prometheus/common/expfmt/decode.go +++ b/vendor/github.com/prometheus/common/expfmt/decode.go @@ -75,14 +75,14 @@ func ResponseFormat(h http.Header) Format { func NewDecoder(r io.Reader, format Format) Decoder { switch format.FormatType() { case TypeProtoDelim: - return &protoDecoder{r: bufio.NewReader(r)} + return &protoDecoder{r: r} } return &textDecoder{r: r} } // protoDecoder implements the Decoder interface for protocol buffers. type protoDecoder struct { - r protodelim.Reader + r io.Reader } // Decode implements the Decoder interface. @@ -90,7 +90,7 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error { opts := protodelim.UnmarshalOptions{ MaxSize: -1, } - if err := opts.UnmarshalFrom(d.r, v); err != nil { + if err := opts.UnmarshalFrom(bufio.NewReader(d.r), v); err != nil { return err } if !model.IsValidMetricName(model.LabelValue(v.GetName())) { diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go index ff5ef7a9..8fd80618 100644 --- a/vendor/github.com/prometheus/common/expfmt/encode.go +++ b/vendor/github.com/prometheus/common/expfmt/encode.go @@ -21,10 +21,9 @@ import ( "google.golang.org/protobuf/encoding/protodelim" "google.golang.org/protobuf/encoding/prototext" + "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg" "github.com/prometheus/common/model" - "github.com/munnerz/goautoneg" - dto "github.com/prometheus/client_model/go" ) @@ -140,13 +139,7 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format { // interface is kept for backwards compatibility. // In cases where the Format does not allow for UTF-8 names, the global // NameEscapingScheme will be applied. -// -// NewEncoder can be called with additional options to customize the OpenMetrics text output. -// For example: -// NewEncoder(w, FmtOpenMetrics_1_0_0, WithCreatedLines()) -// -// Extra options are ignored for all other formats. -func NewEncoder(w io.Writer, format Format, options ...EncoderOption) Encoder { +func NewEncoder(w io.Writer, format Format) Encoder { escapingScheme := format.ToEscapingScheme() switch format.FormatType() { @@ -185,7 +178,7 @@ func NewEncoder(w io.Writer, format Format, options ...EncoderOption) Encoder { case TypeOpenMetrics: return encoderCloser{ encode: func(v *dto.MetricFamily) error { - _, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme), options...) + _, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme)) return err }, close: func() error { diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go index 051b38cd..6fc9555e 100644 --- a/vendor/github.com/prometheus/common/expfmt/expfmt.go +++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go @@ -15,7 +15,6 @@ package expfmt import ( - "fmt" "strings" "github.com/prometheus/common/model" @@ -64,7 +63,7 @@ const ( type FormatType int const ( - TypeUnknown FormatType = iota + TypeUnknown = iota TypeProtoCompact TypeProtoDelim TypeProtoText @@ -74,8 +73,7 @@ const ( // NewFormat generates a new Format from the type provided. Mostly used for // tests, most Formats should be generated as part of content negotiation in -// encode.go. If a type has more than one version, the latest version will be -// returned. +// encode.go. func NewFormat(t FormatType) Format { switch t { case TypeProtoCompact: @@ -93,21 +91,13 @@ func NewFormat(t FormatType) Format { } } -// NewOpenMetricsFormat generates a new OpenMetrics format matching the -// specified version number. -func NewOpenMetricsFormat(version string) (Format, error) { - if version == OpenMetricsVersion_0_0_1 { - return fmtOpenMetrics_0_0_1, nil - } - if version == OpenMetricsVersion_1_0_0 { - return fmtOpenMetrics_1_0_0, nil - } - return fmtUnknown, fmt.Errorf("unknown open metrics version string") -} - // FormatType deduces an overall FormatType for the given format. func (f Format) FormatType() FormatType { toks := strings.Split(string(f), ";") + if len(toks) < 2 { + return TypeUnknown + } + params := make(map[string]string) for i, t := range toks { if i == 0 { diff --git a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go index 353c5e93..5622578e 100644 --- a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go +++ b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go @@ -22,47 +22,11 @@ import ( "strconv" "strings" - "google.golang.org/protobuf/types/known/timestamppb" - "github.com/prometheus/common/model" dto "github.com/prometheus/client_model/go" ) -type encoderOption struct { - withCreatedLines bool - withUnit bool -} - -type EncoderOption func(*encoderOption) - -// WithCreatedLines is an EncoderOption that configures the OpenMetrics encoder -// to include _created lines (See -// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1). -// Created timestamps can improve the accuracy of series reset detection, but -// come with a bandwidth cost. -// -// At the time of writing, created timestamp ingestion is still experimental in -// Prometheus and need to be enabled with the feature-flag -// `--feature-flag=created-timestamp-zero-ingestion`, and breaking changes are -// still possible. Therefore, it is recommended to use this feature with caution. -func WithCreatedLines() EncoderOption { - return func(t *encoderOption) { - t.withCreatedLines = true - } -} - -// WithUnit is an EncoderOption enabling a set unit to be written to the output -// and to be added to the metric name, if it's not there already, as a suffix. -// Without opting in this way, the unit will not be added to the metric name and, -// on top of that, the unit will not be passed onto the output, even if it -// were declared in the *dto.MetricFamily struct, i.e. even if in.Unit !=nil. -func WithUnit() EncoderOption { - return func(t *encoderOption) { - t.withUnit = true - } -} - // MetricFamilyToOpenMetrics converts a MetricFamily proto message into the // OpenMetrics text format and writes the resulting lines to 'out'. It returns // the number of bytes written and any error encountered. The output will have @@ -95,34 +59,20 @@ func WithUnit() EncoderOption { // Prometheus to OpenMetrics or vice versa: // // - Counters are expected to have the `_total` suffix in their metric name. In -// the output, the suffix will be truncated from the `# TYPE`, `# HELP` and `# UNIT` -// lines. A counter with a missing `_total` suffix is not an error. However, +// the output, the suffix will be truncated from the `# TYPE` and `# HELP` +// line. A counter with a missing `_total` suffix is not an error. However, // its type will be set to `unknown` in that case to avoid invalid OpenMetrics // output. // -// - According to the OM specs, the `# UNIT` line is optional, but if populated, -// the unit has to be present in the metric name as its suffix: -// (see https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#unit). -// However, in order to accommodate any potential scenario where such a change in the -// metric name is not desirable, the users are here given the choice of either explicitly -// opt in, in case they wish for the unit to be included in the output AND in the metric name -// as a suffix (see the description of the WithUnit function above), -// or not to opt in, in case they don't want for any of that to happen. -// -// - No support for the following (optional) features: info type, -// stateset type, gaugehistogram type. +// - No support for the following (optional) features: `# UNIT` line, `_created` +// line, info type, stateset type, gaugehistogram type. // // - The size of exemplar labels is not checked (i.e. it's possible to create // exemplars that are larger than allowed by the OpenMetrics specification). // // - The value of Counters is not checked. (OpenMetrics doesn't allow counters // with a `NaN` value.) -func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...EncoderOption) (written int, err error) { - toOM := encoderOption{} - for _, option := range options { - option(&toOM) - } - +func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) { name := in.GetName() if name == "" { return 0, fmt.Errorf("MetricFamily has no name: %s", in) @@ -145,15 +95,12 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E } var ( - n int - metricType = in.GetType() - compliantName = name + n int + metricType = in.GetType() + shortName = name ) - if metricType == dto.MetricType_COUNTER && strings.HasSuffix(compliantName, "_total") { - compliantName = name[:len(name)-6] - } - if toOM.withUnit && in.Unit != nil && !strings.HasSuffix(compliantName, fmt.Sprintf("_%s", *in.Unit)) { - compliantName = compliantName + fmt.Sprintf("_%s", *in.Unit) + if metricType == dto.MetricType_COUNTER && strings.HasSuffix(shortName, "_total") { + shortName = name[:len(name)-6] } // Comments, first HELP, then TYPE. @@ -163,7 +110,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E if err != nil { return } - n, err = writeName(w, compliantName) + n, err = writeName(w, shortName) written += n if err != nil { return @@ -189,7 +136,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E if err != nil { return } - n, err = writeName(w, compliantName) + n, err = writeName(w, shortName) written += n if err != nil { return @@ -216,89 +163,55 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E if err != nil { return } - if toOM.withUnit && in.Unit != nil { - n, err = w.WriteString("# UNIT ") - written += n - if err != nil { - return - } - n, err = writeName(w, compliantName) - written += n - if err != nil { - return - } - - err = w.WriteByte(' ') - written++ - if err != nil { - return - } - n, err = writeEscapedString(w, *in.Unit, true) - written += n - if err != nil { - return - } - err = w.WriteByte('\n') - written++ - if err != nil { - return - } - } - - var createdTsBytesWritten int // Finally the samples, one line for each. - if metricType == dto.MetricType_COUNTER && strings.HasSuffix(name, "_total") { - compliantName = compliantName + "_total" - } for _, metric := range in.Metric { switch metricType { case dto.MetricType_COUNTER: if metric.Counter == nil { return written, fmt.Errorf( - "expected counter in metric %s %s", compliantName, metric, + "expected counter in metric %s %s", name, metric, ) } + // Note that we have ensured above that either the name + // ends on `_total` or that the rendered type is + // `unknown`. Therefore, no `_total` must be added here. n, err = writeOpenMetricsSample( - w, compliantName, "", metric, "", 0, + w, name, "", metric, "", 0, metric.Counter.GetValue(), 0, false, metric.Counter.Exemplar, ) - if toOM.withCreatedLines && metric.Counter.CreatedTimestamp != nil { - createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "_total", metric, "", 0, metric.Counter.GetCreatedTimestamp()) - n += createdTsBytesWritten - } case dto.MetricType_GAUGE: if metric.Gauge == nil { return written, fmt.Errorf( - "expected gauge in metric %s %s", compliantName, metric, + "expected gauge in metric %s %s", name, metric, ) } n, err = writeOpenMetricsSample( - w, compliantName, "", metric, "", 0, + w, name, "", metric, "", 0, metric.Gauge.GetValue(), 0, false, nil, ) case dto.MetricType_UNTYPED: if metric.Untyped == nil { return written, fmt.Errorf( - "expected untyped in metric %s %s", compliantName, metric, + "expected untyped in metric %s %s", name, metric, ) } n, err = writeOpenMetricsSample( - w, compliantName, "", metric, "", 0, + w, name, "", metric, "", 0, metric.Untyped.GetValue(), 0, false, nil, ) case dto.MetricType_SUMMARY: if metric.Summary == nil { return written, fmt.Errorf( - "expected summary in metric %s %s", compliantName, metric, + "expected summary in metric %s %s", name, metric, ) } for _, q := range metric.Summary.Quantile { n, err = writeOpenMetricsSample( - w, compliantName, "", metric, + w, name, "", metric, model.QuantileLabel, q.GetQuantile(), q.GetValue(), 0, false, nil, @@ -309,7 +222,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E } } n, err = writeOpenMetricsSample( - w, compliantName, "_sum", metric, "", 0, + w, name, "_sum", metric, "", 0, metric.Summary.GetSampleSum(), 0, false, nil, ) @@ -318,24 +231,20 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E return } n, err = writeOpenMetricsSample( - w, compliantName, "_count", metric, "", 0, + w, name, "_count", metric, "", 0, 0, metric.Summary.GetSampleCount(), true, nil, ) - if toOM.withCreatedLines && metric.Summary.CreatedTimestamp != nil { - createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Summary.GetCreatedTimestamp()) - n += createdTsBytesWritten - } case dto.MetricType_HISTOGRAM: if metric.Histogram == nil { return written, fmt.Errorf( - "expected histogram in metric %s %s", compliantName, metric, + "expected histogram in metric %s %s", name, metric, ) } infSeen := false for _, b := range metric.Histogram.Bucket { n, err = writeOpenMetricsSample( - w, compliantName, "_bucket", metric, + w, name, "_bucket", metric, model.BucketLabel, b.GetUpperBound(), 0, b.GetCumulativeCount(), true, b.Exemplar, @@ -350,7 +259,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E } if !infSeen { n, err = writeOpenMetricsSample( - w, compliantName, "_bucket", metric, + w, name, "_bucket", metric, model.BucketLabel, math.Inf(+1), 0, metric.Histogram.GetSampleCount(), true, nil, @@ -361,7 +270,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E } } n, err = writeOpenMetricsSample( - w, compliantName, "_sum", metric, "", 0, + w, name, "_sum", metric, "", 0, metric.Histogram.GetSampleSum(), 0, false, nil, ) @@ -370,17 +279,13 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E return } n, err = writeOpenMetricsSample( - w, compliantName, "_count", metric, "", 0, + w, name, "_count", metric, "", 0, 0, metric.Histogram.GetSampleCount(), true, nil, ) - if toOM.withCreatedLines && metric.Histogram.CreatedTimestamp != nil { - createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Histogram.GetCreatedTimestamp()) - n += createdTsBytesWritten - } default: return written, fmt.Errorf( - "unexpected type in metric %s %s", compliantName, metric, + "unexpected type in metric %s %s", name, metric, ) } written += n @@ -445,7 +350,7 @@ func writeOpenMetricsSample( return written, err } } - if exemplar != nil && len(exemplar.Label) > 0 { + if exemplar != nil { n, err = writeExemplar(w, exemplar) written += n if err != nil { @@ -568,49 +473,6 @@ func writeOpenMetricsNameAndLabelPairs( return written, nil } -// writeOpenMetricsCreated writes the created timestamp for a single time series -// following OpenMetrics text format to w, given the metric name, the metric proto -// message itself, optionally a suffix to be removed, e.g. '_total' for counters, -// an additional label name with a float64 value (use empty string as label name if -// not required) and the timestamp that represents the created timestamp. -// The function returns the number of bytes written and any error encountered. -func writeOpenMetricsCreated(w enhancedWriter, - name, suffixToTrim string, metric *dto.Metric, - additionalLabelName string, additionalLabelValue float64, - createdTimestamp *timestamppb.Timestamp, -) (int, error) { - written := 0 - n, err := writeOpenMetricsNameAndLabelPairs( - w, strings.TrimSuffix(name, suffixToTrim)+"_created", metric.Label, additionalLabelName, additionalLabelValue, - ) - written += n - if err != nil { - return written, err - } - - err = w.WriteByte(' ') - written++ - if err != nil { - return written, err - } - - // TODO(beorn7): Format this directly from components of ts to - // avoid overflow/underflow and precision issues of the float - // conversion. - n, err = writeOpenMetricsFloat(w, float64(createdTimestamp.AsTime().UnixNano())/1e9) - written += n - if err != nil { - return written, err - } - - err = w.WriteByte('\n') - written++ - if err != nil { - return written, err - } - return written, nil -} - // writeExemplar writes the provided exemplar in OpenMetrics format to w. The // function returns the number of bytes written and any error encountered. func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) { diff --git a/vendor/github.com/munnerz/goautoneg/README.txt b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt similarity index 100% rename from vendor/github.com/munnerz/goautoneg/README.txt rename to vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt diff --git a/vendor/github.com/munnerz/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go similarity index 52% rename from vendor/github.com/munnerz/goautoneg/autoneg.go rename to vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go index 1dd1cad6..a21b9d15 100644 --- a/vendor/github.com/munnerz/goautoneg/autoneg.go +++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go @@ -1,28 +1,28 @@ /* +Copyright (c) 2011, Open Knowledge Foundation Ltd. +All rights reserved. + HTTP Content-Type Autonegotiation. The functions in this package implement the behaviour specified in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html -Copyright (c) 2011, Open Knowledge Foundation Ltd. -All rights reserved. - 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 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. + 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. - Neither the name of the Open Knowledge Foundation Ltd. nor the - names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. + Neither the name of the Open Knowledge Foundation Ltd. nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -36,7 +36,6 @@ 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. */ - package goautoneg import ( @@ -52,14 +51,16 @@ type Accept struct { Params map[string]string } -// acceptSlice is defined to implement sort interface. -type acceptSlice []Accept +// For internal use, so that we can use the sort interface +type accept_slice []Accept -func (slice acceptSlice) Len() int { +func (accept accept_slice) Len() int { + slice := []Accept(accept) return len(slice) } -func (slice acceptSlice) Less(i, j int) bool { +func (accept accept_slice) Less(i, j int) bool { + slice := []Accept(accept) ai, aj := slice[i], slice[j] if ai.Q > aj.Q { return true @@ -73,93 +74,63 @@ func (slice acceptSlice) Less(i, j int) bool { return false } -func (slice acceptSlice) Swap(i, j int) { +func (accept accept_slice) Swap(i, j int) { + slice := []Accept(accept) slice[i], slice[j] = slice[j], slice[i] } -func stringTrimSpaceCutset(r rune) bool { - return r == ' ' -} - -func nextSplitElement(s, sep string) (item string, remaining string) { - if index := strings.Index(s, sep); index != -1 { - return s[:index], s[index+1:] - } - return s, "" -} - // Parse an Accept Header string returning a sorted list // of clauses -func ParseAccept(header string) acceptSlice { - partsCount := 0 - remaining := header - for len(remaining) > 0 { - partsCount++ - _, remaining = nextSplitElement(remaining, ",") - } - accept := make(acceptSlice, 0, partsCount) - - remaining = header - var part string - for len(remaining) > 0 { - part, remaining = nextSplitElement(remaining, ",") - part = strings.TrimFunc(part, stringTrimSpaceCutset) +func ParseAccept(header string) (accept []Accept) { + parts := strings.Split(header, ",") + accept = make([]Accept, 0, len(parts)) + for _, part := range parts { + part := strings.Trim(part, " ") - a := Accept{ - Q: 1.0, - } + a := Accept{} + a.Params = make(map[string]string) + a.Q = 1.0 - sp, remainingPart := nextSplitElement(part, ";") + mrp := strings.Split(part, ";") - sp0, spRemaining := nextSplitElement(sp, "/") - a.Type = strings.TrimFunc(sp0, stringTrimSpaceCutset) + media_range := mrp[0] + sp := strings.Split(media_range, "/") + a.Type = strings.Trim(sp[0], " ") switch { - case len(spRemaining) == 0: - if a.Type == "*" { - a.SubType = "*" - } else { - continue - } + case len(sp) == 1 && a.Type == "*": + a.SubType = "*" + case len(sp) == 2: + a.SubType = strings.Trim(sp[1], " ") default: - var sp1 string - sp1, spRemaining = nextSplitElement(spRemaining, "/") - if len(spRemaining) > 0 { - continue - } - a.SubType = strings.TrimFunc(sp1, stringTrimSpaceCutset) + continue } - if len(remainingPart) == 0 { + if len(mrp) == 1 { accept = append(accept, a) continue } - a.Params = make(map[string]string) - for len(remainingPart) > 0 { - sp, remainingPart = nextSplitElement(remainingPart, ";") - sp0, spRemaining = nextSplitElement(sp, "=") - if len(spRemaining) == 0 { - continue - } - var sp1 string - sp1, spRemaining = nextSplitElement(spRemaining, "=") - if len(spRemaining) != 0 { + for _, param := range mrp[1:] { + sp := strings.SplitN(param, "=", 2) + if len(sp) != 2 { continue } - token := strings.TrimFunc(sp0, stringTrimSpaceCutset) + token := strings.Trim(sp[0], " ") if token == "q" { - a.Q, _ = strconv.ParseFloat(sp1, 32) + a.Q, _ = strconv.ParseFloat(sp[1], 32) } else { - a.Params[token] = strings.TrimFunc(sp1, stringTrimSpaceCutset) + a.Params[token] = strings.Trim(sp[1], " ") } } accept = append(accept, a) } - sort.Sort(accept) - return accept + slice := accept_slice(accept) + sort.Sort(slice) + + return } // Negotiate the most appropriate content_type given the accept header diff --git a/vendor/github.com/prometheus/common/model/alert.go b/vendor/github.com/prometheus/common/model/alert.go index 80d1fe94..178fdbaf 100644 --- a/vendor/github.com/prometheus/common/model/alert.go +++ b/vendor/github.com/prometheus/common/model/alert.go @@ -75,12 +75,7 @@ func (a *Alert) ResolvedAt(ts time.Time) bool { // Status returns the status of the alert. func (a *Alert) Status() AlertStatus { - return a.StatusAt(time.Now()) -} - -// StatusAt returns the status of the alert at the given timestamp. -func (a *Alert) StatusAt(ts time.Time) AlertStatus { - if a.ResolvedAt(ts) { + if a.Resolved() { return AlertResolved } return AlertFiring @@ -132,17 +127,6 @@ func (as Alerts) HasFiring() bool { return false } -// HasFiringAt returns true iff one of the alerts is not resolved -// at the time ts. -func (as Alerts) HasFiringAt(ts time.Time) bool { - for _, a := range as { - if !a.ResolvedAt(ts) { - return true - } - } - return false -} - // Status returns StatusFiring iff at least one of the alerts is firing. func (as Alerts) Status() AlertStatus { if as.HasFiring() { @@ -150,12 +134,3 @@ func (as Alerts) Status() AlertStatus { } return AlertResolved } - -// StatusAt returns StatusFiring iff at least one of the alerts is firing -// at the time ts. -func (as Alerts) StatusAt(ts time.Time) AlertStatus { - if as.HasFiringAt(ts) { - return AlertFiring - } - return AlertResolved -} diff --git a/vendor/github.com/prometheus/common/model/labelset.go b/vendor/github.com/prometheus/common/model/labelset.go index d0ad88da..6eda08a7 100644 --- a/vendor/github.com/prometheus/common/model/labelset.go +++ b/vendor/github.com/prometheus/common/model/labelset.go @@ -17,6 +17,7 @@ import ( "encoding/json" "fmt" "sort" + "strings" ) // A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet @@ -128,6 +129,16 @@ func (l LabelSet) Merge(other LabelSet) LabelSet { return result } +func (l LabelSet) String() string { + lstrs := make([]string, 0, len(l)) + for l, v := range l { + lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v)) + } + + sort.Strings(lstrs) + return fmt.Sprintf("{%s}", strings.Join(lstrs, ", ")) +} + // Fingerprint returns the LabelSet's fingerprint. func (ls LabelSet) Fingerprint() Fingerprint { return labelSetToFingerprint(ls) diff --git a/vendor/github.com/prometheus/common/model/labelset_string.go b/vendor/github.com/prometheus/common/model/labelset_string.go deleted file mode 100644 index 481c47b4..00000000 --- a/vendor/github.com/prometheus/common/model/labelset_string.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build go1.21 - -package model - -import ( - "bytes" - "slices" - "strconv" -) - -// String will look like `{foo="bar", more="less"}`. Names are sorted alphabetically. -func (l LabelSet) String() string { - var lna [32]string // On stack to avoid memory allocation for sorting names. - labelNames := lna[:0] - for name := range l { - labelNames = append(labelNames, string(name)) - } - slices.Sort(labelNames) - var bytea [1024]byte // On stack to avoid memory allocation while building the output. - b := bytes.NewBuffer(bytea[:0]) - b.WriteByte('{') - for i, name := range labelNames { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(name) - b.WriteByte('=') - b.Write(strconv.AppendQuote(b.AvailableBuffer(), string(l[LabelName(name)]))) - } - b.WriteByte('}') - return b.String() -} diff --git a/vendor/github.com/prometheus/common/model/labelset_string_go120.go b/vendor/github.com/prometheus/common/model/labelset_string_go120.go deleted file mode 100644 index c4212685..00000000 --- a/vendor/github.com/prometheus/common/model/labelset_string_go120.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !go1.21 - -package model - -import ( - "fmt" - "sort" - "strings" -) - -// String was optimized using functions not available for go 1.20 -// or lower. We keep the old implementation for compatibility with client_golang. -// Once client golang drops support for go 1.20 (scheduled for August 2024), this -// file can be removed. -func (l LabelSet) String() string { - labelNames := make([]string, 0, len(l)) - for name := range l { - labelNames = append(labelNames, string(name)) - } - sort.Strings(labelNames) - lstrs := make([]string, 0, len(l)) - for _, name := range labelNames { - lstrs = append(lstrs, fmt.Sprintf("%s=%q", name, l[LabelName(name)])) - } - return fmt.Sprintf("{%s}", strings.Join(lstrs, ", ")) -} diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go index eb865e5a..0bd29b3a 100644 --- a/vendor/github.com/prometheus/common/model/metric.go +++ b/vendor/github.com/prometheus/common/model/metric.go @@ -204,7 +204,6 @@ func EscapeMetricFamily(v *dto.MetricFamily, scheme EscapingScheme) *dto.MetricF out := &dto.MetricFamily{ Help: v.Help, Type: v.Type, - Unit: v.Unit, } // If the name is nil, copy as-is, don't try to escape. diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml index 126df9e6..c24864a9 100644 --- a/vendor/github.com/prometheus/procfs/.golangci.yml +++ b/vendor/github.com/prometheus/procfs/.golangci.yml @@ -1,16 +1,9 @@ --- linters: enable: - - errcheck - godot - - gosimple - - govet - - ineffassign - misspell - revive - - staticcheck - - testifylint - - unused linter-settings: godot: diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md index e00f3b36..56ba67d3 100644 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md @@ -1,3 +1,2 @@ * Johannes 'fish' Ziemke @discordianfish -* Paul Gier @pgier -* Ben Kochie @SuperQ +* Paul Gier @pgier diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common index 16172923..062a2818 100644 --- a/vendor/github.com/prometheus/procfs/Makefile.common +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -49,23 +49,23 @@ endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) -ifneq ($(shell command -v gotestsum 2> /dev/null),) +ifneq ($(shell command -v gotestsum > /dev/null),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif endif -PROMU_VERSION ?= 0.17.0 +PROMU_VERSION ?= 0.15.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.59.0 -# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. +GOLANGCI_LINT_VERSION ?= v1.54.2 +# golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) - ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386 arm64)) + ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) # If we're in CI and there is an Actions file, that means the linter # is being run in Actions, so we don't need to run it here. ifneq (,$(SKIP_GOLANGCI_LINT)) @@ -169,20 +169,16 @@ common-vet: common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" +# 'go list' needs to be executed before staticcheck to prepopulate the modules cache. +# Otherwise staticcheck might fail randomly for some reason not yet explained. + $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) endif -.PHONY: common-lint-fix -common-lint-fix: $(GOLANGCI_LINT) -ifdef GOLANGCI_LINT - @echo ">> running golangci-lint fix" - $(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_OPTS) $(pkgs) -endif - .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" -ifeq (, $(shell command -v yamllint 2> /dev/null)) +ifeq (, $(shell command -v yamllint > /dev/null)) @echo "yamllint not installed so skipping" else yamllint . @@ -208,10 +204,6 @@ common-tarball: promu @echo ">> building release tarball" $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) -.PHONY: common-docker-repo-name -common-docker-repo-name: - @echo "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" - .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: diff --git a/vendor/github.com/prometheus/procfs/arp.go b/vendor/github.com/prometheus/procfs/arp.go index cdcc8a7c..28783e2d 100644 --- a/vendor/github.com/prometheus/procfs/arp.go +++ b/vendor/github.com/prometheus/procfs/arp.go @@ -55,7 +55,7 @@ type ARPEntry struct { func (fs FS) GatherARPEntries() ([]ARPEntry, error) { data, err := os.ReadFile(fs.proc.Path("net/arp")) if err != nil { - return nil, fmt.Errorf("%w: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err) + return nil, fmt.Errorf("%s: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err) } return parseARPEntries(data) @@ -78,11 +78,11 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) { } else if width == expectedDataWidth { entry, err := parseARPEntry(columns) if err != nil { - return []ARPEntry{}, fmt.Errorf("%w: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err) + return []ARPEntry{}, fmt.Errorf("%s: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err) } entries = append(entries, entry) } else { - return []ARPEntry{}, fmt.Errorf("%w: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err) + return []ARPEntry{}, fmt.Errorf("%s: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err) } } diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go index 83807500..4a173636 100644 --- a/vendor/github.com/prometheus/procfs/buddyinfo.go +++ b/vendor/github.com/prometheus/procfs/buddyinfo.go @@ -58,8 +58,8 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { return nil, fmt.Errorf("%w: Invalid number of fields, found: %v", ErrFileParse, parts) } - node := strings.TrimSuffix(parts[1], ",") - zone := strings.TrimSuffix(parts[3], ",") + node := strings.TrimRight(parts[1], ",") + zone := strings.TrimRight(parts[3], ",") arraySize := len(parts[4:]) if bucketCount == -1 { @@ -74,7 +74,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { for i := 0; i < arraySize; i++ { sizes[i], err = strconv.ParseFloat(parts[i+4], 64) if err != nil { - return nil, fmt.Errorf("%w: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err) + return nil, fmt.Errorf("%s: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err) } } diff --git a/vendor/github.com/prometheus/procfs/cpuinfo.go b/vendor/github.com/prometheus/procfs/cpuinfo.go index f0950bb4..f4f5501c 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo.go @@ -194,7 +194,7 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) { firstLine := firstNonEmptyLine(scanner) match, err := regexp.MatchString("^[Pp]rocessor", firstLine) if !match || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("%w: Cannot parse line: %q: %w", ErrFileParse, firstLine, err) + return nil, fmt.Errorf("%s: Cannot parse line: %q: %w", ErrFileParse, firstLine, err) } field := strings.SplitN(firstLine, ": ", 2) @@ -386,7 +386,7 @@ func parseCPUInfoLoong(info []byte) ([]CPUInfo, error) { // find the first "processor" line firstLine := firstNonEmptyLine(scanner) if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine) + return nil, errors.New("invalid cpuinfo file: " + firstLine) } field := strings.SplitN(firstLine, ": ", 2) cpuinfo := []CPUInfo{} diff --git a/vendor/github.com/prometheus/procfs/crypto.go b/vendor/github.com/prometheus/procfs/crypto.go index 5f2a37a7..9a73e263 100644 --- a/vendor/github.com/prometheus/procfs/crypto.go +++ b/vendor/github.com/prometheus/procfs/crypto.go @@ -55,13 +55,13 @@ func (fs FS) Crypto() ([]Crypto, error) { path := fs.proc.Path("crypto") b, err := util.ReadFileNoStat(path) if err != nil { - return nil, fmt.Errorf("%w: Cannot read file %v: %w", ErrFileRead, b, err) + return nil, fmt.Errorf("%s: Cannot read file %v: %w", ErrFileRead, b, err) } crypto, err := parseCrypto(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse %v: %w", ErrFileParse, crypto, err) + return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, crypto, err) } return crypto, nil @@ -84,7 +84,7 @@ func parseCrypto(r io.Reader) ([]Crypto, error) { kv := strings.Split(text, ":") if len(kv) != 2 { - return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, text) + return nil, fmt.Errorf("%w: Cannot parae line: %q", ErrFileParse, text) } k := strings.TrimSpace(kv[0]) diff --git a/vendor/github.com/prometheus/procfs/fscache.go b/vendor/github.com/prometheus/procfs/fscache.go index cf2e3eaa..f560a8db 100644 --- a/vendor/github.com/prometheus/procfs/fscache.go +++ b/vendor/github.com/prometheus/procfs/fscache.go @@ -236,7 +236,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) { m, err := parseFscacheinfo(bytes.NewReader(b)) if err != nil { - return Fscacheinfo{}, fmt.Errorf("%w: Cannot parse %v: %w", ErrFileParse, m, err) + return Fscacheinfo{}, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, m, err) } return *m, nil @@ -245,7 +245,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) { func setFSCacheFields(fields []string, setFields ...*uint64) error { var err error if len(fields) < len(setFields) { - return fmt.Errorf("%w: Expected %d, but got %d: %w", ErrFileParse, len(setFields), len(fields), err) + return fmt.Errorf("%s: Expected %d, but got %d: %w", ErrFileParse, len(setFields), len(fields), err) } for i := range setFields { diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index bc3a20c9..5a145bbf 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -221,16 +221,16 @@ func parseIPPort(s string) (net.IP, uint16, error) { case 46: ip = net.ParseIP(s[1:40]) if ip == nil { - return nil, 0, fmt.Errorf("%w: Invalid IPv6 addr %s: %w", ErrFileParse, s[1:40], err) + return nil, 0, fmt.Errorf("%s: Invalid IPv6 addr %s: %w", ErrFileParse, s[1:40], err) } default: - return nil, 0, fmt.Errorf("%w: Unexpected IP:Port %s: %w", ErrFileParse, s, err) + return nil, 0, fmt.Errorf("%s: Unexpected IP:Port %s: %w", ErrFileParse, s, err) } portString := s[len(s)-4:] if len(portString) != 4 { return nil, 0, - fmt.Errorf("%w: Unexpected port string format %s: %w", ErrFileParse, portString, err) + fmt.Errorf("%s: Unexpected port string format %s: %w", ErrFileParse, portString, err) } port, err := strconv.ParseUint(portString, 16, 16) if err != nil { diff --git a/vendor/github.com/prometheus/procfs/loadavg.go b/vendor/github.com/prometheus/procfs/loadavg.go index 332e76c1..59465c5b 100644 --- a/vendor/github.com/prometheus/procfs/loadavg.go +++ b/vendor/github.com/prometheus/procfs/loadavg.go @@ -51,7 +51,7 @@ func parseLoad(loadavgBytes []byte) (*LoadAvg, error) { for i, load := range parts[0:3] { loads[i], err = strconv.ParseFloat(load, 64) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse load: %f: %w", ErrFileParse, loads[i], err) + return nil, fmt.Errorf("%s: Cannot parse load: %f: %w", ErrFileParse, loads[i], err) } } return &LoadAvg{ diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go index 67a9d2b4..fdd4b954 100644 --- a/vendor/github.com/prometheus/procfs/mdstat.go +++ b/vendor/github.com/prometheus/procfs/mdstat.go @@ -23,7 +23,7 @@ import ( var ( statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[([U_]+)\]`) - recoveryLineBlocksRE = regexp.MustCompile(`\((\d+/\d+)\)`) + recoveryLineBlocksRE = regexp.MustCompile(`\((\d+)/\d+\)`) recoveryLinePctRE = regexp.MustCompile(`= (.+)%`) recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`) recoveryLineSpeedRE = regexp.MustCompile(`speed=(.+)[A-Z]`) @@ -50,8 +50,6 @@ type MDStat struct { BlocksTotal int64 // Number of blocks on the device that are in sync. BlocksSynced int64 - // Number of blocks on the device that need to be synced. - BlocksToBeSynced int64 // progress percentage of current sync BlocksSyncedPct float64 // estimated finishing time for current sync (in minutes) @@ -72,7 +70,7 @@ func (fs FS) MDStat() ([]MDStat, error) { } mdstat, err := parseMDStat(data) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse %v: %w", ErrFileParse, fs.proc.Path("mdstat"), err) + return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, fs.proc.Path("mdstat"), err) } return mdstat, nil } @@ -92,7 +90,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { deviceFields := strings.Fields(line) if len(deviceFields) < 3 { - return nil, fmt.Errorf("%w: Expected 3+ lines, got %q", ErrFileParse, line) + return nil, fmt.Errorf("%s: Expected 3+ lines, got %q", ErrFileParse, line) } mdName := deviceFields[0] // mdx state := deviceFields[2] // active or inactive @@ -107,7 +105,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { active, total, down, size, err := evalStatusLine(lines[i], lines[i+1]) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse md device lines: %v: %w", ErrFileParse, active, err) + return nil, fmt.Errorf("%s: Cannot parse md device lines: %v: %w", ErrFileParse, active, err) } syncLineIdx := i + 2 @@ -117,8 +115,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { // If device is syncing at the moment, get the number of currently // synced bytes, otherwise that number equals the size of the device. - blocksSynced := size - blocksToBeSynced := size + syncedBlocks := size speed := float64(0) finish := float64(0) pct := float64(0) @@ -139,11 +136,11 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { // Handle case when resync=PENDING or resync=DELAYED. if strings.Contains(lines[syncLineIdx], "PENDING") || strings.Contains(lines[syncLineIdx], "DELAYED") { - blocksSynced = 0 + syncedBlocks = 0 } else { - blocksSynced, blocksToBeSynced, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx]) + syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx]) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err) + return nil, fmt.Errorf("%s: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err) } } } @@ -157,8 +154,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { DisksSpare: spare, DisksTotal: total, BlocksTotal: size, - BlocksSynced: blocksSynced, - BlocksToBeSynced: blocksToBeSynced, + BlocksSynced: syncedBlocks, BlocksSyncedPct: pct, BlocksSyncedFinishTime: finish, BlocksSyncedSpeed: speed, @@ -172,13 +168,13 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) { statusFields := strings.Fields(statusLine) if len(statusFields) < 1 { - return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) } sizeStr := statusFields[0] size, err = strconv.ParseInt(sizeStr, 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) } if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") { @@ -193,71 +189,65 @@ func evalStatusLine(deviceLine, statusLine string) (active, total, down, size in matches := statusLineRE.FindStringSubmatch(statusLine) if len(matches) != 5 { - return 0, 0, 0, 0, fmt.Errorf("%w: Could not fild all substring matches %s: %w", ErrFileParse, statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Could not fild all substring matches %s: %w", ErrFileParse, statusLine, err) } total, err = strconv.ParseInt(matches[2], 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) } active, err = strconv.ParseInt(matches[3], 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected active %d: %w", ErrFileParse, active, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected active %d: %w", ErrFileParse, active, err) } down = int64(strings.Count(matches[4], "_")) return active, total, down, size, nil } -func evalRecoveryLine(recoveryLine string) (blocksSynced int64, blocksToBeSynced int64, pct float64, finish float64, speed float64, err error) { +func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) { matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine blocks %s: %w", ErrFileParse, recoveryLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected recoveryLine %s: %w", ErrFileParse, recoveryLine, err) } - blocks := strings.Split(matches[1], "/") - blocksSynced, err = strconv.ParseInt(blocks[0], 10, 64) + syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64) if err != nil { - return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery blocks synced %q: %w", ErrFileParse, matches[1], err) - } - - blocksToBeSynced, err = strconv.ParseInt(blocks[1], 10, 64) - if err != nil { - return blocksSynced, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery to be synced blocks %q: %w", ErrFileParse, matches[2], err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected parsing of recoveryLine %q: %w", ErrFileParse, recoveryLine, err) } // Get percentage complete matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine) + return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine) } pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64) if err != nil { - return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine) + return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine) } // Get time expected left to complete matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine) + return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine) } finish, err = strconv.ParseFloat(matches[1], 64) if err != nil { - return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine) + return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine) } // Get recovery speed matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine) + return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine) } speed, err = strconv.ParseFloat(matches[1], 64) if err != nil { - return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err) + return syncedBlocks, pct, finish, 0, fmt.Errorf("%s: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err) } - return blocksSynced, blocksToBeSynced, pct, finish, speed, nil + return syncedBlocks, pct, finish, speed, nil } func evalComponentDevices(deviceFields []string) []string { diff --git a/vendor/github.com/prometheus/procfs/meminfo.go b/vendor/github.com/prometheus/procfs/meminfo.go index 4b2c4050..eaf00e22 100644 --- a/vendor/github.com/prometheus/procfs/meminfo.go +++ b/vendor/github.com/prometheus/procfs/meminfo.go @@ -126,7 +126,6 @@ type Meminfo struct { VmallocUsed *uint64 // largest contiguous block of vmalloc area which is free VmallocChunk *uint64 - Percpu *uint64 HardwareCorrupted *uint64 AnonHugePages *uint64 ShmemHugePages *uint64 @@ -141,55 +140,6 @@ type Meminfo struct { DirectMap4k *uint64 DirectMap2M *uint64 DirectMap1G *uint64 - - // The struct fields below are the byte-normalized counterparts to the - // existing struct fields. Values are normalized using the optional - // unit field in the meminfo line. - MemTotalBytes *uint64 - MemFreeBytes *uint64 - MemAvailableBytes *uint64 - BuffersBytes *uint64 - CachedBytes *uint64 - SwapCachedBytes *uint64 - ActiveBytes *uint64 - InactiveBytes *uint64 - ActiveAnonBytes *uint64 - InactiveAnonBytes *uint64 - ActiveFileBytes *uint64 - InactiveFileBytes *uint64 - UnevictableBytes *uint64 - MlockedBytes *uint64 - SwapTotalBytes *uint64 - SwapFreeBytes *uint64 - DirtyBytes *uint64 - WritebackBytes *uint64 - AnonPagesBytes *uint64 - MappedBytes *uint64 - ShmemBytes *uint64 - SlabBytes *uint64 - SReclaimableBytes *uint64 - SUnreclaimBytes *uint64 - KernelStackBytes *uint64 - PageTablesBytes *uint64 - NFSUnstableBytes *uint64 - BounceBytes *uint64 - WritebackTmpBytes *uint64 - CommitLimitBytes *uint64 - CommittedASBytes *uint64 - VmallocTotalBytes *uint64 - VmallocUsedBytes *uint64 - VmallocChunkBytes *uint64 - PercpuBytes *uint64 - HardwareCorruptedBytes *uint64 - AnonHugePagesBytes *uint64 - ShmemHugePagesBytes *uint64 - ShmemPmdMappedBytes *uint64 - CmaTotalBytes *uint64 - CmaFreeBytes *uint64 - HugepagesizeBytes *uint64 - DirectMap4kBytes *uint64 - DirectMap2MBytes *uint64 - DirectMap1GBytes *uint64 } // Meminfo returns an information about current kernel/system memory statistics. @@ -202,7 +152,7 @@ func (fs FS) Meminfo() (Meminfo, error) { m, err := parseMemInfo(bytes.NewReader(b)) if err != nil { - return Meminfo{}, fmt.Errorf("%w: %w", ErrFileParse, err) + return Meminfo{}, fmt.Errorf("%s: %w", ErrFileParse, err) } return *m, nil @@ -212,176 +162,114 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) { var m Meminfo s := bufio.NewScanner(r) for s.Scan() { + // Each line has at least a name and value; we ignore the unit. fields := strings.Fields(s.Text()) - var val, valBytes uint64 + if len(fields) < 2 { + return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text()) + } - val, err := strconv.ParseUint(fields[1], 0, 64) + v, err := strconv.ParseUint(fields[1], 0, 64) if err != nil { return nil, err } - switch len(fields) { - case 2: - // No unit present, use the parsed the value as bytes directly. - valBytes = val - case 3: - // Unit present in optional 3rd field, convert it to - // bytes. The only unit supported within the Linux - // kernel is `kB`. - if fields[2] != "kB" { - return nil, fmt.Errorf("%w: Unsupported unit in optional 3rd field %q", ErrFileParse, fields[2]) - } - - valBytes = 1024 * val - - default: - return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text()) - } - switch fields[0] { case "MemTotal:": - m.MemTotal = &val - m.MemTotalBytes = &valBytes + m.MemTotal = &v case "MemFree:": - m.MemFree = &val - m.MemFreeBytes = &valBytes + m.MemFree = &v case "MemAvailable:": - m.MemAvailable = &val - m.MemAvailableBytes = &valBytes + m.MemAvailable = &v case "Buffers:": - m.Buffers = &val - m.BuffersBytes = &valBytes + m.Buffers = &v case "Cached:": - m.Cached = &val - m.CachedBytes = &valBytes + m.Cached = &v case "SwapCached:": - m.SwapCached = &val - m.SwapCachedBytes = &valBytes + m.SwapCached = &v case "Active:": - m.Active = &val - m.ActiveBytes = &valBytes + m.Active = &v case "Inactive:": - m.Inactive = &val - m.InactiveBytes = &valBytes + m.Inactive = &v case "Active(anon):": - m.ActiveAnon = &val - m.ActiveAnonBytes = &valBytes + m.ActiveAnon = &v case "Inactive(anon):": - m.InactiveAnon = &val - m.InactiveAnonBytes = &valBytes + m.InactiveAnon = &v case "Active(file):": - m.ActiveFile = &val - m.ActiveFileBytes = &valBytes + m.ActiveFile = &v case "Inactive(file):": - m.InactiveFile = &val - m.InactiveFileBytes = &valBytes + m.InactiveFile = &v case "Unevictable:": - m.Unevictable = &val - m.UnevictableBytes = &valBytes + m.Unevictable = &v case "Mlocked:": - m.Mlocked = &val - m.MlockedBytes = &valBytes + m.Mlocked = &v case "SwapTotal:": - m.SwapTotal = &val - m.SwapTotalBytes = &valBytes + m.SwapTotal = &v case "SwapFree:": - m.SwapFree = &val - m.SwapFreeBytes = &valBytes + m.SwapFree = &v case "Dirty:": - m.Dirty = &val - m.DirtyBytes = &valBytes + m.Dirty = &v case "Writeback:": - m.Writeback = &val - m.WritebackBytes = &valBytes + m.Writeback = &v case "AnonPages:": - m.AnonPages = &val - m.AnonPagesBytes = &valBytes + m.AnonPages = &v case "Mapped:": - m.Mapped = &val - m.MappedBytes = &valBytes + m.Mapped = &v case "Shmem:": - m.Shmem = &val - m.ShmemBytes = &valBytes + m.Shmem = &v case "Slab:": - m.Slab = &val - m.SlabBytes = &valBytes + m.Slab = &v case "SReclaimable:": - m.SReclaimable = &val - m.SReclaimableBytes = &valBytes + m.SReclaimable = &v case "SUnreclaim:": - m.SUnreclaim = &val - m.SUnreclaimBytes = &valBytes + m.SUnreclaim = &v case "KernelStack:": - m.KernelStack = &val - m.KernelStackBytes = &valBytes + m.KernelStack = &v case "PageTables:": - m.PageTables = &val - m.PageTablesBytes = &valBytes + m.PageTables = &v case "NFS_Unstable:": - m.NFSUnstable = &val - m.NFSUnstableBytes = &valBytes + m.NFSUnstable = &v case "Bounce:": - m.Bounce = &val - m.BounceBytes = &valBytes + m.Bounce = &v case "WritebackTmp:": - m.WritebackTmp = &val - m.WritebackTmpBytes = &valBytes + m.WritebackTmp = &v case "CommitLimit:": - m.CommitLimit = &val - m.CommitLimitBytes = &valBytes + m.CommitLimit = &v case "Committed_AS:": - m.CommittedAS = &val - m.CommittedASBytes = &valBytes + m.CommittedAS = &v case "VmallocTotal:": - m.VmallocTotal = &val - m.VmallocTotalBytes = &valBytes + m.VmallocTotal = &v case "VmallocUsed:": - m.VmallocUsed = &val - m.VmallocUsedBytes = &valBytes + m.VmallocUsed = &v case "VmallocChunk:": - m.VmallocChunk = &val - m.VmallocChunkBytes = &valBytes - case "Percpu:": - m.Percpu = &val - m.PercpuBytes = &valBytes + m.VmallocChunk = &v case "HardwareCorrupted:": - m.HardwareCorrupted = &val - m.HardwareCorruptedBytes = &valBytes + m.HardwareCorrupted = &v case "AnonHugePages:": - m.AnonHugePages = &val - m.AnonHugePagesBytes = &valBytes + m.AnonHugePages = &v case "ShmemHugePages:": - m.ShmemHugePages = &val - m.ShmemHugePagesBytes = &valBytes + m.ShmemHugePages = &v case "ShmemPmdMapped:": - m.ShmemPmdMapped = &val - m.ShmemPmdMappedBytes = &valBytes + m.ShmemPmdMapped = &v case "CmaTotal:": - m.CmaTotal = &val - m.CmaTotalBytes = &valBytes + m.CmaTotal = &v case "CmaFree:": - m.CmaFree = &val - m.CmaFreeBytes = &valBytes + m.CmaFree = &v case "HugePages_Total:": - m.HugePagesTotal = &val + m.HugePagesTotal = &v case "HugePages_Free:": - m.HugePagesFree = &val + m.HugePagesFree = &v case "HugePages_Rsvd:": - m.HugePagesRsvd = &val + m.HugePagesRsvd = &v case "HugePages_Surp:": - m.HugePagesSurp = &val + m.HugePagesSurp = &v case "Hugepagesize:": - m.Hugepagesize = &val - m.HugepagesizeBytes = &valBytes + m.Hugepagesize = &v case "DirectMap4k:": - m.DirectMap4k = &val - m.DirectMap4kBytes = &valBytes + m.DirectMap4k = &v case "DirectMap2M:": - m.DirectMap2M = &val - m.DirectMap2MBytes = &valBytes + m.DirectMap2M = &v case "DirectMap1G:": - m.DirectMap1G = &val - m.DirectMap1GBytes = &valBytes + m.DirectMap1G = &v } } diff --git a/vendor/github.com/prometheus/procfs/mountinfo.go b/vendor/github.com/prometheus/procfs/mountinfo.go index a704c5e7..388ebf39 100644 --- a/vendor/github.com/prometheus/procfs/mountinfo.go +++ b/vendor/github.com/prometheus/procfs/mountinfo.go @@ -109,7 +109,7 @@ func parseMountInfoString(mountString string) (*MountInfo, error) { if mountInfo[6] != "" { mount.OptionalFields, err = mountOptionsParseOptionalFields(mountInfo[6 : mountInfoLength-4]) if err != nil { - return nil, fmt.Errorf("%w: %w", ErrFileParse, err) + return nil, fmt.Errorf("%s: %w", ErrFileParse, err) } } return mount, nil diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go index 75a3b6c8..9d8af6db 100644 --- a/vendor/github.com/prometheus/procfs/mountstats.go +++ b/vendor/github.com/prometheus/procfs/mountstats.go @@ -88,7 +88,7 @@ type MountStatsNFS struct { // Statistics broken down by filesystem operation. Operations []NFSOperationStats // Statistics about the NFS RPC transport. - Transport []NFSTransportStats + Transport NFSTransportStats } // mountStats implements MountStats. @@ -194,6 +194,8 @@ type NFSOperationStats struct { CumulativeTotalResponseMilliseconds uint64 // Duration from when a request was enqueued to when it was completely handled. CumulativeTotalRequestMilliseconds uint64 + // The average time from the point the client sends RPC requests until it receives the response. + AverageRTTMilliseconds float64 // The count of operations that complete with tk_status < 0. These statuses usually indicate error conditions. Errors uint64 } @@ -432,7 +434,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e return nil, err } - stats.Transport = append(stats.Transport, *tstats) + stats.Transport = *tstats } // When encountering "per-operation statistics", we must break this @@ -580,6 +582,9 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { CumulativeTotalResponseMilliseconds: ns[6], CumulativeTotalRequestMilliseconds: ns[7], } + if ns[0] != 0 { + opStats.AverageRTTMilliseconds = float64(ns[6]) / float64(ns[0]) + } if len(ns) > 8 { opStats.Errors = ns[8] @@ -627,7 +632,7 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats return nil, fmt.Errorf("%w: invalid NFS transport stats 1.1 statement: %v, protocol: %v", ErrFileParse, ss, protocol) } default: - return nil, fmt.Errorf("%w: Unrecognized NFS transport stats version: %q, protocol: %v", ErrFileParse, statVersion, protocol) + return nil, fmt.Errorf("%s: Unrecognized NFS transport stats version: %q, protocol: %v", ErrFileParse, statVersion, protocol) } // Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay diff --git a/vendor/github.com/prometheus/procfs/net_conntrackstat.go b/vendor/github.com/prometheus/procfs/net_conntrackstat.go index 316df5fb..fdfa4561 100644 --- a/vendor/github.com/prometheus/procfs/net_conntrackstat.go +++ b/vendor/github.com/prometheus/procfs/net_conntrackstat.go @@ -58,7 +58,7 @@ func readConntrackStat(path string) ([]ConntrackStatEntry, error) { stat, err := parseConntrackStat(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("%w: Cannot read file: %v: %w", ErrFileRead, path, err) + return nil, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, path, err) } return stat, nil @@ -86,7 +86,7 @@ func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) { func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) { entries, err := util.ParseHexUint64s(fields) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse entry: %d: %w", ErrFileParse, entries, err) + return nil, fmt.Errorf("%s: Cannot parse entry: %d: %w", ErrFileParse, entries, err) } numEntries := len(entries) if numEntries < 16 || numEntries > 17 { diff --git a/vendor/github.com/prometheus/procfs/net_ip_socket.go b/vendor/github.com/prometheus/procfs/net_ip_socket.go index b70f1fc7..4da81ea5 100644 --- a/vendor/github.com/prometheus/procfs/net_ip_socket.go +++ b/vendor/github.com/prometheus/procfs/net_ip_socket.go @@ -50,13 +50,10 @@ type ( // UsedSockets shows the total number of parsed lines representing the // number of used sockets. UsedSockets uint64 - // Drops shows the total number of dropped packets of all UPD sockets. - Drops *uint64 } // netIPSocketLine represents the fields parsed from a single line // in /proc/net/{t,u}dp{,6}. Fields which are not used by IPSocket are skipped. - // Drops is non-nil for udp{,6}, but nil for tcp{,6}. // For the proc file format details, see https://linux.die.net/man/5/proc. netIPSocketLine struct { Sl uint64 @@ -69,7 +66,6 @@ type ( RxQueue uint64 UID uint64 Inode uint64 - Drops *uint64 } ) @@ -81,14 +77,13 @@ func newNetIPSocket(file string) (NetIPSocket, error) { defer f.Close() var netIPSocket NetIPSocket - isUDP := strings.Contains(file, "udp") lr := io.LimitReader(f, readLimit) s := bufio.NewScanner(lr) s.Scan() // skip first line with headers for s.Scan() { fields := strings.Fields(s.Text()) - line, err := parseNetIPSocketLine(fields, isUDP) + line, err := parseNetIPSocketLine(fields) if err != nil { return nil, err } @@ -109,25 +104,19 @@ func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) { defer f.Close() var netIPSocketSummary NetIPSocketSummary - var udpPacketDrops uint64 - isUDP := strings.Contains(file, "udp") lr := io.LimitReader(f, readLimit) s := bufio.NewScanner(lr) s.Scan() // skip first line with headers for s.Scan() { fields := strings.Fields(s.Text()) - line, err := parseNetIPSocketLine(fields, isUDP) + line, err := parseNetIPSocketLine(fields) if err != nil { return nil, err } netIPSocketSummary.TxQueueLength += line.TxQueue netIPSocketSummary.RxQueueLength += line.RxQueue netIPSocketSummary.UsedSockets++ - if isUDP { - udpPacketDrops += *line.Drops - netIPSocketSummary.Drops = &udpPacketDrops - } } if err := s.Err(); err != nil { return nil, err @@ -141,7 +130,7 @@ func parseIP(hexIP string) (net.IP, error) { var byteIP []byte byteIP, err := hex.DecodeString(hexIP) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse socket field in %q: %w", ErrFileParse, hexIP, err) + return nil, fmt.Errorf("%s: Cannot parse socket field in %q: %w", ErrFileParse, hexIP, err) } switch len(byteIP) { case 4: @@ -155,12 +144,12 @@ func parseIP(hexIP string) (net.IP, error) { } return i, nil default: - return nil, fmt.Errorf("%w: Unable to parse IP %s: %v", ErrFileParse, hexIP, nil) + return nil, fmt.Errorf("%s: Unable to parse IP %s: %w", ErrFileParse, hexIP, nil) } } // parseNetIPSocketLine parses a single line, represented by a list of fields. -func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) { +func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) { line := &netIPSocketLine{} if len(fields) < 10 { return nil, fmt.Errorf( @@ -178,7 +167,7 @@ func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) } if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil { - return nil, fmt.Errorf("%w: Unable to parse sl field in %q: %w", ErrFileParse, line.Sl, err) + return nil, fmt.Errorf("%s: Unable to parse sl field in %q: %w", ErrFileParse, line.Sl, err) } // local_address l := strings.Split(fields[1], ":") @@ -189,7 +178,7 @@ func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) return nil, err } if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil { - return nil, fmt.Errorf("%w: Unable to parse local_address port value line %q: %w", ErrFileParse, line.LocalPort, err) + return nil, fmt.Errorf("%s: Unable to parse local_address port value line %q: %w", ErrFileParse, line.LocalPort, err) } // remote_address @@ -201,12 +190,12 @@ func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) return nil, err } if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil { - return nil, fmt.Errorf("%w: Cannot parse rem_address port value in %q: %w", ErrFileParse, line.RemPort, err) + return nil, fmt.Errorf("%s: Cannot parse rem_address port value in %q: %w", ErrFileParse, line.RemPort, err) } // st if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil { - return nil, fmt.Errorf("%w: Cannot parse st value in %q: %w", ErrFileParse, line.St, err) + return nil, fmt.Errorf("%s: Cannot parse st value in %q: %w", ErrFileParse, line.St, err) } // tx_queue and rx_queue @@ -219,29 +208,20 @@ func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) ) } if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil { - return nil, fmt.Errorf("%w: Cannot parse tx_queue value in %q: %w", ErrFileParse, line.TxQueue, err) + return nil, fmt.Errorf("%s: Cannot parse tx_queue value in %q: %w", ErrFileParse, line.TxQueue, err) } if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil { - return nil, fmt.Errorf("%w: Cannot parse trx_queue value in %q: %w", ErrFileParse, line.RxQueue, err) + return nil, fmt.Errorf("%s: Cannot parse trx_queue value in %q: %w", ErrFileParse, line.RxQueue, err) } // uid if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil { - return nil, fmt.Errorf("%w: Cannot parse UID value in %q: %w", ErrFileParse, line.UID, err) + return nil, fmt.Errorf("%s: Cannot parse UID value in %q: %w", ErrFileParse, line.UID, err) } // inode if line.Inode, err = strconv.ParseUint(fields[9], 0, 64); err != nil { - return nil, fmt.Errorf("%w: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err) - } - - // drops - if isUDP { - drops, err := strconv.ParseUint(fields[12], 0, 64) - if err != nil { - return nil, fmt.Errorf("%w: Cannot parse drops value in %q: %w", ErrFileParse, drops, err) - } - line.Drops = &drops + return nil, fmt.Errorf("%s: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err) } return line, nil diff --git a/vendor/github.com/prometheus/procfs/net_sockstat.go b/vendor/github.com/prometheus/procfs/net_sockstat.go index fae62b13..360e36af 100644 --- a/vendor/github.com/prometheus/procfs/net_sockstat.go +++ b/vendor/github.com/prometheus/procfs/net_sockstat.go @@ -69,7 +69,7 @@ func readSockstat(name string) (*NetSockstat, error) { stat, err := parseSockstat(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("%w: sockstats from %q: %w", ErrFileRead, name, err) + return nil, fmt.Errorf("%s: sockstats from %q: %w", ErrFileRead, name, err) } return stat, nil @@ -89,7 +89,7 @@ func parseSockstat(r io.Reader) (*NetSockstat, error) { // The remaining fields are key/value pairs. kvs, err := parseSockstatKVs(fields[1:]) if err != nil { - return nil, fmt.Errorf("%w: sockstat key/value pairs from %q: %w", ErrFileParse, s.Text(), err) + return nil, fmt.Errorf("%s: sockstat key/value pairs from %q: %w", ErrFileParse, s.Text(), err) } // The first field is the protocol. We must trim its colon suffix. diff --git a/vendor/github.com/prometheus/procfs/net_softnet.go b/vendor/github.com/prometheus/procfs/net_softnet.go index 71c8059f..c7708529 100644 --- a/vendor/github.com/prometheus/procfs/net_softnet.go +++ b/vendor/github.com/prometheus/procfs/net_softnet.go @@ -64,7 +64,7 @@ func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) { entries, err := parseSoftnet(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("%w: /proc/net/softnet_stat: %w", ErrFileParse, err) + return nil, fmt.Errorf("%s: /proc/net/softnet_stat: %w", ErrFileParse, err) } return entries, nil diff --git a/vendor/github.com/prometheus/procfs/net_tls_stat.go b/vendor/github.com/prometheus/procfs/net_tls_stat.go deleted file mode 100644 index 13994c17..00000000 --- a/vendor/github.com/prometheus/procfs/net_tls_stat.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2023 Prometheus Team -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package procfs - -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" -) - -// TLSStat struct represents data in /proc/net/tls_stat. -// See https://docs.kernel.org/networking/tls.html#statistics -type TLSStat struct { - // number of TX sessions currently installed where host handles cryptography - TLSCurrTxSw int - // number of RX sessions currently installed where host handles cryptography - TLSCurrRxSw int - // number of TX sessions currently installed where NIC handles cryptography - TLSCurrTxDevice int - // number of RX sessions currently installed where NIC handles cryptography - TLSCurrRxDevice int - //number of TX sessions opened with host cryptography - TLSTxSw int - //number of RX sessions opened with host cryptography - TLSRxSw int - // number of TX sessions opened with NIC cryptography - TLSTxDevice int - // number of RX sessions opened with NIC cryptography - TLSRxDevice int - // record decryption failed (e.g. due to incorrect authentication tag) - TLSDecryptError int - // number of RX resyncs sent to NICs handling cryptography - TLSRxDeviceResync int - // number of RX records which had to be re-decrypted due to TLS_RX_EXPECT_NO_PAD mis-prediction. Note that this counter will also increment for non-data records. - TLSDecryptRetry int - // number of data RX records which had to be re-decrypted due to TLS_RX_EXPECT_NO_PAD mis-prediction. - TLSRxNoPadViolation int -} - -// NewTLSStat reads the tls_stat statistics. -func NewTLSStat() (TLSStat, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return TLSStat{}, err - } - - return fs.NewTLSStat() -} - -// NewTLSStat reads the tls_stat statistics. -func (fs FS) NewTLSStat() (TLSStat, error) { - file, err := os.Open(fs.proc.Path("net/tls_stat")) - if err != nil { - return TLSStat{}, err - } - defer file.Close() - - var ( - tlsstat = TLSStat{} - s = bufio.NewScanner(file) - ) - - for s.Scan() { - fields := strings.Fields(s.Text()) - - if len(fields) != 2 { - return TLSStat{}, fmt.Errorf("%w: %q line %q", ErrFileParse, file.Name(), s.Text()) - } - - name := fields[0] - value, err := strconv.Atoi(fields[1]) - if err != nil { - return TLSStat{}, err - } - - switch name { - case "TlsCurrTxSw": - tlsstat.TLSCurrTxSw = value - case "TlsCurrRxSw": - tlsstat.TLSCurrRxSw = value - case "TlsCurrTxDevice": - tlsstat.TLSCurrTxDevice = value - case "TlsCurrRxDevice": - tlsstat.TLSCurrRxDevice = value - case "TlsTxSw": - tlsstat.TLSTxSw = value - case "TlsRxSw": - tlsstat.TLSRxSw = value - case "TlsTxDevice": - tlsstat.TLSTxDevice = value - case "TlsRxDevice": - tlsstat.TLSRxDevice = value - case "TlsDecryptError": - tlsstat.TLSDecryptError = value - case "TlsRxDeviceResync": - tlsstat.TLSRxDeviceResync = value - case "TlsDecryptRetry": - tlsstat.TLSDecryptRetry = value - case "TlsRxNoPadViolation": - tlsstat.TLSRxNoPadViolation = value - } - - } - - return tlsstat, s.Err() -} diff --git a/vendor/github.com/prometheus/procfs/net_unix.go b/vendor/github.com/prometheus/procfs/net_unix.go index d868cebd..acbbc57e 100644 --- a/vendor/github.com/prometheus/procfs/net_unix.go +++ b/vendor/github.com/prometheus/procfs/net_unix.go @@ -108,14 +108,14 @@ func parseNetUNIX(r io.Reader) (*NetUNIX, error) { line := s.Text() item, err := nu.parseLine(line, hasInode, minFields) if err != nil { - return nil, fmt.Errorf("%w: /proc/net/unix encountered data %q: %w", ErrFileParse, line, err) + return nil, fmt.Errorf("%s: /proc/net/unix encountered data %q: %w", ErrFileParse, line, err) } nu.Rows = append(nu.Rows, item) } if err := s.Err(); err != nil { - return nil, fmt.Errorf("%w: /proc/net/unix encountered data: %w", ErrFileParse, err) + return nil, fmt.Errorf("%s: /proc/net/unix encountered data: %w", ErrFileParse, err) } return &nu, nil @@ -136,29 +136,29 @@ func (u *NetUNIX) parseLine(line string, hasInode bool, min int) (*NetUNIXLine, users, err := u.parseUsers(fields[1]) if err != nil { - return nil, fmt.Errorf("%w: ref count %q: %w", ErrFileParse, fields[1], err) + return nil, fmt.Errorf("%s: ref count %q: %w", ErrFileParse, fields[1], err) } flags, err := u.parseFlags(fields[3]) if err != nil { - return nil, fmt.Errorf("%w: Unable to parse flags %q: %w", ErrFileParse, fields[3], err) + return nil, fmt.Errorf("%s: Unable to parse flags %q: %w", ErrFileParse, fields[3], err) } typ, err := u.parseType(fields[4]) if err != nil { - return nil, fmt.Errorf("%w: Failed to parse type %q: %w", ErrFileParse, fields[4], err) + return nil, fmt.Errorf("%s: Failed to parse type %q: %w", ErrFileParse, fields[4], err) } state, err := u.parseState(fields[5]) if err != nil { - return nil, fmt.Errorf("%w: Failed to parse state %q: %w", ErrFileParse, fields[5], err) + return nil, fmt.Errorf("%s: Failed to parse state %q: %w", ErrFileParse, fields[5], err) } var inode uint64 if hasInode { inode, err = u.parseInode(fields[6]) if err != nil { - return nil, fmt.Errorf("%w failed to parse inode %q: %w", ErrFileParse, fields[6], err) + return nil, fmt.Errorf("%s failed to parse inode %q: %w", ErrFileParse, fields[6], err) } } diff --git a/vendor/github.com/prometheus/procfs/net_wireless.go b/vendor/github.com/prometheus/procfs/net_wireless.go index 7c597bc8..7443edca 100644 --- a/vendor/github.com/prometheus/procfs/net_wireless.go +++ b/vendor/github.com/prometheus/procfs/net_wireless.go @@ -68,7 +68,7 @@ func (fs FS) Wireless() ([]*Wireless, error) { m, err := parseWireless(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("%w: wireless: %w", ErrFileParse, err) + return nil, fmt.Errorf("%s: wireless: %w", ErrFileParse, err) } return m, nil @@ -114,47 +114,47 @@ func parseWireless(r io.Reader) ([]*Wireless, error) { qlink, err := strconv.Atoi(strings.TrimSuffix(stats[1], ".")) if err != nil { - return nil, fmt.Errorf("%w: parse Quality:link as integer %q: %w", ErrFileParse, qlink, err) + return nil, fmt.Errorf("%s: parse Quality:link as integer %q: %w", ErrFileParse, qlink, err) } qlevel, err := strconv.Atoi(strings.TrimSuffix(stats[2], ".")) if err != nil { - return nil, fmt.Errorf("%w: Quality:level as integer %q: %w", ErrFileParse, qlevel, err) + return nil, fmt.Errorf("%s: Quality:level as integer %q: %w", ErrFileParse, qlevel, err) } qnoise, err := strconv.Atoi(strings.TrimSuffix(stats[3], ".")) if err != nil { - return nil, fmt.Errorf("%w: Quality:noise as integer %q: %w", ErrFileParse, qnoise, err) + return nil, fmt.Errorf("%s: Quality:noise as integer %q: %w", ErrFileParse, qnoise, err) } dnwid, err := strconv.Atoi(stats[4]) if err != nil { - return nil, fmt.Errorf("%w: Discarded:nwid as integer %q: %w", ErrFileParse, dnwid, err) + return nil, fmt.Errorf("%s: Discarded:nwid as integer %q: %w", ErrFileParse, dnwid, err) } dcrypt, err := strconv.Atoi(stats[5]) if err != nil { - return nil, fmt.Errorf("%w: Discarded:crypt as integer %q: %w", ErrFileParse, dcrypt, err) + return nil, fmt.Errorf("%s: Discarded:crypt as integer %q: %w", ErrFileParse, dcrypt, err) } dfrag, err := strconv.Atoi(stats[6]) if err != nil { - return nil, fmt.Errorf("%w: Discarded:frag as integer %q: %w", ErrFileParse, dfrag, err) + return nil, fmt.Errorf("%s: Discarded:frag as integer %q: %w", ErrFileParse, dfrag, err) } dretry, err := strconv.Atoi(stats[7]) if err != nil { - return nil, fmt.Errorf("%w: Discarded:retry as integer %q: %w", ErrFileParse, dretry, err) + return nil, fmt.Errorf("%s: Discarded:retry as integer %q: %w", ErrFileParse, dretry, err) } dmisc, err := strconv.Atoi(stats[8]) if err != nil { - return nil, fmt.Errorf("%w: Discarded:misc as integer %q: %w", ErrFileParse, dmisc, err) + return nil, fmt.Errorf("%s: Discarded:misc as integer %q: %w", ErrFileParse, dmisc, err) } mbeacon, err := strconv.Atoi(stats[9]) if err != nil { - return nil, fmt.Errorf("%w: Missed:beacon as integer %q: %w", ErrFileParse, mbeacon, err) + return nil, fmt.Errorf("%s: Missed:beacon as integer %q: %w", ErrFileParse, mbeacon, err) } w := &Wireless{ @@ -175,7 +175,7 @@ func parseWireless(r io.Reader) ([]*Wireless, error) { } if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("%w: Failed to scan /proc/net/wireless: %w", ErrFileRead, err) + return nil, fmt.Errorf("%s: Failed to scan /proc/net/wireless: %w", ErrFileRead, err) } return interfaces, nil diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go index 14279636..d1f71caa 100644 --- a/vendor/github.com/prometheus/procfs/proc.go +++ b/vendor/github.com/prometheus/procfs/proc.go @@ -111,7 +111,7 @@ func (fs FS) AllProcs() (Procs, error) { names, err := d.Readdirnames(-1) if err != nil { - return Procs{}, fmt.Errorf("%w: Cannot read file: %v: %w", ErrFileRead, names, err) + return Procs{}, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, names, err) } p := Procs{} @@ -137,7 +137,7 @@ func (p Proc) CmdLine() ([]string, error) { return []string{}, nil } - return strings.Split(string(bytes.TrimRight(data, "\x00")), "\x00"), nil + return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil } // Wchan returns the wchan (wait channel) of a process. @@ -212,7 +212,7 @@ func (p Proc) FileDescriptors() ([]uintptr, error) { for i, n := range names { fd, err := strconv.ParseInt(n, 10, 32) if err != nil { - return nil, fmt.Errorf("%w: Cannot parse line: %v: %w", ErrFileParse, i, err) + return nil, fmt.Errorf("%s: Cannot parse line: %v: %w", ErrFileParse, i, err) } fds[i] = uintptr(fd) } @@ -297,7 +297,7 @@ func (p Proc) fileDescriptors() ([]string, error) { names, err := d.Readdirnames(-1) if err != nil { - return nil, fmt.Errorf("%w: Cannot read file: %v: %w", ErrFileRead, names, err) + return nil, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, names, err) } return names, nil diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go index 9530b14b..c86d815d 100644 --- a/vendor/github.com/prometheus/procfs/proc_limits.go +++ b/vendor/github.com/prometheus/procfs/proc_limits.go @@ -154,7 +154,7 @@ func parseUint(s string) (uint64, error) { } i, err := strconv.ParseUint(s, 10, 64) if err != nil { - return 0, fmt.Errorf("%w: couldn't parse value %q: %w", ErrFileParse, s, err) + return 0, fmt.Errorf("%s: couldn't parse value %q: %w", ErrFileParse, s, err) } return i, nil } diff --git a/vendor/github.com/prometheus/procfs/proc_ns.go b/vendor/github.com/prometheus/procfs/proc_ns.go index 0f8f847f..c2266675 100644 --- a/vendor/github.com/prometheus/procfs/proc_ns.go +++ b/vendor/github.com/prometheus/procfs/proc_ns.go @@ -40,7 +40,7 @@ func (p Proc) Namespaces() (Namespaces, error) { names, err := d.Readdirnames(-1) if err != nil { - return nil, fmt.Errorf("%w: failed to read contents of ns dir: %w", ErrFileRead, err) + return nil, fmt.Errorf("%s: failed to read contents of ns dir: %w", ErrFileRead, err) } ns := make(Namespaces, len(names)) @@ -58,7 +58,7 @@ func (p Proc) Namespaces() (Namespaces, error) { typ := fields[0] inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32) if err != nil { - return nil, fmt.Errorf("%w: inode from %q: %w", ErrFileParse, fields[1], err) + return nil, fmt.Errorf("%s: inode from %q: %w", ErrFileParse, fields[1], err) } ns[name] = Namespace{typ, uint32(inode)} diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go index ccd35f15..fe9dbb42 100644 --- a/vendor/github.com/prometheus/procfs/proc_psi.go +++ b/vendor/github.com/prometheus/procfs/proc_psi.go @@ -61,7 +61,7 @@ type PSIStats struct { func (fs FS) PSIStatsForResource(resource string) (PSIStats, error) { data, err := util.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource))) if err != nil { - return PSIStats{}, fmt.Errorf("%w: psi_stats: unavailable for %q: %w", ErrFileRead, resource, err) + return PSIStats{}, fmt.Errorf("%s: psi_stats: unavailable for %q: %w", ErrFileRead, resource, err) } return parsePSIStats(bytes.NewReader(data)) diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go index 09060e82..ad8785a4 100644 --- a/vendor/github.com/prometheus/procfs/proc_smaps.go +++ b/vendor/github.com/prometheus/procfs/proc_smaps.go @@ -127,7 +127,7 @@ func (s *ProcSMapsRollup) parseLine(line string) error { } v := strings.TrimSpace(kv[1]) - v = strings.TrimSuffix(v, " kB") + v = strings.TrimRight(v, " kB") vKBytes, err := strconv.ParseUint(v, 10, 64) if err != nil { diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 06a8d931..923e5500 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -110,11 +110,6 @@ type ProcStat struct { Policy uint // Aggregated block I/O delays, measured in clock ticks (centiseconds). DelayAcctBlkIOTicks uint64 - // Guest time of the process (time spent running a virtual CPU for a guest - // operating system), measured in clock ticks. - GuestTime int - // Guest time of the process's children, measured in clock ticks. - CGuestTime int proc FS } @@ -194,8 +189,6 @@ func (p Proc) Stat() (ProcStat, error) { &s.RTPriority, &s.Policy, &s.DelayAcctBlkIOTicks, - &s.GuestTime, - &s.CGuestTime, ) if err != nil { return ProcStat{}, err diff --git a/vendor/github.com/prometheus/procfs/proc_status.go b/vendor/github.com/prometheus/procfs/proc_status.go index a055197c..46307f57 100644 --- a/vendor/github.com/prometheus/procfs/proc_status.go +++ b/vendor/github.com/prometheus/procfs/proc_status.go @@ -15,7 +15,6 @@ package procfs import ( "bytes" - "math/bits" "sort" "strconv" "strings" @@ -77,9 +76,9 @@ type ProcStatus struct { NonVoluntaryCtxtSwitches uint64 // UIDs of the process (Real, effective, saved set, and filesystem UIDs) - UIDs [4]uint64 + UIDs [4]string // GIDs of the process (Real, effective, saved set, and filesystem GIDs) - GIDs [4]uint64 + GIDs [4]string // CpusAllowedList: List of cpu cores processes are allowed to run on. CpusAllowedList []uint64 @@ -114,37 +113,22 @@ func (p Proc) NewStatus() (ProcStatus, error) { // convert kB to B vBytes := vKBytes * 1024 - err = s.fillStatus(k, v, vKBytes, vBytes) - if err != nil { - return ProcStatus{}, err - } + s.fillStatus(k, v, vKBytes, vBytes) } return s, nil } -func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintBytes uint64) error { +func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintBytes uint64) { switch k { case "Tgid": s.TGID = int(vUint) case "Name": s.Name = vString case "Uid": - var err error - for i, v := range strings.Split(vString, "\t") { - s.UIDs[i], err = strconv.ParseUint(v, 10, bits.UintSize) - if err != nil { - return err - } - } + copy(s.UIDs[:], strings.Split(vString, "\t")) case "Gid": - var err error - for i, v := range strings.Split(vString, "\t") { - s.GIDs[i], err = strconv.ParseUint(v, 10, bits.UintSize) - if err != nil { - return err - } - } + copy(s.GIDs[:], strings.Split(vString, "\t")) case "NSpid": s.NSpids = calcNSPidsList(vString) case "VmPeak": @@ -189,7 +173,6 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt s.CpusAllowedList = calcCpusAllowedList(vString) } - return nil } // TotalCtxtSwitches returns the total context switch. diff --git a/vendor/github.com/prometheus/procfs/proc_sys.go b/vendor/github.com/prometheus/procfs/proc_sys.go index 5eefbe2e..12c5bf05 100644 --- a/vendor/github.com/prometheus/procfs/proc_sys.go +++ b/vendor/github.com/prometheus/procfs/proc_sys.go @@ -44,7 +44,7 @@ func (fs FS) SysctlInts(sysctl string) ([]int, error) { vp := util.NewValueParser(f) values[i] = vp.Int() if err := vp.Err(); err != nil { - return nil, fmt.Errorf("%w: field %d in sysctl %s is not a valid int: %w", ErrFileParse, i, sysctl, err) + return nil, fmt.Errorf("%s: field %d in sysctl %s is not a valid int: %w", ErrFileParse, i, sysctl, err) } } return values, nil diff --git a/vendor/github.com/prometheus/procfs/softirqs.go b/vendor/github.com/prometheus/procfs/softirqs.go index 28708e07..b8fad677 100644 --- a/vendor/github.com/prometheus/procfs/softirqs.go +++ b/vendor/github.com/prometheus/procfs/softirqs.go @@ -74,7 +74,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Hi = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Hi[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (HI%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (HI%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "TIMER:": @@ -82,7 +82,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Timer = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Timer[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (TIMER%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (TIMER%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "NET_TX:": @@ -90,7 +90,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.NetTx = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.NetTx[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (NET_TX%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (NET_TX%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "NET_RX:": @@ -98,7 +98,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.NetRx = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.NetRx[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (NET_RX%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (NET_RX%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "BLOCK:": @@ -106,7 +106,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Block = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Block[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (BLOCK%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (BLOCK%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "IRQ_POLL:": @@ -114,7 +114,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.IRQPoll = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.IRQPoll[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (IRQ_POLL%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (IRQ_POLL%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "TASKLET:": @@ -122,7 +122,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Tasklet = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Tasklet[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (TASKLET%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (TASKLET%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "SCHED:": @@ -130,7 +130,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Sched = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Sched[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (SCHED%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (SCHED%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "HRTIMER:": @@ -138,7 +138,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.HRTimer = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.HRTimer[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (HRTIMER%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (HRTIMER%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "RCU:": @@ -146,14 +146,14 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.RCU = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.RCU[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse %q (RCU%d): %w", ErrFileParse, count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (RCU%d): %w", ErrFileParse, count, i, err) } } } } if err := scanner.Err(); err != nil { - return Softirqs{}, fmt.Errorf("%w: couldn't parse softirqs: %w", ErrFileParse, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse softirqs: %w", ErrFileParse, err) } return softirqs, scanner.Err() diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go index e36b41c1..34fc3ee2 100644 --- a/vendor/github.com/prometheus/procfs/stat.go +++ b/vendor/github.com/prometheus/procfs/stat.go @@ -93,7 +93,7 @@ func parseCPUStat(line string) (CPUStat, int64, error) { &cpuStat.Guest, &cpuStat.GuestNice) if err != nil && err != io.EOF { - return CPUStat{}, -1, fmt.Errorf("%w: couldn't parse %q (cpu): %w", ErrFileParse, line, err) + return CPUStat{}, -1, fmt.Errorf("%s: couldn't parse %q (cpu): %w", ErrFileParse, line, err) } if count == 0 { return CPUStat{}, -1, fmt.Errorf("%w: couldn't parse %q (cpu): 0 elements parsed", ErrFileParse, line) @@ -116,7 +116,7 @@ func parseCPUStat(line string) (CPUStat, int64, error) { cpuID, err := strconv.ParseInt(cpu[3:], 10, 64) if err != nil { - return CPUStat{}, -1, fmt.Errorf("%w: couldn't parse %q (cpu/cpuid): %w", ErrFileParse, line, err) + return CPUStat{}, -1, fmt.Errorf("%s: couldn't parse %q (cpu/cpuid): %w", ErrFileParse, line, err) } return cpuStat, cpuID, nil @@ -136,7 +136,7 @@ func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) { &softIRQStat.Hrtimer, &softIRQStat.Rcu) if err != nil { - return SoftIRQStat{}, 0, fmt.Errorf("%w: couldn't parse %q (softirq): %w", ErrFileParse, line, err) + return SoftIRQStat{}, 0, fmt.Errorf("%s: couldn't parse %q (softirq): %w", ErrFileParse, line, err) } return softIRQStat, total, nil @@ -201,34 +201,34 @@ func parseStat(r io.Reader, fileName string) (Stat, error) { switch { case parts[0] == "btime": if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (btime): %w", ErrFileParse, parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (btime): %w", ErrFileParse, parts[1], err) } case parts[0] == "intr": if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (intr): %w", ErrFileParse, parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (intr): %w", ErrFileParse, parts[1], err) } numberedIRQs := parts[2:] stat.IRQ = make([]uint64, len(numberedIRQs)) for i, count := range numberedIRQs { if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (intr%d): %w", ErrFileParse, count, i, err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (intr%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "ctxt": if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (ctxt): %w", ErrFileParse, parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (ctxt): %w", ErrFileParse, parts[1], err) } case parts[0] == "processes": if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (processes): %w", ErrFileParse, parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (processes): %w", ErrFileParse, parts[1], err) } case parts[0] == "procs_running": if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (procs_running): %w", ErrFileParse, parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (procs_running): %w", ErrFileParse, parts[1], err) } case parts[0] == "procs_blocked": if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q (procs_blocked): %w", ErrFileParse, parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (procs_blocked): %w", ErrFileParse, parts[1], err) } case parts[0] == "softirq": softIRQStats, total, err := parseSoftIRQStat(line) @@ -251,7 +251,7 @@ func parseStat(r io.Reader, fileName string) (Stat, error) { } if err := scanner.Err(); err != nil { - return Stat{}, fmt.Errorf("%w: couldn't parse %q: %w", ErrFileParse, fileName, err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q: %w", ErrFileParse, fileName, err) } return stat, nil diff --git a/vendor/github.com/prometheus/procfs/swaps.go b/vendor/github.com/prometheus/procfs/swaps.go index 65fec834..fa00f555 100644 --- a/vendor/github.com/prometheus/procfs/swaps.go +++ b/vendor/github.com/prometheus/procfs/swaps.go @@ -74,15 +74,15 @@ func parseSwapString(swapString string) (*Swap, error) { swap.Size, err = strconv.Atoi(swapFields[2]) if err != nil { - return nil, fmt.Errorf("%w: invalid swap size: %s: %w", ErrFileParse, swapFields[2], err) + return nil, fmt.Errorf("%s: invalid swap size: %s: %w", ErrFileParse, swapFields[2], err) } swap.Used, err = strconv.Atoi(swapFields[3]) if err != nil { - return nil, fmt.Errorf("%w: invalid swap used: %s: %w", ErrFileParse, swapFields[3], err) + return nil, fmt.Errorf("%s: invalid swap used: %s: %w", ErrFileParse, swapFields[3], err) } swap.Priority, err = strconv.Atoi(swapFields[4]) if err != nil { - return nil, fmt.Errorf("%w: invalid swap priority: %s: %w", ErrFileParse, swapFields[4], err) + return nil, fmt.Errorf("%s: invalid swap priority: %s: %w", ErrFileParse, swapFields[4], err) } return swap, nil diff --git a/vendor/github.com/prometheus/procfs/thread.go b/vendor/github.com/prometheus/procfs/thread.go index 80e0e947..df2215ec 100644 --- a/vendor/github.com/prometheus/procfs/thread.go +++ b/vendor/github.com/prometheus/procfs/thread.go @@ -45,7 +45,7 @@ func (fs FS) AllThreads(pid int) (Procs, error) { names, err := d.Readdirnames(-1) if err != nil { - return Procs{}, fmt.Errorf("%w: could not read %q: %w", ErrFileRead, d.Name(), err) + return Procs{}, fmt.Errorf("%s: could not read %q: %w", ErrFileRead, d.Name(), err) } t := Procs{} diff --git a/vendor/github.com/prometheus/procfs/zoneinfo.go b/vendor/github.com/prometheus/procfs/zoneinfo.go index e54d94b0..ce5fefa5 100644 --- a/vendor/github.com/prometheus/procfs/zoneinfo.go +++ b/vendor/github.com/prometheus/procfs/zoneinfo.go @@ -75,11 +75,11 @@ var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`) func (fs FS) Zoneinfo() ([]Zoneinfo, error) { data, err := os.ReadFile(fs.proc.Path("zoneinfo")) if err != nil { - return nil, fmt.Errorf("%w: error reading zoneinfo %q: %w", ErrFileRead, fs.proc.Path("zoneinfo"), err) + return nil, fmt.Errorf("%s: error reading zoneinfo %q: %w", ErrFileRead, fs.proc.Path("zoneinfo"), err) } zoneinfo, err := parseZoneinfo(data) if err != nil { - return nil, fmt.Errorf("%w: error parsing zoneinfo %q: %w", ErrFileParse, fs.proc.Path("zoneinfo"), err) + return nil, fmt.Errorf("%s: error parsing zoneinfo %q: %w", ErrFileParse, fs.proc.Path("zoneinfo"), err) } return zoneinfo, nil } diff --git a/vendor/github.com/rcrowley/go-metrics/.travis.yml b/vendor/github.com/rcrowley/go-metrics/.travis.yml index ce9afeae..409a5b63 100644 --- a/vendor/github.com/rcrowley/go-metrics/.travis.yml +++ b/vendor/github.com/rcrowley/go-metrics/.travis.yml @@ -13,7 +13,6 @@ go: - "1.12" - "1.13" - "1.14" - - "1.15" script: - ./validate.sh diff --git a/vendor/github.com/rivo/uniseg/README.md b/vendor/github.com/rivo/uniseg/README.md index a8191b81..25e93468 100644 --- a/vendor/github.com/rivo/uniseg/README.md +++ b/vendor/github.com/rivo/uniseg/README.md @@ -3,7 +3,7 @@ [![Go Reference](https://pkg.go.dev/badge/github.com/rivo/uniseg.svg)](https://pkg.go.dev/github.com/rivo/uniseg) [![Go Report](https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg)](https://goreportcard.com/report/github.com/rivo/uniseg) -This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](https://unicode.org/reports/tr29/), Unicode Line Breaking according to [Unicode Standard Annex #14](https://unicode.org/reports/tr14/) (Unicode version 15.0.0), and monospace font string width calculation similar to [wcwidth](https://man7.org/linux/man-pages/man3/wcwidth.3.html). +This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](https://unicode.org/reports/tr29/), Unicode Line Breaking according to [Unicode Standard Annex #14](https://unicode.org/reports/tr14/) (Unicode version 14.0.0), and monospace font string width calculation similar to [wcwidth](https://man7.org/linux/man-pages/man3/wcwidth.3.html). ## Background @@ -73,7 +73,7 @@ for gr.Next() { ### Using the [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) Function -This avoids allocating a new `Graphemes` object but it requires the handling of states and boundaries: +This is orders of magnitude faster than the `Graphemes` class, but it requires the handling of states and boundaries: ```go str := "🇩🇪🏳️‍🌈" @@ -88,7 +88,29 @@ for len(str) > 0 { ### Advanced Examples -The [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) class offers the most convenient way to access all functionality of this package. But in some cases, it may be better to use the specialized functions directly. For example, if you're only interested in word segmentation, use [`FirstWord`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWord) or [`FirstWordInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWordInString): +Breaking into grapheme clusters and evaluating line breaks: + +```go +str := "First line.\nSecond line." +state := -1 +var ( + c string + boundaries int +) +for len(str) > 0 { + c, str, boundaries, state = uniseg.StepString(str, state) + fmt.Print(c) + if boundaries&uniseg.MaskLine == uniseg.LineCanBreak { + fmt.Print("|") + } else if boundaries&uniseg.MaskLine == uniseg.LineMustBreak { + fmt.Print("‖") + } +} +// First |line. +// ‖Second |line.‖ +``` + +If you're only interested in word segmentation, use [`FirstWord`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWord) or [`FirstWordInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWordInString): ```go str := "Hello, world!" @@ -111,8 +133,6 @@ Similarly, use - [`FirstSentence`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentence) or [`FirstSentenceInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentenceInString) for sentence segmentation only, and - [`FirstLineSegment`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegment) or [`FirstLineSegmentInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegmentInString) for line breaking / word wrapping (although using [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) is preferred as it will observe grapheme cluster boundaries). -If you're only interested in the width of characters, use [`FirstGraphemeCluster`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeCluster) or [`FirstGraphemeClusterInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeClusterInString). It is much faster than using [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step), [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString), or the [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) class because it does not include the logic for word / sentence / line boundaries. - Finally, if you need to reverse a string while preserving grapheme clusters, use [`ReverseString`](https://pkg.go.dev/github.com/rivo/uniseg#ReverseString): ```go diff --git a/vendor/github.com/rivo/uniseg/eastasianwidth.go b/vendor/github.com/rivo/uniseg/eastasianwidth.go index 5fc54d99..661934ac 100644 --- a/vendor/github.com/rivo/uniseg/eastasianwidth.go +++ b/vendor/github.com/rivo/uniseg/eastasianwidth.go @@ -1,13 +1,13 @@ -// Code generated via go generate from gen_properties.go. DO NOT EDIT. - package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. + // eastAsianWidth are taken from -// https://www.unicode.org/Public/15.0.0/ucd/EastAsianWidth.txt +// https://www.unicode.org/Public/14.0.0/ucd/EastAsianWidth.txt // and -// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt // ("Extended_Pictographic" only) -// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode +// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode // license agreement. var eastAsianWidth = [][3]int{ {0x0000, 0x001F, prN}, // Cc [32] .. @@ -504,7 +504,6 @@ var eastAsianWidth = [][3]int{ {0x0CE2, 0x0CE3, prN}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL {0x0CE6, 0x0CEF, prN}, // Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE {0x0CF1, 0x0CF2, prN}, // Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA - {0x0CF3, 0x0CF3, prN}, // Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT {0x0D00, 0x0D01, prN}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU {0x0D02, 0x0D03, prN}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA {0x0D04, 0x0D0C, prN}, // Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L @@ -566,7 +565,7 @@ var eastAsianWidth = [][3]int{ {0x0EBD, 0x0EBD, prN}, // Lo LAO SEMIVOWEL SIGN NYO {0x0EC0, 0x0EC4, prN}, // Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI {0x0EC6, 0x0EC6, prN}, // Lm LAO KO LA - {0x0EC8, 0x0ECE, prN}, // Mn [7] LAO TONE MAI EK..LAO YAMAKKAN + {0x0EC8, 0x0ECD, prN}, // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA {0x0ED0, 0x0ED9, prN}, // Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE {0x0EDC, 0x0EDF, prN}, // Lo [4] LAO HO NO..LAO LETTER KHMU NYO {0x0F00, 0x0F00, prN}, // Lo TIBETAN SYLLABLE OM @@ -1917,7 +1916,6 @@ var eastAsianWidth = [][3]int{ {0x10EAB, 0x10EAC, prN}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK {0x10EAD, 0x10EAD, prN}, // Pd YEZIDI HYPHENATION MARK {0x10EB0, 0x10EB1, prN}, // Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE - {0x10EFD, 0x10EFF, prN}, // Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA {0x10F00, 0x10F1C, prN}, // Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL {0x10F1D, 0x10F26, prN}, // No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF {0x10F27, 0x10F27, prN}, // Lo OLD SOGDIAN LIGATURE AYIN-DALETH @@ -2000,8 +1998,6 @@ var eastAsianWidth = [][3]int{ {0x11236, 0x11237, prN}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA {0x11238, 0x1123D, prN}, // Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN {0x1123E, 0x1123E, prN}, // Mn KHOJKI SIGN SUKUN - {0x1123F, 0x11240, prN}, // Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I - {0x11241, 0x11241, prN}, // Mn KHOJKI VOWEL SIGN VOCALIC R {0x11280, 0x11286, prN}, // Lo [7] MULTANI LETTER A..MULTANI LETTER GA {0x11288, 0x11288, prN}, // Lo MULTANI LETTER GHA {0x1128A, 0x1128D, prN}, // Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -2164,7 +2160,6 @@ var eastAsianWidth = [][3]int{ {0x11A9E, 0x11AA2, prN}, // Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 {0x11AB0, 0x11ABF, prN}, // Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA {0x11AC0, 0x11AF8, prN}, // Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL - {0x11B00, 0x11B09, prN}, // Po [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU {0x11C00, 0x11C08, prN}, // Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L {0x11C0A, 0x11C2E, prN}, // Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA {0x11C2F, 0x11C2F, prN}, // Mc BHAIKSUKI VOWEL SIGN AA @@ -2210,19 +2205,6 @@ var eastAsianWidth = [][3]int{ {0x11EF3, 0x11EF4, prN}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U {0x11EF5, 0x11EF6, prN}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O {0x11EF7, 0x11EF8, prN}, // Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION - {0x11F00, 0x11F01, prN}, // Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA - {0x11F02, 0x11F02, prN}, // Lo KAWI SIGN REPHA - {0x11F03, 0x11F03, prN}, // Mc KAWI SIGN VISARGA - {0x11F04, 0x11F10, prN}, // Lo [13] KAWI LETTER A..KAWI LETTER O - {0x11F12, 0x11F33, prN}, // Lo [34] KAWI LETTER KA..KAWI LETTER JNYA - {0x11F34, 0x11F35, prN}, // Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA - {0x11F36, 0x11F3A, prN}, // Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R - {0x11F3E, 0x11F3F, prN}, // Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI - {0x11F40, 0x11F40, prN}, // Mn KAWI VOWEL SIGN EU - {0x11F41, 0x11F41, prN}, // Mc KAWI SIGN KILLER - {0x11F42, 0x11F42, prN}, // Mn KAWI CONJOINER - {0x11F43, 0x11F4F, prN}, // Po [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL - {0x11F50, 0x11F59, prN}, // Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE {0x11FB0, 0x11FB0, prN}, // Lo LISU LETTER YHA {0x11FC0, 0x11FD4, prN}, // No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH {0x11FD5, 0x11FDC, prN}, // So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI @@ -2235,11 +2217,8 @@ var eastAsianWidth = [][3]int{ {0x12480, 0x12543, prN}, // Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU {0x12F90, 0x12FF0, prN}, // Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 {0x12FF1, 0x12FF2, prN}, // Po [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302 - {0x13000, 0x1342F, prN}, // Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D - {0x13430, 0x1343F, prN}, // Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE - {0x13440, 0x13440, prN}, // Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY - {0x13441, 0x13446, prN}, // Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN - {0x13447, 0x13455, prN}, // Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED + {0x13000, 0x1342E, prN}, // Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 + {0x13430, 0x13438, prN}, // Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT {0x14400, 0x14646, prN}, // Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 {0x16800, 0x16A38, prN}, // Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ {0x16A40, 0x16A5E, prN}, // Lo [31] MRO LETTER TA..MRO LETTER TEK @@ -2284,9 +2263,7 @@ var eastAsianWidth = [][3]int{ {0x1AFFD, 0x1AFFE, prW}, // Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 {0x1B000, 0x1B0FF, prW}, // Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 {0x1B100, 0x1B122, prW}, // Lo [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU - {0x1B132, 0x1B132, prW}, // Lo HIRAGANA LETTER SMALL KO {0x1B150, 0x1B152, prW}, // Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO - {0x1B155, 0x1B155, prW}, // Lo KATAKANA LETTER SMALL KO {0x1B164, 0x1B167, prW}, // Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N {0x1B170, 0x1B2FB, prW}, // Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB {0x1BC00, 0x1BC6A, prN}, // Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M @@ -2317,7 +2294,6 @@ var eastAsianWidth = [][3]int{ {0x1D200, 0x1D241, prN}, // So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 {0x1D242, 0x1D244, prN}, // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME {0x1D245, 0x1D245, prN}, // So GREEK MUSICAL LEIMMA - {0x1D2C0, 0x1D2D3, prN}, // No [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN {0x1D2E0, 0x1D2F3, prN}, // No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN {0x1D300, 0x1D356, prN}, // So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING {0x1D360, 0x1D378, prN}, // No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE @@ -2377,14 +2353,11 @@ var eastAsianWidth = [][3]int{ {0x1DF00, 0x1DF09, prN}, // Ll [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK {0x1DF0A, 0x1DF0A, prN}, // Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK {0x1DF0B, 0x1DF1E, prN}, // Ll [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL - {0x1DF25, 0x1DF2A, prN}, // Ll [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK {0x1E000, 0x1E006, prN}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE {0x1E008, 0x1E018, prN}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU {0x1E01B, 0x1E021, prN}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI {0x1E023, 0x1E024, prN}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS {0x1E026, 0x1E02A, prN}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA - {0x1E030, 0x1E06D, prN}, // Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE - {0x1E08F, 0x1E08F, prN}, // Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I {0x1E100, 0x1E12C, prN}, // Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W {0x1E130, 0x1E136, prN}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D {0x1E137, 0x1E13D, prN}, // Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER @@ -2397,10 +2370,6 @@ var eastAsianWidth = [][3]int{ {0x1E2EC, 0x1E2EF, prN}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI {0x1E2F0, 0x1E2F9, prN}, // Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE {0x1E2FF, 0x1E2FF, prN}, // Sc WANCHO NGUN SIGN - {0x1E4D0, 0x1E4EA, prN}, // Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL - {0x1E4EB, 0x1E4EB, prN}, // Lm NAG MUNDARI SIGN OJOD - {0x1E4EC, 0x1E4EF, prN}, // Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH - {0x1E4F0, 0x1E4F9, prN}, // Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE {0x1E7E0, 0x1E7E6, prN}, // Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO {0x1E7E8, 0x1E7EB, prN}, // Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE {0x1E7ED, 0x1E7EE, prN}, // Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -2529,14 +2498,13 @@ var eastAsianWidth = [][3]int{ {0x1F6D0, 0x1F6D2, prW}, // So [3] PLACE OF WORSHIP..SHOPPING TROLLEY {0x1F6D3, 0x1F6D4, prN}, // So [2] STUPA..PAGODA {0x1F6D5, 0x1F6D7, prW}, // So [3] HINDU TEMPLE..ELEVATOR - {0x1F6DC, 0x1F6DF, prW}, // So [4] WIRELESS..RING BUOY + {0x1F6DD, 0x1F6DF, prW}, // So [3] PLAYGROUND SLIDE..RING BUOY {0x1F6E0, 0x1F6EA, prN}, // So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE {0x1F6EB, 0x1F6EC, prW}, // So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING {0x1F6F0, 0x1F6F3, prN}, // So [4] SATELLITE..PASSENGER SHIP {0x1F6F4, 0x1F6FC, prW}, // So [9] SCOOTER..ROLLER SKATE - {0x1F700, 0x1F776, prN}, // So [119] ALCHEMICAL SYMBOL FOR QUINTESSENCE..LUNAR ECLIPSE - {0x1F77B, 0x1F77F, prN}, // So [5] HAUMEA..ORCUS - {0x1F780, 0x1F7D9, prN}, // So [90] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NINE POINTED WHITE STAR + {0x1F700, 0x1F773, prN}, // So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE + {0x1F780, 0x1F7D8, prN}, // So [89] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NEGATIVE CIRCLED SQUARE {0x1F7E0, 0x1F7EB, prW}, // So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE {0x1F7F0, 0x1F7F0, prW}, // So HEAVY EQUALS SIGN {0x1F800, 0x1F80B, prN}, // So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD @@ -2553,20 +2521,22 @@ var eastAsianWidth = [][3]int{ {0x1F947, 0x1F9FF, prW}, // So [185] FIRST PLACE MEDAL..NAZAR AMULET {0x1FA00, 0x1FA53, prN}, // So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP {0x1FA60, 0x1FA6D, prN}, // So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER - {0x1FA70, 0x1FA7C, prW}, // So [13] BALLET SHOES..CRUTCH - {0x1FA80, 0x1FA88, prW}, // So [9] YO-YO..FLUTE - {0x1FA90, 0x1FABD, prW}, // So [46] RINGED PLANET..WING - {0x1FABF, 0x1FAC5, prW}, // So [7] GOOSE..PERSON WITH CROWN - {0x1FACE, 0x1FADB, prW}, // So [14] MOOSE..PEA POD - {0x1FAE0, 0x1FAE8, prW}, // So [9] MELTING FACE..SHAKING FACE - {0x1FAF0, 0x1FAF8, prW}, // So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND + {0x1FA70, 0x1FA74, prW}, // So [5] BALLET SHOES..THONG SANDAL + {0x1FA78, 0x1FA7C, prW}, // So [5] DROP OF BLOOD..CRUTCH + {0x1FA80, 0x1FA86, prW}, // So [7] YO-YO..NESTING DOLLS + {0x1FA90, 0x1FAAC, prW}, // So [29] RINGED PLANET..HAMSA + {0x1FAB0, 0x1FABA, prW}, // So [11] FLY..NEST WITH EGGS + {0x1FAC0, 0x1FAC5, prW}, // So [6] ANATOMICAL HEART..PERSON WITH CROWN + {0x1FAD0, 0x1FAD9, prW}, // So [10] BLUEBERRIES..JAR + {0x1FAE0, 0x1FAE7, prW}, // So [8] MELTING FACE..BUBBLES + {0x1FAF0, 0x1FAF6, prW}, // So [7] HAND WITH INDEX FINGER AND THUMB CROSSED..HEART HANDS {0x1FB00, 0x1FB92, prN}, // So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK {0x1FB94, 0x1FBCA, prN}, // So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON {0x1FBF0, 0x1FBF9, prN}, // Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE {0x20000, 0x2A6DF, prW}, // Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF {0x2A6E0, 0x2A6FF, prW}, // Cn [32] .. - {0x2A700, 0x2B739, prW}, // Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 - {0x2B73A, 0x2B73F, prW}, // Cn [6] .. + {0x2A700, 0x2B738, prW}, // Lo [4153] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B738 + {0x2B739, 0x2B73F, prW}, // Cn [7] .. {0x2B740, 0x2B81D, prW}, // Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D {0x2B81E, 0x2B81F, prW}, // Cn [2] .. {0x2B820, 0x2CEA1, prW}, // Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 @@ -2577,9 +2547,7 @@ var eastAsianWidth = [][3]int{ {0x2FA1E, 0x2FA1F, prW}, // Cn [2] .. {0x2FA20, 0x2FFFD, prW}, // Cn [1502] .. {0x30000, 0x3134A, prW}, // Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A - {0x3134B, 0x3134F, prW}, // Cn [5] .. - {0x31350, 0x323AF, prW}, // Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF - {0x323B0, 0x3FFFD, prW}, // Cn [56398] .. + {0x3134B, 0x3FFFD, prW}, // Cn [60595] .. {0xE0001, 0xE0001, prN}, // Cf LANGUAGE TAG {0xE0020, 0xE007F, prN}, // Cf [96] TAG SPACE..CANCEL TAG {0xE0100, 0xE01EF, prA}, // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 diff --git a/vendor/github.com/rivo/uniseg/emojipresentation.go b/vendor/github.com/rivo/uniseg/emojipresentation.go index 9b5f499c..fd0f7451 100644 --- a/vendor/github.com/rivo/uniseg/emojipresentation.go +++ b/vendor/github.com/rivo/uniseg/emojipresentation.go @@ -1,13 +1,13 @@ -// Code generated via go generate from gen_properties.go. DO NOT EDIT. - package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. + // emojiPresentation are taken from // // and -// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt // ("Extended_Pictographic" only) -// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode +// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode // license agreement. var emojiPresentation = [][3]int{ {0x231A, 0x231B, prEmojiPresentation}, // E0.6 [2] (⌚..⌛) watch..hourglass done @@ -211,7 +211,6 @@ var emojiPresentation = [][3]int{ {0x1F6D1, 0x1F6D2, prEmojiPresentation}, // E3.0 [2] (🛑..🛒) stop sign..shopping cart {0x1F6D5, 0x1F6D5, prEmojiPresentation}, // E12.0 [1] (🛕) hindu temple {0x1F6D6, 0x1F6D7, prEmojiPresentation}, // E13.0 [2] (🛖..🛗) hut..elevator - {0x1F6DC, 0x1F6DC, prEmojiPresentation}, // E15.0 [1] (🛜) wireless {0x1F6DD, 0x1F6DF, prEmojiPresentation}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy {0x1F6EB, 0x1F6EC, prEmojiPresentation}, // E1.0 [2] (🛫..🛬) airplane departure..airplane arrival {0x1F6F4, 0x1F6F6, prEmojiPresentation}, // E3.0 [3] (🛴..🛶) kick scooter..canoe @@ -268,28 +267,19 @@ var emojiPresentation = [][3]int{ {0x1F9E7, 0x1F9FF, prEmojiPresentation}, // E11.0 [25] (🧧..🧿) red envelope..nazar amulet {0x1FA70, 0x1FA73, prEmojiPresentation}, // E12.0 [4] (🩰..🩳) ballet shoes..shorts {0x1FA74, 0x1FA74, prEmojiPresentation}, // E13.0 [1] (🩴) thong sandal - {0x1FA75, 0x1FA77, prEmojiPresentation}, // E15.0 [3] (🩵..🩷) light blue heart..pink heart {0x1FA78, 0x1FA7A, prEmojiPresentation}, // E12.0 [3] (🩸..🩺) drop of blood..stethoscope {0x1FA7B, 0x1FA7C, prEmojiPresentation}, // E14.0 [2] (🩻..🩼) x-ray..crutch {0x1FA80, 0x1FA82, prEmojiPresentation}, // E12.0 [3] (🪀..🪂) yo-yo..parachute {0x1FA83, 0x1FA86, prEmojiPresentation}, // E13.0 [4] (🪃..🪆) boomerang..nesting dolls - {0x1FA87, 0x1FA88, prEmojiPresentation}, // E15.0 [2] (🪇..🪈) maracas..flute {0x1FA90, 0x1FA95, prEmojiPresentation}, // E12.0 [6] (🪐..🪕) ringed planet..banjo {0x1FA96, 0x1FAA8, prEmojiPresentation}, // E13.0 [19] (🪖..🪨) military helmet..rock {0x1FAA9, 0x1FAAC, prEmojiPresentation}, // E14.0 [4] (🪩..🪬) mirror ball..hamsa - {0x1FAAD, 0x1FAAF, prEmojiPresentation}, // E15.0 [3] (🪭..🪯) folding hand fan..khanda {0x1FAB0, 0x1FAB6, prEmojiPresentation}, // E13.0 [7] (🪰..🪶) fly..feather {0x1FAB7, 0x1FABA, prEmojiPresentation}, // E14.0 [4] (🪷..🪺) lotus..nest with eggs - {0x1FABB, 0x1FABD, prEmojiPresentation}, // E15.0 [3] (🪻..🪽) hyacinth..wing - {0x1FABF, 0x1FABF, prEmojiPresentation}, // E15.0 [1] (🪿) goose {0x1FAC0, 0x1FAC2, prEmojiPresentation}, // E13.0 [3] (🫀..🫂) anatomical heart..people hugging {0x1FAC3, 0x1FAC5, prEmojiPresentation}, // E14.0 [3] (🫃..🫅) pregnant man..person with crown - {0x1FACE, 0x1FACF, prEmojiPresentation}, // E15.0 [2] (🫎..🫏) moose..donkey {0x1FAD0, 0x1FAD6, prEmojiPresentation}, // E13.0 [7] (🫐..🫖) blueberries..teapot {0x1FAD7, 0x1FAD9, prEmojiPresentation}, // E14.0 [3] (🫗..🫙) pouring liquid..jar - {0x1FADA, 0x1FADB, prEmojiPresentation}, // E15.0 [2] (🫚..🫛) ginger root..pea pod {0x1FAE0, 0x1FAE7, prEmojiPresentation}, // E14.0 [8] (🫠..🫧) melting face..bubbles - {0x1FAE8, 0x1FAE8, prEmojiPresentation}, // E15.0 [1] (🫨) shaking face {0x1FAF0, 0x1FAF6, prEmojiPresentation}, // E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands - {0x1FAF7, 0x1FAF8, prEmojiPresentation}, // E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand } diff --git a/vendor/github.com/rivo/uniseg/gen_breaktest.go b/vendor/github.com/rivo/uniseg/gen_breaktest.go index 6bfbeb5e..e613c4cd 100644 --- a/vendor/github.com/rivo/uniseg/gen_breaktest.go +++ b/vendor/github.com/rivo/uniseg/gen_breaktest.go @@ -32,7 +32,7 @@ import ( // We want to test against a specific version rather than the latest. When the // package is upgraded to a new version, change these to generate new tests. const ( - testCaseURL = `https://www.unicode.org/Public/15.0.0/ucd/auxiliary/%s.txt` + testCaseURL = `https://www.unicode.org/Public/14.0.0/ucd/auxiliary/%s.txt` ) func main() { @@ -76,9 +76,9 @@ func parse(url string) ([]byte, error) { buf := new(bytes.Buffer) buf.Grow(120 << 10) - buf.WriteString(`// Code generated via go generate from gen_breaktest.go. DO NOT EDIT. + buf.WriteString(`package uniseg -package uniseg +// Code generated via go generate from gen_breaktest.go. DO NOT EDIT. // ` + os.Args[3] + ` are Grapheme testcases taken from // ` + url + ` @@ -136,9 +136,7 @@ var ( // // E.g. for the input b="÷ 0020 × 0308 ÷ 1F1E6 ÷" // it will append -// -// "\u0020\u0308\U0001F1E6" -// +// "\u0020\u0308\U0001F1E6" // and "[][]rune{{0x0020,0x0308},{0x1F1E6},}" // to orig and exp respectively. // diff --git a/vendor/github.com/rivo/uniseg/gen_properties.go b/vendor/github.com/rivo/uniseg/gen_properties.go index 8992d2c5..999d5efd 100644 --- a/vendor/github.com/rivo/uniseg/gen_properties.go +++ b/vendor/github.com/rivo/uniseg/gen_properties.go @@ -41,8 +41,8 @@ import ( // We want to test against a specific version rather than the latest. When the // package is upgraded to a new version, change these to generate new tests. const ( - propertyURL = `https://www.unicode.org/Public/15.0.0/ucd/%s.txt` - emojiURL = `https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt` + propertyURL = `https://www.unicode.org/Public/14.0.0/ucd/%s.txt` + emojiURL = `https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt` ) // The regular expression for a line containing a code point range property. @@ -178,11 +178,6 @@ func parse(propertyURL, emojiProperty string, includeGeneralCategory bool) (stri } } - // Avoid overflow during binary search. - if len(properties) >= 1<<31 { - return "", errors.New("too many properties") - } - // Sort properties. sort.Slice(properties, func(i, j int) bool { left, _ := strconv.ParseUint(properties[i][0], 16, 64) @@ -205,9 +200,9 @@ func parse(propertyURL, emojiProperty string, includeGeneralCategory bool) (stri // ` + emojiURL + ` // ("Extended_Pictographic" only)` } - buf.WriteString(`// Code generated via go generate from gen_properties.go. DO NOT EDIT. + buf.WriteString(`package uniseg -package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. // ` + os.Args[3] + ` are taken from // ` + propertyURL + emojiComment + ` diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go index b12403d4..d5d4c09e 100644 --- a/vendor/github.com/rivo/uniseg/grapheme.go +++ b/vendor/github.com/rivo/uniseg/grapheme.go @@ -13,10 +13,9 @@ import "unicode/utf8" // well as boundary information and character width is available via the various // methods (see examples below). // -// This class basically wraps the [StepString] parser and provides a convenient -// interface to it. If you are only interested in some parts of this package's -// functionality, using the specialized functions starting with "First" is -// almost always faster. +// Using this class to iterate over a string is convenient but it is much slower +// than using this package's [Step] or [StepString] functions or any of the +// other specialized functions starting with "First". type Graphemes struct { // The original string. original string @@ -188,8 +187,8 @@ func ReverseString(s string) string { const shiftGraphemePropState = 4 // FirstGraphemeCluster returns the first grapheme cluster found in the given -// byte slice according to the rules of [Unicode Standard Annex #29, Grapheme -// Cluster Boundaries]. This function can be called continuously to extract all +// byte slice according to the rules of Unicode Standard Annex #29, Grapheme +// Cluster Boundaries. This function can be called continuously to extract all // grapheme clusters from a byte slice, as illustrated in the example below. // // If you don't know the current state, for example when calling the function @@ -210,8 +209,6 @@ const shiftGraphemePropState = 4 // While slightly less convenient than using the Graphemes class, this function // has much better performance and makes no allocations. It lends itself well to // large byte slices. -// -// [Unicode Standard Annex #29, Grapheme Cluster Boundaries]: http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { @@ -223,7 +220,7 @@ func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, new if len(b) <= length { // If we're already past the end, there is nothing else to parse. var prop int if state < 0 { - prop = propertyGraphemes(r) + prop = property(graphemeCodePoints, r) } else { prop = state >> shiftGraphemePropState } @@ -253,14 +250,16 @@ func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, new return b[:length], b[length:], width, state | (prop << shiftGraphemePropState) } - if firstProp == prExtendedPictographic { + if r == vs16 { + width = 2 + } else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL { + width += runeWidth(r, prop) + } else if firstProp == prExtendedPictographic { if r == vs15 { width = 1 - } else if r == vs16 { + } else { width = 2 } - } else if firstProp != prRegionalIndicator && firstProp != prL { - width += runeWidth(r, prop) } length += l @@ -283,7 +282,7 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, if len(str) <= length { // If we're already past the end, there is nothing else to parse. var prop int if state < 0 { - prop = propertyGraphemes(r) + prop = property(graphemeCodePoints, r) } else { prop = state >> shiftGraphemePropState } @@ -313,14 +312,16 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, return str[:length], str[length:], width, state | (prop << shiftGraphemePropState) } - if firstProp == prExtendedPictographic { + if r == vs16 { + width = 2 + } else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL { + width += runeWidth(r, prop) + } else if firstProp == prExtendedPictographic { if r == vs15 { width = 1 - } else if r == vs16 { + } else { width = 2 } - } else if firstProp != prRegionalIndicator && firstProp != prL { - width += runeWidth(r, prop) } length += l diff --git a/vendor/github.com/rivo/uniseg/graphemeproperties.go b/vendor/github.com/rivo/uniseg/graphemeproperties.go index 0aff4a61..a87d140b 100644 --- a/vendor/github.com/rivo/uniseg/graphemeproperties.go +++ b/vendor/github.com/rivo/uniseg/graphemeproperties.go @@ -1,13 +1,13 @@ -// Code generated via go generate from gen_properties.go. DO NOT EDIT. - package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. + // graphemeCodePoints are taken from -// https://www.unicode.org/Public/15.0.0/ucd/auxiliary/GraphemeBreakProperty.txt +// https://www.unicode.org/Public/14.0.0/ucd/auxiliary/GraphemeBreakProperty.txt // and -// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt // ("Extended_Pictographic" only) -// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode +// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode // license agreement. var graphemeCodePoints = [][3]int{ {0x0000, 0x0009, prControl}, // Cc [10] .. @@ -143,7 +143,6 @@ var graphemeCodePoints = [][3]int{ {0x0CCC, 0x0CCD, prExtend}, // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA {0x0CD5, 0x0CD6, prExtend}, // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK {0x0CE2, 0x0CE3, prExtend}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL - {0x0CF3, 0x0CF3, prSpacingMark}, // Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT {0x0D00, 0x0D01, prExtend}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU {0x0D02, 0x0D03, prSpacingMark}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA {0x0D3B, 0x0D3C, prExtend}, // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA @@ -173,7 +172,7 @@ var graphemeCodePoints = [][3]int{ {0x0EB1, 0x0EB1, prExtend}, // Mn LAO VOWEL SIGN MAI KAN {0x0EB3, 0x0EB3, prSpacingMark}, // Lo LAO VOWEL SIGN AM {0x0EB4, 0x0EBC, prExtend}, // Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO - {0x0EC8, 0x0ECE, prExtend}, // Mn [7] LAO TONE MAI EK..LAO YAMAKKAN + {0x0EC8, 0x0ECD, prExtend}, // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA {0x0F18, 0x0F19, prExtend}, // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS {0x0F35, 0x0F35, prExtend}, // Mn TIBETAN MARK NGAS BZUNG NYI ZLA {0x0F37, 0x0F37, prExtend}, // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS @@ -1337,7 +1336,6 @@ var graphemeCodePoints = [][3]int{ {0x10AE5, 0x10AE6, prExtend}, // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW {0x10D24, 0x10D27, prExtend}, // Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI {0x10EAB, 0x10EAC, prExtend}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK - {0x10EFD, 0x10EFF, prExtend}, // Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA {0x10F46, 0x10F50, prExtend}, // Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW {0x10F82, 0x10F85, prExtend}, // Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW {0x11000, 0x11000, prSpacingMark}, // Mc BRAHMI SIGN CANDRABINDU @@ -1377,7 +1375,6 @@ var graphemeCodePoints = [][3]int{ {0x11235, 0x11235, prSpacingMark}, // Mc KHOJKI SIGN VIRAMA {0x11236, 0x11237, prExtend}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA {0x1123E, 0x1123E, prExtend}, // Mn KHOJKI SIGN SUKUN - {0x11241, 0x11241, prExtend}, // Mn KHOJKI VOWEL SIGN VOCALIC R {0x112DF, 0x112DF, prExtend}, // Mn KHUDAWADI SIGN ANUSVARA {0x112E0, 0x112E2, prSpacingMark}, // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II {0x112E3, 0x112EA, prExtend}, // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA @@ -1497,18 +1494,7 @@ var graphemeCodePoints = [][3]int{ {0x11D97, 0x11D97, prExtend}, // Mn GUNJALA GONDI VIRAMA {0x11EF3, 0x11EF4, prExtend}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U {0x11EF5, 0x11EF6, prSpacingMark}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O - {0x11F00, 0x11F01, prExtend}, // Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA - {0x11F02, 0x11F02, prPrepend}, // Lo KAWI SIGN REPHA - {0x11F03, 0x11F03, prSpacingMark}, // Mc KAWI SIGN VISARGA - {0x11F34, 0x11F35, prSpacingMark}, // Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA - {0x11F36, 0x11F3A, prExtend}, // Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R - {0x11F3E, 0x11F3F, prSpacingMark}, // Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI - {0x11F40, 0x11F40, prExtend}, // Mn KAWI VOWEL SIGN EU - {0x11F41, 0x11F41, prSpacingMark}, // Mc KAWI SIGN KILLER - {0x11F42, 0x11F42, prExtend}, // Mn KAWI CONJOINER - {0x13430, 0x1343F, prControl}, // Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE - {0x13440, 0x13440, prExtend}, // Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY - {0x13447, 0x13455, prExtend}, // Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED + {0x13430, 0x13438, prControl}, // Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT {0x16AF0, 0x16AF4, prExtend}, // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE {0x16B30, 0x16B36, prExtend}, // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM {0x16F4F, 0x16F4F, prExtend}, // Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -1541,11 +1527,9 @@ var graphemeCodePoints = [][3]int{ {0x1E01B, 0x1E021, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI {0x1E023, 0x1E024, prExtend}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS {0x1E026, 0x1E02A, prExtend}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA - {0x1E08F, 0x1E08F, prExtend}, // Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I {0x1E130, 0x1E136, prExtend}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D {0x1E2AE, 0x1E2AE, prExtend}, // Mn TOTO SIGN RISING TONE {0x1E2EC, 0x1E2EF, prExtend}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI - {0x1E4EC, 0x1E4EF, prExtend}, // Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH {0x1E8D0, 0x1E8D6, prExtend}, // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS {0x1E944, 0x1E94A, prExtend}, // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA {0x1F000, 0x1F003, prExtendedPictographic}, // E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND @@ -1796,8 +1780,7 @@ var graphemeCodePoints = [][3]int{ {0x1F6D3, 0x1F6D4, prExtendedPictographic}, // E0.0 [2] (🛓..🛔) STUPA..PAGODA {0x1F6D5, 0x1F6D5, prExtendedPictographic}, // E12.0 [1] (🛕) hindu temple {0x1F6D6, 0x1F6D7, prExtendedPictographic}, // E13.0 [2] (🛖..🛗) hut..elevator - {0x1F6D8, 0x1F6DB, prExtendedPictographic}, // E0.0 [4] (🛘..🛛) .. - {0x1F6DC, 0x1F6DC, prExtendedPictographic}, // E15.0 [1] (🛜) wireless + {0x1F6D8, 0x1F6DC, prExtendedPictographic}, // E0.0 [5] (🛘..🛜) .. {0x1F6DD, 0x1F6DF, prExtendedPictographic}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy {0x1F6E0, 0x1F6E5, prExtendedPictographic}, // E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat {0x1F6E6, 0x1F6E8, prExtendedPictographic}, // E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE @@ -1814,7 +1797,7 @@ var graphemeCodePoints = [][3]int{ {0x1F6FA, 0x1F6FA, prExtendedPictographic}, // E12.0 [1] (🛺) auto rickshaw {0x1F6FB, 0x1F6FC, prExtendedPictographic}, // E13.0 [2] (🛻..🛼) pickup truck..roller skate {0x1F6FD, 0x1F6FF, prExtendedPictographic}, // E0.0 [3] (🛽..🛿) .. - {0x1F774, 0x1F77F, prExtendedPictographic}, // E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS + {0x1F774, 0x1F77F, prExtendedPictographic}, // E0.0 [12] (🝴..🝿) .. {0x1F7D5, 0x1F7DF, prExtendedPictographic}, // E0.0 [11] (🟕..🟟) CIRCLED TRIANGLE.. {0x1F7E0, 0x1F7EB, prExtendedPictographic}, // E12.0 [12] (🟠..🟫) orange circle..brown square {0x1F7EC, 0x1F7EF, prExtendedPictographic}, // E0.0 [4] (🟬..🟯) .. @@ -1873,37 +1856,30 @@ var graphemeCodePoints = [][3]int{ {0x1FA00, 0x1FA6F, prExtendedPictographic}, // E0.0 [112] (🨀..🩯) NEUTRAL CHESS KING.. {0x1FA70, 0x1FA73, prExtendedPictographic}, // E12.0 [4] (🩰..🩳) ballet shoes..shorts {0x1FA74, 0x1FA74, prExtendedPictographic}, // E13.0 [1] (🩴) thong sandal - {0x1FA75, 0x1FA77, prExtendedPictographic}, // E15.0 [3] (🩵..🩷) light blue heart..pink heart + {0x1FA75, 0x1FA77, prExtendedPictographic}, // E0.0 [3] (🩵..🩷) .. {0x1FA78, 0x1FA7A, prExtendedPictographic}, // E12.0 [3] (🩸..🩺) drop of blood..stethoscope {0x1FA7B, 0x1FA7C, prExtendedPictographic}, // E14.0 [2] (🩻..🩼) x-ray..crutch {0x1FA7D, 0x1FA7F, prExtendedPictographic}, // E0.0 [3] (🩽..🩿) .. {0x1FA80, 0x1FA82, prExtendedPictographic}, // E12.0 [3] (🪀..🪂) yo-yo..parachute {0x1FA83, 0x1FA86, prExtendedPictographic}, // E13.0 [4] (🪃..🪆) boomerang..nesting dolls - {0x1FA87, 0x1FA88, prExtendedPictographic}, // E15.0 [2] (🪇..🪈) maracas..flute - {0x1FA89, 0x1FA8F, prExtendedPictographic}, // E0.0 [7] (🪉..🪏) .. + {0x1FA87, 0x1FA8F, prExtendedPictographic}, // E0.0 [9] (🪇..🪏) .. {0x1FA90, 0x1FA95, prExtendedPictographic}, // E12.0 [6] (🪐..🪕) ringed planet..banjo {0x1FA96, 0x1FAA8, prExtendedPictographic}, // E13.0 [19] (🪖..🪨) military helmet..rock {0x1FAA9, 0x1FAAC, prExtendedPictographic}, // E14.0 [4] (🪩..🪬) mirror ball..hamsa - {0x1FAAD, 0x1FAAF, prExtendedPictographic}, // E15.0 [3] (🪭..🪯) folding hand fan..khanda + {0x1FAAD, 0x1FAAF, prExtendedPictographic}, // E0.0 [3] (🪭..🪯) .. {0x1FAB0, 0x1FAB6, prExtendedPictographic}, // E13.0 [7] (🪰..🪶) fly..feather {0x1FAB7, 0x1FABA, prExtendedPictographic}, // E14.0 [4] (🪷..🪺) lotus..nest with eggs - {0x1FABB, 0x1FABD, prExtendedPictographic}, // E15.0 [3] (🪻..🪽) hyacinth..wing - {0x1FABE, 0x1FABE, prExtendedPictographic}, // E0.0 [1] (🪾) - {0x1FABF, 0x1FABF, prExtendedPictographic}, // E15.0 [1] (🪿) goose + {0x1FABB, 0x1FABF, prExtendedPictographic}, // E0.0 [5] (🪻..🪿) .. {0x1FAC0, 0x1FAC2, prExtendedPictographic}, // E13.0 [3] (🫀..🫂) anatomical heart..people hugging {0x1FAC3, 0x1FAC5, prExtendedPictographic}, // E14.0 [3] (🫃..🫅) pregnant man..person with crown - {0x1FAC6, 0x1FACD, prExtendedPictographic}, // E0.0 [8] (🫆..🫍) .. - {0x1FACE, 0x1FACF, prExtendedPictographic}, // E15.0 [2] (🫎..🫏) moose..donkey + {0x1FAC6, 0x1FACF, prExtendedPictographic}, // E0.0 [10] (🫆..🫏) .. {0x1FAD0, 0x1FAD6, prExtendedPictographic}, // E13.0 [7] (🫐..🫖) blueberries..teapot {0x1FAD7, 0x1FAD9, prExtendedPictographic}, // E14.0 [3] (🫗..🫙) pouring liquid..jar - {0x1FADA, 0x1FADB, prExtendedPictographic}, // E15.0 [2] (🫚..🫛) ginger root..pea pod - {0x1FADC, 0x1FADF, prExtendedPictographic}, // E0.0 [4] (🫜..🫟) .. + {0x1FADA, 0x1FADF, prExtendedPictographic}, // E0.0 [6] (🫚..🫟) .. {0x1FAE0, 0x1FAE7, prExtendedPictographic}, // E14.0 [8] (🫠..🫧) melting face..bubbles - {0x1FAE8, 0x1FAE8, prExtendedPictographic}, // E15.0 [1] (🫨) shaking face - {0x1FAE9, 0x1FAEF, prExtendedPictographic}, // E0.0 [7] (🫩..🫯) .. + {0x1FAE8, 0x1FAEF, prExtendedPictographic}, // E0.0 [8] (🫨..🫯) .. {0x1FAF0, 0x1FAF6, prExtendedPictographic}, // E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands - {0x1FAF7, 0x1FAF8, prExtendedPictographic}, // E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand - {0x1FAF9, 0x1FAFF, prExtendedPictographic}, // E0.0 [7] (🫹..🫿) .. + {0x1FAF7, 0x1FAFF, prExtendedPictographic}, // E0.0 [9] (🫷..🫿) .. {0x1FC00, 0x1FFFD, prExtendedPictographic}, // E0.0[1022] (🰀..🿽) .. {0xE0000, 0xE0000, prControl}, // Cn {0xE0001, 0xE0001, prControl}, // Cf LANGUAGE TAG diff --git a/vendor/github.com/rivo/uniseg/graphemerules.go b/vendor/github.com/rivo/uniseg/graphemerules.go index 5d399d29..907b30bd 100644 --- a/vendor/github.com/rivo/uniseg/graphemerules.go +++ b/vendor/github.com/rivo/uniseg/graphemerules.go @@ -21,12 +21,11 @@ const ( grBoundary ) -// grTransitions implements the grapheme cluster parser's state transitions. -// Maps state and property to a new state, a breaking instruction, and rule -// number. The breaking instruction always refers to the boundary between the -// last and next code point. Returns negative values if no transition is found. +// The grapheme cluster parser's state transitions. Maps (state, property) to +// (new state, breaking instruction, rule number). The breaking instruction +// always refers to the boundary between the last and next code point. // -// This function is used as follows: +// This map is queried as follows: // // 1. Find specific state + specific property. Stop if found. // 2. Find specific state + any property. @@ -37,96 +36,59 @@ const ( // are equal. Stop. // 6. Assume grAny and grBoundary. // -// Unicode version 15.0.0. -func grTransitions(state, prop int) (newState int, newProp int, boundary int) { - // It turns out that using a big switch statement is much faster than using - // a map. - - switch uint64(state) | uint64(prop)<<32 { +// Unicode version 14.0.0. +var grTransitions = map[[2]int][3]int{ // GB5 - case grAny | prCR<<32: - return grCR, grBoundary, 50 - case grAny | prLF<<32: - return grControlLF, grBoundary, 50 - case grAny | prControl<<32: - return grControlLF, grBoundary, 50 + {grAny, prCR}: {grCR, grBoundary, 50}, + {grAny, prLF}: {grControlLF, grBoundary, 50}, + {grAny, prControl}: {grControlLF, grBoundary, 50}, // GB4 - case grCR | prAny<<32: - return grAny, grBoundary, 40 - case grControlLF | prAny<<32: - return grAny, grBoundary, 40 - - // GB3 - case grCR | prLF<<32: - return grControlLF, grNoBoundary, 30 - - // GB6 - case grAny | prL<<32: - return grL, grBoundary, 9990 - case grL | prL<<32: - return grL, grNoBoundary, 60 - case grL | prV<<32: - return grLVV, grNoBoundary, 60 - case grL | prLV<<32: - return grLVV, grNoBoundary, 60 - case grL | prLVT<<32: - return grLVTT, grNoBoundary, 60 - - // GB7 - case grAny | prLV<<32: - return grLVV, grBoundary, 9990 - case grAny | prV<<32: - return grLVV, grBoundary, 9990 - case grLVV | prV<<32: - return grLVV, grNoBoundary, 70 - case grLVV | prT<<32: - return grLVTT, grNoBoundary, 70 - - // GB8 - case grAny | prLVT<<32: - return grLVTT, grBoundary, 9990 - case grAny | prT<<32: - return grLVTT, grBoundary, 9990 - case grLVTT | prT<<32: - return grLVTT, grNoBoundary, 80 - - // GB9 - case grAny | prExtend<<32: - return grAny, grNoBoundary, 90 - case grAny | prZWJ<<32: - return grAny, grNoBoundary, 90 - - // GB9a - case grAny | prSpacingMark<<32: - return grAny, grNoBoundary, 91 - - // GB9b - case grAny | prPrepend<<32: - return grPrepend, grBoundary, 9990 - case grPrepend | prAny<<32: - return grAny, grNoBoundary, 92 - - // GB11 - case grAny | prExtendedPictographic<<32: - return grExtendedPictographic, grBoundary, 9990 - case grExtendedPictographic | prExtend<<32: - return grExtendedPictographic, grNoBoundary, 110 - case grExtendedPictographic | prZWJ<<32: - return grExtendedPictographicZWJ, grNoBoundary, 110 - case grExtendedPictographicZWJ | prExtendedPictographic<<32: - return grExtendedPictographic, grNoBoundary, 110 - - // GB12 / GB13 - case grAny | prRegionalIndicator<<32: - return grRIOdd, grBoundary, 9990 - case grRIOdd | prRegionalIndicator<<32: - return grRIEven, grNoBoundary, 120 - case grRIEven | prRegionalIndicator<<32: - return grRIOdd, grBoundary, 120 - default: - return -1, -1, -1 - } + {grCR, prAny}: {grAny, grBoundary, 40}, + {grControlLF, prAny}: {grAny, grBoundary, 40}, + + // GB3. + {grCR, prLF}: {grAny, grNoBoundary, 30}, + + // GB6. + {grAny, prL}: {grL, grBoundary, 9990}, + {grL, prL}: {grL, grNoBoundary, 60}, + {grL, prV}: {grLVV, grNoBoundary, 60}, + {grL, prLV}: {grLVV, grNoBoundary, 60}, + {grL, prLVT}: {grLVTT, grNoBoundary, 60}, + + // GB7. + {grAny, prLV}: {grLVV, grBoundary, 9990}, + {grAny, prV}: {grLVV, grBoundary, 9990}, + {grLVV, prV}: {grLVV, grNoBoundary, 70}, + {grLVV, prT}: {grLVTT, grNoBoundary, 70}, + + // GB8. + {grAny, prLVT}: {grLVTT, grBoundary, 9990}, + {grAny, prT}: {grLVTT, grBoundary, 9990}, + {grLVTT, prT}: {grLVTT, grNoBoundary, 80}, + + // GB9. + {grAny, prExtend}: {grAny, grNoBoundary, 90}, + {grAny, prZWJ}: {grAny, grNoBoundary, 90}, + + // GB9a. + {grAny, prSpacingMark}: {grAny, grNoBoundary, 91}, + + // GB9b. + {grAny, prPrepend}: {grPrepend, grBoundary, 9990}, + {grPrepend, prAny}: {grAny, grNoBoundary, 92}, + + // GB11. + {grAny, prExtendedPictographic}: {grExtendedPictographic, grBoundary, 9990}, + {grExtendedPictographic, prExtend}: {grExtendedPictographic, grNoBoundary, 110}, + {grExtendedPictographic, prZWJ}: {grExtendedPictographicZWJ, grNoBoundary, 110}, + {grExtendedPictographicZWJ, prExtendedPictographic}: {grExtendedPictographic, grNoBoundary, 110}, + + // GB12 / GB13. + {grAny, prRegionalIndicator}: {grRIOdd, grBoundary, 9990}, + {grRIOdd, prRegionalIndicator}: {grRIEven, grNoBoundary, 120}, + {grRIEven, prRegionalIndicator}: {grRIOdd, grBoundary, 120}, } // transitionGraphemeState determines the new state of the grapheme cluster @@ -135,40 +97,40 @@ func grTransitions(state, prop int) (newState int, newProp int, boundary int) { // table) and whether a cluster boundary was detected. func transitionGraphemeState(state int, r rune) (newState, prop int, boundary bool) { // Determine the property of the next character. - prop = propertyGraphemes(r) + prop = property(graphemeCodePoints, r) // Find the applicable transition. - nextState, nextProp, _ := grTransitions(state, prop) - if nextState >= 0 { + transition, ok := grTransitions[[2]int{state, prop}] + if ok { // We have a specific transition. We'll use it. - return nextState, prop, nextProp == grBoundary + return transition[0], prop, transition[1] == grBoundary } // No specific transition found. Try the less specific ones. - anyPropState, anyPropProp, anyPropRule := grTransitions(state, prAny) - anyStateState, anyStateProp, anyStateRule := grTransitions(grAny, prop) - if anyPropState >= 0 && anyStateState >= 0 { + transAnyProp, okAnyProp := grTransitions[[2]int{state, prAny}] + transAnyState, okAnyState := grTransitions[[2]int{grAny, prop}] + if okAnyProp && okAnyState { // Both apply. We'll use a mix (see comments for grTransitions). - newState = anyStateState - boundary = anyStateProp == grBoundary - if anyPropRule < anyStateRule { - boundary = anyPropProp == grBoundary + newState = transAnyState[0] + boundary = transAnyState[1] == grBoundary + if transAnyProp[2] < transAnyState[2] { + boundary = transAnyProp[1] == grBoundary } return } - if anyPropState >= 0 { + if okAnyProp { // We only have a specific state. - return anyPropState, prop, anyPropProp == grBoundary + return transAnyProp[0], prop, transAnyProp[1] == grBoundary // This branch will probably never be reached because okAnyState will // always be true given the current transition map. But we keep it here // for future modifications to the transition map where this may not be // true anymore. } - if anyStateState >= 0 { + if okAnyState { // We only have a specific property. - return anyStateState, prop, anyStateProp == grBoundary + return transAnyState[0], prop, transAnyState[1] == grBoundary } // No known transition. GB999: Any ÷ Any. diff --git a/vendor/github.com/rivo/uniseg/line.go b/vendor/github.com/rivo/uniseg/line.go index 7a46318d..c0398cac 100644 --- a/vendor/github.com/rivo/uniseg/line.go +++ b/vendor/github.com/rivo/uniseg/line.go @@ -4,7 +4,7 @@ import "unicode/utf8" // FirstLineSegment returns the prefix of the given byte slice after which a // decision to break the string over to the next line can or must be made, -// according to the rules of [Unicode Standard Annex #14]. This is used to +// according to the rules of Unicode Standard Annex #14. This is used to // implement line breaking. // // Line breaking, also known as word wrapping, is the process of breaking a @@ -35,7 +35,7 @@ import "unicode/utf8" // // Given an empty byte slice "b", the function returns nil values. // -// Note that in accordance with [UAX #14 LB3], the final segment will end with +// Note that in accordance with UAX #14 LB3, the final segment will end with // "mustBreak" set to true. You can choose to ignore this by checking if the // length of the "rest" slice is 0 and calling [HasTrailingLineBreak] or // [HasTrailingLineBreakInString] on the last rune. @@ -43,9 +43,6 @@ import "unicode/utf8" // Note also that this algorithm may break within grapheme clusters. This is // addressed in Section 8.2 Example 6 of UAX #14. To avoid this, you can use // the [Step] function instead. -// -// [Unicode Standard Annex #14]: https://www.unicode.org/reports/tr14/ -// [UAX #14 LB3]: https://www.unicode.org/reports/tr14/#Algorithm func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { @@ -80,7 +77,7 @@ func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool } } -// FirstLineSegmentInString is like [FirstLineSegment] but its input and outputs +// FirstLineSegmentInString is like FirstLineSegment() but its input and outputs // are strings. func FirstLineSegmentInString(str string, state int) (segment, rest string, mustBreak bool, newState int) { // An empty byte slice returns nothing. @@ -122,13 +119,13 @@ func FirstLineSegmentInString(str string, state int) (segment, rest string, must // [UAX #14]: https://www.unicode.org/reports/tr14/#Algorithm func HasTrailingLineBreak(b []byte) bool { r, _ := utf8.DecodeLastRune(b) - property, _ := propertyLineBreak(r) - return property == prBK || property == prCR || property == prLF || property == prNL + property, _ := propertyWithGenCat(lineBreakCodePoints, r) + return property == lbBK || property == lbCR || property == lbLF || property == lbNL } // HasTrailingLineBreakInString is like [HasTrailingLineBreak] but for a string. func HasTrailingLineBreakInString(str string) bool { r, _ := utf8.DecodeLastRuneInString(str) - property, _ := propertyLineBreak(r) - return property == prBK || property == prCR || property == prLF || property == prNL + property, _ := propertyWithGenCat(lineBreakCodePoints, r) + return property == lbBK || property == lbCR || property == lbLF || property == lbNL } diff --git a/vendor/github.com/rivo/uniseg/lineproperties.go b/vendor/github.com/rivo/uniseg/lineproperties.go index ac7fac4c..32169306 100644 --- a/vendor/github.com/rivo/uniseg/lineproperties.go +++ b/vendor/github.com/rivo/uniseg/lineproperties.go @@ -1,13 +1,13 @@ -// Code generated via go generate from gen_properties.go. DO NOT EDIT. - package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. + // lineBreakCodePoints are taken from -// https://www.unicode.org/Public/15.0.0/ucd/LineBreak.txt +// https://www.unicode.org/Public/14.0.0/ucd/LineBreak.txt // and -// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt // ("Extended_Pictographic" only) -// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode +// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode // license agreement. var lineBreakCodePoints = [][4]int{ {0x0000, 0x0008, prCM, gcCc}, // [9] .. @@ -439,7 +439,6 @@ var lineBreakCodePoints = [][4]int{ {0x0CE2, 0x0CE3, prCM, gcMn}, // [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL {0x0CE6, 0x0CEF, prNU, gcNd}, // [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE {0x0CF1, 0x0CF2, prAL, gcLo}, // [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA - {0x0CF3, 0x0CF3, prCM, gcMc}, // KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT {0x0D00, 0x0D01, prCM, gcMn}, // [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU {0x0D02, 0x0D03, prCM, gcMc}, // [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA {0x0D04, 0x0D0C, prAL, gcLo}, // [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L @@ -501,7 +500,7 @@ var lineBreakCodePoints = [][4]int{ {0x0EBD, 0x0EBD, prSA, gcLo}, // LAO SEMIVOWEL SIGN NYO {0x0EC0, 0x0EC4, prSA, gcLo}, // [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI {0x0EC6, 0x0EC6, prSA, gcLm}, // LAO KO LA - {0x0EC8, 0x0ECE, prSA, gcMn}, // [7] LAO TONE MAI EK..LAO YAMAKKAN + {0x0EC8, 0x0ECD, prSA, gcMn}, // [6] LAO TONE MAI EK..LAO NIGGAHITA {0x0ED0, 0x0ED9, prNU, gcNd}, // [10] LAO DIGIT ZERO..LAO DIGIT NINE {0x0EDC, 0x0EDF, prSA, gcLo}, // [4] LAO HO NO..LAO LETTER KHMU NYO {0x0F00, 0x0F00, prAL, gcLo}, // TIBETAN SYLLABLE OM @@ -814,11 +813,7 @@ var lineBreakCodePoints = [][4]int{ {0x1D79, 0x1D7F, prAL, gcLl}, // [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE {0x1D80, 0x1D9A, prAL, gcLl}, // [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK {0x1D9B, 0x1DBF, prAL, gcLm}, // [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA - {0x1DC0, 0x1DCC, prCM, gcMn}, // [13] COMBINING DOTTED GRAVE ACCENT..COMBINING MACRON-BREVE - {0x1DCD, 0x1DCD, prGL, gcMn}, // COMBINING DOUBLE CIRCUMFLEX ABOVE - {0x1DCE, 0x1DFB, prCM, gcMn}, // [46] COMBINING OGONEK ABOVE..COMBINING DELETION MARK - {0x1DFC, 0x1DFC, prGL, gcMn}, // COMBINING DOUBLE INVERTED BREVE BELOW - {0x1DFD, 0x1DFF, prCM, gcMn}, // [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW + {0x1DC0, 0x1DFF, prCM, gcMn}, // [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW {0x1E00, 0x1EFF, prAL, gcLC}, // [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP {0x1F00, 0x1F15, prAL, gcLC}, // [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA {0x1F18, 0x1F1D, prAL, gcLu}, // [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA @@ -894,7 +889,7 @@ var lineBreakCodePoints = [][4]int{ {0x2054, 0x2054, prAL, gcPc}, // INVERTED UNDERTIE {0x2055, 0x2055, prAL, gcPo}, // FLOWER PUNCTUATION MARK {0x2056, 0x2056, prBA, gcPo}, // THREE DOT PUNCTUATION - {0x2057, 0x2057, prPO, gcPo}, // QUADRUPLE PRIME + {0x2057, 0x2057, prAL, gcPo}, // QUADRUPLE PRIME {0x2058, 0x205B, prBA, gcPo}, // [4] FOUR DOT PUNCTUATION..FOUR DOT MARK {0x205C, 0x205C, prAL, gcPo}, // DOTTED CROSS {0x205D, 0x205E, prBA, gcPo}, // [2] TRICOLON..VERTICAL FOUR DOTS @@ -2756,7 +2751,6 @@ var lineBreakCodePoints = [][4]int{ {0x10EAB, 0x10EAC, prCM, gcMn}, // [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK {0x10EAD, 0x10EAD, prBA, gcPd}, // YEZIDI HYPHENATION MARK {0x10EB0, 0x10EB1, prAL, gcLo}, // [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE - {0x10EFD, 0x10EFF, prCM, gcMn}, // [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA {0x10F00, 0x10F1C, prAL, gcLo}, // [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL {0x10F1D, 0x10F26, prAL, gcNo}, // [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF {0x10F27, 0x10F27, prAL, gcLo}, // OLD SOGDIAN LIGATURE AYIN-DALETH @@ -2846,8 +2840,6 @@ var lineBreakCodePoints = [][4]int{ {0x1123B, 0x1123C, prBA, gcPo}, // [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK {0x1123D, 0x1123D, prAL, gcPo}, // KHOJKI ABBREVIATION SIGN {0x1123E, 0x1123E, prCM, gcMn}, // KHOJKI SIGN SUKUN - {0x1123F, 0x11240, prAL, gcLo}, // [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I - {0x11241, 0x11241, prCM, gcMn}, // KHOJKI VOWEL SIGN VOCALIC R {0x11280, 0x11286, prAL, gcLo}, // [7] MULTANI LETTER A..MULTANI LETTER GA {0x11288, 0x11288, prAL, gcLo}, // MULTANI LETTER GHA {0x1128A, 0x1128D, prAL, gcLo}, // [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -3021,7 +3013,6 @@ var lineBreakCodePoints = [][4]int{ {0x11AA1, 0x11AA2, prBA, gcPo}, // [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2 {0x11AB0, 0x11ABF, prAL, gcLo}, // [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA {0x11AC0, 0x11AF8, prAL, gcLo}, // [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL - {0x11B00, 0x11B09, prBB, gcPo}, // [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU {0x11C00, 0x11C08, prAL, gcLo}, // [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L {0x11C0A, 0x11C2E, prAL, gcLo}, // [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA {0x11C2F, 0x11C2F, prCM, gcMc}, // BHAIKSUKI VOWEL SIGN AA @@ -3068,20 +3059,6 @@ var lineBreakCodePoints = [][4]int{ {0x11EF3, 0x11EF4, prCM, gcMn}, // [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U {0x11EF5, 0x11EF6, prCM, gcMc}, // [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O {0x11EF7, 0x11EF8, prAL, gcPo}, // [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION - {0x11F00, 0x11F01, prCM, gcMn}, // [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA - {0x11F02, 0x11F02, prAL, gcLo}, // KAWI SIGN REPHA - {0x11F03, 0x11F03, prCM, gcMc}, // KAWI SIGN VISARGA - {0x11F04, 0x11F10, prAL, gcLo}, // [13] KAWI LETTER A..KAWI LETTER O - {0x11F12, 0x11F33, prAL, gcLo}, // [34] KAWI LETTER KA..KAWI LETTER JNYA - {0x11F34, 0x11F35, prCM, gcMc}, // [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA - {0x11F36, 0x11F3A, prCM, gcMn}, // [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R - {0x11F3E, 0x11F3F, prCM, gcMc}, // [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI - {0x11F40, 0x11F40, prCM, gcMn}, // KAWI VOWEL SIGN EU - {0x11F41, 0x11F41, prCM, gcMc}, // KAWI SIGN KILLER - {0x11F42, 0x11F42, prCM, gcMn}, // KAWI CONJOINER - {0x11F43, 0x11F44, prBA, gcPo}, // [2] KAWI DANDA..KAWI DOUBLE DANDA - {0x11F45, 0x11F4F, prID, gcPo}, // [11] KAWI PUNCTUATION SECTION MARKER..KAWI PUNCTUATION CLOSING SPIRAL - {0x11F50, 0x11F59, prNU, gcNd}, // [10] KAWI DIGIT ZERO..KAWI DIGIT NINE {0x11FB0, 0x11FB0, prAL, gcLo}, // LISU LETTER YHA {0x11FC0, 0x11FD4, prAL, gcNo}, // [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH {0x11FD5, 0x11FDC, prAL, gcSo}, // [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI @@ -3107,18 +3084,10 @@ var lineBreakCodePoints = [][4]int{ {0x1328A, 0x13378, prAL, gcLo}, // [239] EGYPTIAN HIEROGLYPH O037..EGYPTIAN HIEROGLYPH V011 {0x13379, 0x13379, prOP, gcLo}, // EGYPTIAN HIEROGLYPH V011A {0x1337A, 0x1337B, prCL, gcLo}, // [2] EGYPTIAN HIEROGLYPH V011B..EGYPTIAN HIEROGLYPH V011C - {0x1337C, 0x1342F, prAL, gcLo}, // [180] EGYPTIAN HIEROGLYPH V012..EGYPTIAN HIEROGLYPH V011D + {0x1337C, 0x1342E, prAL, gcLo}, // [179] EGYPTIAN HIEROGLYPH V012..EGYPTIAN HIEROGLYPH AA032 {0x13430, 0x13436, prGL, gcCf}, // [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE {0x13437, 0x13437, prOP, gcCf}, // EGYPTIAN HIEROGLYPH BEGIN SEGMENT {0x13438, 0x13438, prCL, gcCf}, // EGYPTIAN HIEROGLYPH END SEGMENT - {0x13439, 0x1343B, prGL, gcCf}, // [3] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH INSERT AT BOTTOM - {0x1343C, 0x1343C, prOP, gcCf}, // EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE - {0x1343D, 0x1343D, prCL, gcCf}, // EGYPTIAN HIEROGLYPH END ENCLOSURE - {0x1343E, 0x1343E, prOP, gcCf}, // EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE - {0x1343F, 0x1343F, prCL, gcCf}, // EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE - {0x13440, 0x13440, prCM, gcMn}, // EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY - {0x13441, 0x13446, prAL, gcLo}, // [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN - {0x13447, 0x13455, prCM, gcMn}, // [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED {0x14400, 0x145CD, prAL, gcLo}, // [462] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A409 {0x145CE, 0x145CE, prOP, gcLo}, // ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK {0x145CF, 0x145CF, prCL, gcLo}, // ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK @@ -3168,9 +3137,7 @@ var lineBreakCodePoints = [][4]int{ {0x1AFFD, 0x1AFFE, prAL, gcLm}, // [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 {0x1B000, 0x1B0FF, prID, gcLo}, // [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 {0x1B100, 0x1B122, prID, gcLo}, // [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU - {0x1B132, 0x1B132, prCJ, gcLo}, // HIRAGANA LETTER SMALL KO {0x1B150, 0x1B152, prCJ, gcLo}, // [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO - {0x1B155, 0x1B155, prCJ, gcLo}, // KATAKANA LETTER SMALL KO {0x1B164, 0x1B167, prCJ, gcLo}, // [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N {0x1B170, 0x1B2FB, prID, gcLo}, // [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB {0x1BC00, 0x1BC6A, prAL, gcLo}, // [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M @@ -3201,7 +3168,6 @@ var lineBreakCodePoints = [][4]int{ {0x1D200, 0x1D241, prAL, gcSo}, // [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 {0x1D242, 0x1D244, prCM, gcMn}, // [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME {0x1D245, 0x1D245, prAL, gcSo}, // GREEK MUSICAL LEIMMA - {0x1D2C0, 0x1D2D3, prAL, gcNo}, // [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN {0x1D2E0, 0x1D2F3, prAL, gcNo}, // [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN {0x1D300, 0x1D356, prAL, gcSo}, // [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING {0x1D360, 0x1D378, prAL, gcNo}, // [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE @@ -3262,14 +3228,11 @@ var lineBreakCodePoints = [][4]int{ {0x1DF00, 0x1DF09, prAL, gcLl}, // [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK {0x1DF0A, 0x1DF0A, prAL, gcLo}, // LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK {0x1DF0B, 0x1DF1E, prAL, gcLl}, // [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL - {0x1DF25, 0x1DF2A, prAL, gcLl}, // [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK {0x1E000, 0x1E006, prCM, gcMn}, // [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE {0x1E008, 0x1E018, prCM, gcMn}, // [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU {0x1E01B, 0x1E021, prCM, gcMn}, // [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI {0x1E023, 0x1E024, prCM, gcMn}, // [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS {0x1E026, 0x1E02A, prCM, gcMn}, // [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA - {0x1E030, 0x1E06D, prAL, gcLm}, // [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE - {0x1E08F, 0x1E08F, prCM, gcMn}, // COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I {0x1E100, 0x1E12C, prAL, gcLo}, // [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W {0x1E130, 0x1E136, prCM, gcMn}, // [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D {0x1E137, 0x1E13D, prAL, gcLm}, // [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER @@ -3282,10 +3245,6 @@ var lineBreakCodePoints = [][4]int{ {0x1E2EC, 0x1E2EF, prCM, gcMn}, // [4] WANCHO TONE TUP..WANCHO TONE KOINI {0x1E2F0, 0x1E2F9, prNU, gcNd}, // [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE {0x1E2FF, 0x1E2FF, prPR, gcSc}, // WANCHO NGUN SIGN - {0x1E4D0, 0x1E4EA, prAL, gcLo}, // [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL - {0x1E4EB, 0x1E4EB, prAL, gcLm}, // NAG MUNDARI SIGN OJOD - {0x1E4EC, 0x1E4EF, prCM, gcMn}, // [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH - {0x1E4F0, 0x1E4F9, prNU, gcNd}, // [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE {0x1E7E0, 0x1E7E6, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO {0x1E7E8, 0x1E7EB, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE {0x1E7ED, 0x1E7EE, prAL, gcLo}, // [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -3453,18 +3412,16 @@ var lineBreakCodePoints = [][4]int{ {0x1F6C1, 0x1F6CB, prID, gcSo}, // [11] BATHTUB..COUCH AND LAMP {0x1F6CC, 0x1F6CC, prEB, gcSo}, // SLEEPING ACCOMMODATION {0x1F6CD, 0x1F6D7, prID, gcSo}, // [11] SHOPPING BAGS..ELEVATOR - {0x1F6D8, 0x1F6DB, prID, gcCn}, // [4] .. - {0x1F6DC, 0x1F6EC, prID, gcSo}, // [17] WIRELESS..AIRPLANE ARRIVING + {0x1F6D8, 0x1F6DC, prID, gcCn}, // [5] .. + {0x1F6DD, 0x1F6EC, prID, gcSo}, // [16] PLAYGROUND SLIDE..AIRPLANE ARRIVING {0x1F6ED, 0x1F6EF, prID, gcCn}, // [3] .. {0x1F6F0, 0x1F6FC, prID, gcSo}, // [13] SATELLITE..ROLLER SKATE {0x1F6FD, 0x1F6FF, prID, gcCn}, // [3] .. {0x1F700, 0x1F773, prAL, gcSo}, // [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE - {0x1F774, 0x1F776, prID, gcSo}, // [3] LOT OF FORTUNE..LUNAR ECLIPSE - {0x1F777, 0x1F77A, prID, gcCn}, // [4] .. - {0x1F77B, 0x1F77F, prID, gcSo}, // [5] HAUMEA..ORCUS + {0x1F774, 0x1F77F, prID, gcCn}, // [12] .. {0x1F780, 0x1F7D4, prAL, gcSo}, // [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR - {0x1F7D5, 0x1F7D9, prID, gcSo}, // [5] CIRCLED TRIANGLE..NINE POINTED WHITE STAR - {0x1F7DA, 0x1F7DF, prID, gcCn}, // [6] .. + {0x1F7D5, 0x1F7D8, prID, gcSo}, // [4] CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE + {0x1F7D9, 0x1F7DF, prID, gcCn}, // [7] .. {0x1F7E0, 0x1F7EB, prID, gcSo}, // [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE {0x1F7EC, 0x1F7EF, prID, gcCn}, // [4] .. {0x1F7F0, 0x1F7F0, prID, gcSo}, // HEAVY EQUALS SIGN @@ -3510,29 +3467,33 @@ var lineBreakCodePoints = [][4]int{ {0x1FA54, 0x1FA5F, prID, gcCn}, // [12] .. {0x1FA60, 0x1FA6D, prID, gcSo}, // [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER {0x1FA6E, 0x1FA6F, prID, gcCn}, // [2] .. - {0x1FA70, 0x1FA7C, prID, gcSo}, // [13] BALLET SHOES..CRUTCH + {0x1FA70, 0x1FA74, prID, gcSo}, // [5] BALLET SHOES..THONG SANDAL + {0x1FA75, 0x1FA77, prID, gcCn}, // [3] .. + {0x1FA78, 0x1FA7C, prID, gcSo}, // [5] DROP OF BLOOD..CRUTCH {0x1FA7D, 0x1FA7F, prID, gcCn}, // [3] .. - {0x1FA80, 0x1FA88, prID, gcSo}, // [9] YO-YO..FLUTE - {0x1FA89, 0x1FA8F, prID, gcCn}, // [7] .. - {0x1FA90, 0x1FABD, prID, gcSo}, // [46] RINGED PLANET..WING - {0x1FABE, 0x1FABE, prID, gcCn}, // - {0x1FABF, 0x1FAC2, prID, gcSo}, // [4] GOOSE..PEOPLE HUGGING + {0x1FA80, 0x1FA86, prID, gcSo}, // [7] YO-YO..NESTING DOLLS + {0x1FA87, 0x1FA8F, prID, gcCn}, // [9] .. + {0x1FA90, 0x1FAAC, prID, gcSo}, // [29] RINGED PLANET..HAMSA + {0x1FAAD, 0x1FAAF, prID, gcCn}, // [3] .. + {0x1FAB0, 0x1FABA, prID, gcSo}, // [11] FLY..NEST WITH EGGS + {0x1FABB, 0x1FABF, prID, gcCn}, // [5] .. + {0x1FAC0, 0x1FAC2, prID, gcSo}, // [3] ANATOMICAL HEART..PEOPLE HUGGING {0x1FAC3, 0x1FAC5, prEB, gcSo}, // [3] PREGNANT MAN..PERSON WITH CROWN - {0x1FAC6, 0x1FACD, prID, gcCn}, // [8] .. - {0x1FACE, 0x1FADB, prID, gcSo}, // [14] MOOSE..PEA POD - {0x1FADC, 0x1FADF, prID, gcCn}, // [4] .. - {0x1FAE0, 0x1FAE8, prID, gcSo}, // [9] MELTING FACE..SHAKING FACE - {0x1FAE9, 0x1FAEF, prID, gcCn}, // [7] .. - {0x1FAF0, 0x1FAF8, prEB, gcSo}, // [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND - {0x1FAF9, 0x1FAFF, prID, gcCn}, // [7] .. + {0x1FAC6, 0x1FACF, prID, gcCn}, // [10] .. + {0x1FAD0, 0x1FAD9, prID, gcSo}, // [10] BLUEBERRIES..JAR + {0x1FADA, 0x1FADF, prID, gcCn}, // [6] .. + {0x1FAE0, 0x1FAE7, prID, gcSo}, // [8] MELTING FACE..BUBBLES + {0x1FAE8, 0x1FAEF, prID, gcCn}, // [8] .. + {0x1FAF0, 0x1FAF6, prEB, gcSo}, // [7] HAND WITH INDEX FINGER AND THUMB CROSSED..HEART HANDS + {0x1FAF7, 0x1FAFF, prID, gcCn}, // [9] .. {0x1FB00, 0x1FB92, prAL, gcSo}, // [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK {0x1FB94, 0x1FBCA, prAL, gcSo}, // [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON {0x1FBF0, 0x1FBF9, prNU, gcNd}, // [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE {0x1FC00, 0x1FFFD, prID, gcCn}, // [1022] .. {0x20000, 0x2A6DF, prID, gcLo}, // [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF {0x2A6E0, 0x2A6FF, prID, gcCn}, // [32] .. - {0x2A700, 0x2B739, prID, gcLo}, // [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 - {0x2B73A, 0x2B73F, prID, gcCn}, // [6] .. + {0x2A700, 0x2B738, prID, gcLo}, // [4153] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B738 + {0x2B739, 0x2B73F, prID, gcCn}, // [7] .. {0x2B740, 0x2B81D, prID, gcLo}, // [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D {0x2B81E, 0x2B81F, prID, gcCn}, // [2] .. {0x2B820, 0x2CEA1, prID, gcLo}, // [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 @@ -3543,9 +3504,7 @@ var lineBreakCodePoints = [][4]int{ {0x2FA1E, 0x2FA1F, prID, gcCn}, // [2] .. {0x2FA20, 0x2FFFD, prID, gcCn}, // [1502] .. {0x30000, 0x3134A, prID, gcLo}, // [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A - {0x3134B, 0x3134F, prID, gcCn}, // [5] .. - {0x31350, 0x323AF, prID, gcLo}, // [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF - {0x323B0, 0x3FFFD, prID, gcCn}, // [56398] .. + {0x3134B, 0x3FFFD, prID, gcCn}, // [60595] .. {0xE0001, 0xE0001, prCM, gcCf}, // LANGUAGE TAG {0xE0020, 0xE007F, prCM, gcCf}, // [96] TAG SPACE..CANCEL TAG {0xE0100, 0xE01EF, prCM, gcMn}, // [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 diff --git a/vendor/github.com/rivo/uniseg/linerules.go b/vendor/github.com/rivo/uniseg/linerules.go index 7708ae0f..d2ad5168 100644 --- a/vendor/github.com/rivo/uniseg/linerules.go +++ b/vendor/github.com/rivo/uniseg/linerules.go @@ -64,381 +64,222 @@ const ( LineMustBreak // You must break the line here. ) -// lbTransitions implements the line break parser's state transitions. It's -// anologous to [grTransitions], see comments there for details. -// -// Unicode version 15.0.0. -func lbTransitions(state, prop int) (newState, lineBreak, rule int) { - switch uint64(state) | uint64(prop)<<32 { +// The line break parser's state transitions. It's anologous to grTransitions, +// see comments there for details. Unicode version 14.0.0. +var lbTransitions = map[[2]int][3]int{ // LB4. - case lbBK | prAny<<32: - return lbAny, LineMustBreak, 40 + {lbAny, prBK}: {lbBK, LineCanBreak, 310}, + {lbBK, prAny}: {lbAny, LineMustBreak, 40}, // LB5. - case lbCR | prLF<<32: - return lbLF, LineDontBreak, 50 - case lbCR | prAny<<32: - return lbAny, LineMustBreak, 50 - case lbLF | prAny<<32: - return lbAny, LineMustBreak, 50 - case lbNL | prAny<<32: - return lbAny, LineMustBreak, 50 + {lbAny, prCR}: {lbCR, LineCanBreak, 310}, + {lbAny, prLF}: {lbLF, LineCanBreak, 310}, + {lbAny, prNL}: {lbNL, LineCanBreak, 310}, + {lbCR, prLF}: {lbLF, LineDontBreak, 50}, + {lbCR, prAny}: {lbAny, LineMustBreak, 50}, + {lbLF, prAny}: {lbAny, LineMustBreak, 50}, + {lbNL, prAny}: {lbAny, LineMustBreak, 50}, // LB6. - case lbAny | prBK<<32: - return lbBK, LineDontBreak, 60 - case lbAny | prCR<<32: - return lbCR, LineDontBreak, 60 - case lbAny | prLF<<32: - return lbLF, LineDontBreak, 60 - case lbAny | prNL<<32: - return lbNL, LineDontBreak, 60 + {lbAny, prBK}: {lbBK, LineDontBreak, 60}, + {lbAny, prCR}: {lbCR, LineDontBreak, 60}, + {lbAny, prLF}: {lbLF, LineDontBreak, 60}, + {lbAny, prNL}: {lbNL, LineDontBreak, 60}, // LB7. - case lbAny | prSP<<32: - return lbSP, LineDontBreak, 70 - case lbAny | prZW<<32: - return lbZW, LineDontBreak, 70 + {lbAny, prSP}: {lbSP, LineDontBreak, 70}, + {lbAny, prZW}: {lbZW, LineDontBreak, 70}, // LB8. - case lbZW | prSP<<32: - return lbZW, LineDontBreak, 70 - case lbZW | prAny<<32: - return lbAny, LineCanBreak, 80 + {lbZW, prSP}: {lbZW, LineDontBreak, 70}, + {lbZW, prAny}: {lbAny, LineCanBreak, 80}, // LB11. - case lbAny | prWJ<<32: - return lbWJ, LineDontBreak, 110 - case lbWJ | prAny<<32: - return lbAny, LineDontBreak, 110 + {lbAny, prWJ}: {lbWJ, LineDontBreak, 110}, + {lbWJ, prAny}: {lbAny, LineDontBreak, 110}, // LB12. - case lbAny | prGL<<32: - return lbGL, LineCanBreak, 310 - case lbGL | prAny<<32: - return lbAny, LineDontBreak, 120 + {lbAny, prGL}: {lbGL, LineCanBreak, 310}, + {lbGL, prAny}: {lbAny, LineDontBreak, 120}, // LB13 (simple transitions). - case lbAny | prCL<<32: - return lbCL, LineCanBreak, 310 - case lbAny | prCP<<32: - return lbCP, LineCanBreak, 310 - case lbAny | prEX<<32: - return lbEX, LineDontBreak, 130 - case lbAny | prIS<<32: - return lbIS, LineCanBreak, 310 - case lbAny | prSY<<32: - return lbSY, LineCanBreak, 310 + {lbAny, prCL}: {lbCL, LineCanBreak, 310}, + {lbAny, prCP}: {lbCP, LineCanBreak, 310}, + {lbAny, prEX}: {lbEX, LineDontBreak, 130}, + {lbAny, prIS}: {lbIS, LineCanBreak, 310}, + {lbAny, prSY}: {lbSY, LineCanBreak, 310}, // LB14. - case lbAny | prOP<<32: - return lbOP, LineCanBreak, 310 - case lbOP | prSP<<32: - return lbOP, LineDontBreak, 70 - case lbOP | prAny<<32: - return lbAny, LineDontBreak, 140 + {lbAny, prOP}: {lbOP, LineCanBreak, 310}, + {lbOP, prSP}: {lbOP, LineDontBreak, 70}, + {lbOP, prAny}: {lbAny, LineDontBreak, 140}, // LB15. - case lbQU | prSP<<32: - return lbQUSP, LineDontBreak, 70 - case lbQU | prOP<<32: - return lbOP, LineDontBreak, 150 - case lbQUSP | prOP<<32: - return lbOP, LineDontBreak, 150 + {lbQU, prSP}: {lbQUSP, LineDontBreak, 70}, + {lbQU, prOP}: {lbOP, LineDontBreak, 150}, + {lbQUSP, prOP}: {lbOP, LineDontBreak, 150}, // LB16. - case lbCL | prSP<<32: - return lbCLCPSP, LineDontBreak, 70 - case lbNUCL | prSP<<32: - return lbCLCPSP, LineDontBreak, 70 - case lbCP | prSP<<32: - return lbCLCPSP, LineDontBreak, 70 - case lbNUCP | prSP<<32: - return lbCLCPSP, LineDontBreak, 70 - case lbCL | prNS<<32: - return lbNS, LineDontBreak, 160 - case lbNUCL | prNS<<32: - return lbNS, LineDontBreak, 160 - case lbCP | prNS<<32: - return lbNS, LineDontBreak, 160 - case lbNUCP | prNS<<32: - return lbNS, LineDontBreak, 160 - case lbCLCPSP | prNS<<32: - return lbNS, LineDontBreak, 160 + {lbCL, prSP}: {lbCLCPSP, LineDontBreak, 70}, + {lbNUCL, prSP}: {lbCLCPSP, LineDontBreak, 70}, + {lbCP, prSP}: {lbCLCPSP, LineDontBreak, 70}, + {lbNUCP, prSP}: {lbCLCPSP, LineDontBreak, 70}, + {lbCL, prNS}: {lbNS, LineDontBreak, 160}, + {lbNUCL, prNS}: {lbNS, LineDontBreak, 160}, + {lbCP, prNS}: {lbNS, LineDontBreak, 160}, + {lbNUCP, prNS}: {lbNS, LineDontBreak, 160}, + {lbCLCPSP, prNS}: {lbNS, LineDontBreak, 160}, // LB17. - case lbAny | prB2<<32: - return lbB2, LineCanBreak, 310 - case lbB2 | prSP<<32: - return lbB2SP, LineDontBreak, 70 - case lbB2 | prB2<<32: - return lbB2, LineDontBreak, 170 - case lbB2SP | prB2<<32: - return lbB2, LineDontBreak, 170 + {lbAny, prB2}: {lbB2, LineCanBreak, 310}, + {lbB2, prSP}: {lbB2SP, LineDontBreak, 70}, + {lbB2, prB2}: {lbB2, LineDontBreak, 170}, + {lbB2SP, prB2}: {lbB2, LineDontBreak, 170}, // LB18. - case lbSP | prAny<<32: - return lbAny, LineCanBreak, 180 - case lbQUSP | prAny<<32: - return lbAny, LineCanBreak, 180 - case lbCLCPSP | prAny<<32: - return lbAny, LineCanBreak, 180 - case lbB2SP | prAny<<32: - return lbAny, LineCanBreak, 180 + {lbSP, prAny}: {lbAny, LineCanBreak, 180}, + {lbQUSP, prAny}: {lbAny, LineCanBreak, 180}, + {lbCLCPSP, prAny}: {lbAny, LineCanBreak, 180}, + {lbB2SP, prAny}: {lbAny, LineCanBreak, 180}, // LB19. - case lbAny | prQU<<32: - return lbQU, LineDontBreak, 190 - case lbQU | prAny<<32: - return lbAny, LineDontBreak, 190 + {lbAny, prQU}: {lbQU, LineDontBreak, 190}, + {lbQU, prAny}: {lbAny, LineDontBreak, 190}, // LB20. - case lbAny | prCB<<32: - return lbCB, LineCanBreak, 200 - case lbCB | prAny<<32: - return lbAny, LineCanBreak, 200 + {lbAny, prCB}: {lbCB, LineCanBreak, 200}, + {lbCB, prAny}: {lbAny, LineCanBreak, 200}, // LB21. - case lbAny | prBA<<32: - return lbBA, LineDontBreak, 210 - case lbAny | prHY<<32: - return lbHY, LineDontBreak, 210 - case lbAny | prNS<<32: - return lbNS, LineDontBreak, 210 - case lbAny | prBB<<32: - return lbBB, LineCanBreak, 310 - case lbBB | prAny<<32: - return lbAny, LineDontBreak, 210 + {lbAny, prBA}: {lbBA, LineDontBreak, 210}, + {lbAny, prHY}: {lbHY, LineDontBreak, 210}, + {lbAny, prNS}: {lbNS, LineDontBreak, 210}, + {lbAny, prBB}: {lbBB, LineCanBreak, 310}, + {lbBB, prAny}: {lbAny, LineDontBreak, 210}, // LB21a. - case lbAny | prHL<<32: - return lbHL, LineCanBreak, 310 - case lbHL | prHY<<32: - return lbLB21a, LineDontBreak, 210 - case lbHL | prBA<<32: - return lbLB21a, LineDontBreak, 210 - case lbLB21a | prAny<<32: - return lbAny, LineDontBreak, 211 + {lbAny, prHL}: {lbHL, LineCanBreak, 310}, + {lbHL, prHY}: {lbLB21a, LineDontBreak, 210}, + {lbHL, prBA}: {lbLB21a, LineDontBreak, 210}, + {lbLB21a, prAny}: {lbAny, LineDontBreak, 211}, // LB21b. - case lbSY | prHL<<32: - return lbHL, LineDontBreak, 212 - case lbNUSY | prHL<<32: - return lbHL, LineDontBreak, 212 + {lbSY, prHL}: {lbHL, LineDontBreak, 212}, + {lbNUSY, prHL}: {lbHL, LineDontBreak, 212}, // LB22. - case lbAny | prIN<<32: - return lbAny, LineDontBreak, 220 + {lbAny, prIN}: {lbAny, LineDontBreak, 220}, // LB23. - case lbAny | prAL<<32: - return lbAL, LineCanBreak, 310 - case lbAny | prNU<<32: - return lbNU, LineCanBreak, 310 - case lbAL | prNU<<32: - return lbNU, LineDontBreak, 230 - case lbHL | prNU<<32: - return lbNU, LineDontBreak, 230 - case lbNU | prAL<<32: - return lbAL, LineDontBreak, 230 - case lbNU | prHL<<32: - return lbHL, LineDontBreak, 230 - case lbNUNU | prAL<<32: - return lbAL, LineDontBreak, 230 - case lbNUNU | prHL<<32: - return lbHL, LineDontBreak, 230 + {lbAny, prAL}: {lbAL, LineCanBreak, 310}, + {lbAny, prNU}: {lbNU, LineCanBreak, 310}, + {lbAL, prNU}: {lbNU, LineDontBreak, 230}, + {lbHL, prNU}: {lbNU, LineDontBreak, 230}, + {lbNU, prAL}: {lbAL, LineDontBreak, 230}, + {lbNU, prHL}: {lbHL, LineDontBreak, 230}, + {lbNUNU, prAL}: {lbAL, LineDontBreak, 230}, + {lbNUNU, prHL}: {lbHL, LineDontBreak, 230}, // LB23a. - case lbAny | prPR<<32: - return lbPR, LineCanBreak, 310 - case lbAny | prID<<32: - return lbIDEM, LineCanBreak, 310 - case lbAny | prEB<<32: - return lbEB, LineCanBreak, 310 - case lbAny | prEM<<32: - return lbIDEM, LineCanBreak, 310 - case lbPR | prID<<32: - return lbIDEM, LineDontBreak, 231 - case lbPR | prEB<<32: - return lbEB, LineDontBreak, 231 - case lbPR | prEM<<32: - return lbIDEM, LineDontBreak, 231 - case lbIDEM | prPO<<32: - return lbPO, LineDontBreak, 231 - case lbEB | prPO<<32: - return lbPO, LineDontBreak, 231 + {lbAny, prPR}: {lbPR, LineCanBreak, 310}, + {lbAny, prID}: {lbIDEM, LineCanBreak, 310}, + {lbAny, prEB}: {lbEB, LineCanBreak, 310}, + {lbAny, prEM}: {lbIDEM, LineCanBreak, 310}, + {lbPR, prID}: {lbIDEM, LineDontBreak, 231}, + {lbPR, prEB}: {lbEB, LineDontBreak, 231}, + {lbPR, prEM}: {lbIDEM, LineDontBreak, 231}, + {lbIDEM, prPO}: {lbPO, LineDontBreak, 231}, + {lbEB, prPO}: {lbPO, LineDontBreak, 231}, // LB24. - case lbAny | prPO<<32: - return lbPO, LineCanBreak, 310 - case lbPR | prAL<<32: - return lbAL, LineDontBreak, 240 - case lbPR | prHL<<32: - return lbHL, LineDontBreak, 240 - case lbPO | prAL<<32: - return lbAL, LineDontBreak, 240 - case lbPO | prHL<<32: - return lbHL, LineDontBreak, 240 - case lbAL | prPR<<32: - return lbPR, LineDontBreak, 240 - case lbAL | prPO<<32: - return lbPO, LineDontBreak, 240 - case lbHL | prPR<<32: - return lbPR, LineDontBreak, 240 - case lbHL | prPO<<32: - return lbPO, LineDontBreak, 240 + {lbAny, prPO}: {lbPO, LineCanBreak, 310}, + {lbPR, prAL}: {lbAL, LineDontBreak, 240}, + {lbPR, prHL}: {lbHL, LineDontBreak, 240}, + {lbPO, prAL}: {lbAL, LineDontBreak, 240}, + {lbPO, prHL}: {lbHL, LineDontBreak, 240}, + {lbAL, prPR}: {lbPR, LineDontBreak, 240}, + {lbAL, prPO}: {lbPO, LineDontBreak, 240}, + {lbHL, prPR}: {lbPR, LineDontBreak, 240}, + {lbHL, prPO}: {lbPO, LineDontBreak, 240}, // LB25 (simple transitions). - case lbPR | prNU<<32: - return lbNU, LineDontBreak, 250 - case lbPO | prNU<<32: - return lbNU, LineDontBreak, 250 - case lbOP | prNU<<32: - return lbNU, LineDontBreak, 250 - case lbHY | prNU<<32: - return lbNU, LineDontBreak, 250 - case lbNU | prNU<<32: - return lbNUNU, LineDontBreak, 250 - case lbNU | prSY<<32: - return lbNUSY, LineDontBreak, 250 - case lbNU | prIS<<32: - return lbNUIS, LineDontBreak, 250 - case lbNUNU | prNU<<32: - return lbNUNU, LineDontBreak, 250 - case lbNUNU | prSY<<32: - return lbNUSY, LineDontBreak, 250 - case lbNUNU | prIS<<32: - return lbNUIS, LineDontBreak, 250 - case lbNUSY | prNU<<32: - return lbNUNU, LineDontBreak, 250 - case lbNUSY | prSY<<32: - return lbNUSY, LineDontBreak, 250 - case lbNUSY | prIS<<32: - return lbNUIS, LineDontBreak, 250 - case lbNUIS | prNU<<32: - return lbNUNU, LineDontBreak, 250 - case lbNUIS | prSY<<32: - return lbNUSY, LineDontBreak, 250 - case lbNUIS | prIS<<32: - return lbNUIS, LineDontBreak, 250 - case lbNU | prCL<<32: - return lbNUCL, LineDontBreak, 250 - case lbNU | prCP<<32: - return lbNUCP, LineDontBreak, 250 - case lbNUNU | prCL<<32: - return lbNUCL, LineDontBreak, 250 - case lbNUNU | prCP<<32: - return lbNUCP, LineDontBreak, 250 - case lbNUSY | prCL<<32: - return lbNUCL, LineDontBreak, 250 - case lbNUSY | prCP<<32: - return lbNUCP, LineDontBreak, 250 - case lbNUIS | prCL<<32: - return lbNUCL, LineDontBreak, 250 - case lbNUIS | prCP<<32: - return lbNUCP, LineDontBreak, 250 - case lbNU | prPO<<32: - return lbPO, LineDontBreak, 250 - case lbNUNU | prPO<<32: - return lbPO, LineDontBreak, 250 - case lbNUSY | prPO<<32: - return lbPO, LineDontBreak, 250 - case lbNUIS | prPO<<32: - return lbPO, LineDontBreak, 250 - case lbNUCL | prPO<<32: - return lbPO, LineDontBreak, 250 - case lbNUCP | prPO<<32: - return lbPO, LineDontBreak, 250 - case lbNU | prPR<<32: - return lbPR, LineDontBreak, 250 - case lbNUNU | prPR<<32: - return lbPR, LineDontBreak, 250 - case lbNUSY | prPR<<32: - return lbPR, LineDontBreak, 250 - case lbNUIS | prPR<<32: - return lbPR, LineDontBreak, 250 - case lbNUCL | prPR<<32: - return lbPR, LineDontBreak, 250 - case lbNUCP | prPR<<32: - return lbPR, LineDontBreak, 250 + {lbPR, prNU}: {lbNU, LineDontBreak, 250}, + {lbPO, prNU}: {lbNU, LineDontBreak, 250}, + {lbOP, prNU}: {lbNU, LineDontBreak, 250}, + {lbHY, prNU}: {lbNU, LineDontBreak, 250}, + {lbNU, prNU}: {lbNUNU, LineDontBreak, 250}, + {lbNU, prSY}: {lbNUSY, LineDontBreak, 250}, + {lbNU, prIS}: {lbNUIS, LineDontBreak, 250}, + {lbNUNU, prNU}: {lbNUNU, LineDontBreak, 250}, + {lbNUNU, prSY}: {lbNUSY, LineDontBreak, 250}, + {lbNUNU, prIS}: {lbNUIS, LineDontBreak, 250}, + {lbNUSY, prNU}: {lbNUNU, LineDontBreak, 250}, + {lbNUSY, prSY}: {lbNUSY, LineDontBreak, 250}, + {lbNUSY, prIS}: {lbNUIS, LineDontBreak, 250}, + {lbNUIS, prNU}: {lbNUNU, LineDontBreak, 250}, + {lbNUIS, prSY}: {lbNUSY, LineDontBreak, 250}, + {lbNUIS, prIS}: {lbNUIS, LineDontBreak, 250}, + {lbNU, prCL}: {lbNUCL, LineDontBreak, 250}, + {lbNU, prCP}: {lbNUCP, LineDontBreak, 250}, + {lbNUNU, prCL}: {lbNUCL, LineDontBreak, 250}, + {lbNUNU, prCP}: {lbNUCP, LineDontBreak, 250}, + {lbNUSY, prCL}: {lbNUCL, LineDontBreak, 250}, + {lbNUSY, prCP}: {lbNUCP, LineDontBreak, 250}, + {lbNUIS, prCL}: {lbNUCL, LineDontBreak, 250}, + {lbNUIS, prCP}: {lbNUCP, LineDontBreak, 250}, + {lbNU, prPO}: {lbPO, LineDontBreak, 250}, + {lbNUNU, prPO}: {lbPO, LineDontBreak, 250}, + {lbNUSY, prPO}: {lbPO, LineDontBreak, 250}, + {lbNUIS, prPO}: {lbPO, LineDontBreak, 250}, + {lbNUCL, prPO}: {lbPO, LineDontBreak, 250}, + {lbNUCP, prPO}: {lbPO, LineDontBreak, 250}, + {lbNU, prPR}: {lbPR, LineDontBreak, 250}, + {lbNUNU, prPR}: {lbPR, LineDontBreak, 250}, + {lbNUSY, prPR}: {lbPR, LineDontBreak, 250}, + {lbNUIS, prPR}: {lbPR, LineDontBreak, 250}, + {lbNUCL, prPR}: {lbPR, LineDontBreak, 250}, + {lbNUCP, prPR}: {lbPR, LineDontBreak, 250}, // LB26. - case lbAny | prJL<<32: - return lbJL, LineCanBreak, 310 - case lbAny | prJV<<32: - return lbJV, LineCanBreak, 310 - case lbAny | prJT<<32: - return lbJT, LineCanBreak, 310 - case lbAny | prH2<<32: - return lbH2, LineCanBreak, 310 - case lbAny | prH3<<32: - return lbH3, LineCanBreak, 310 - case lbJL | prJL<<32: - return lbJL, LineDontBreak, 260 - case lbJL | prJV<<32: - return lbJV, LineDontBreak, 260 - case lbJL | prH2<<32: - return lbH2, LineDontBreak, 260 - case lbJL | prH3<<32: - return lbH3, LineDontBreak, 260 - case lbJV | prJV<<32: - return lbJV, LineDontBreak, 260 - case lbJV | prJT<<32: - return lbJT, LineDontBreak, 260 - case lbH2 | prJV<<32: - return lbJV, LineDontBreak, 260 - case lbH2 | prJT<<32: - return lbJT, LineDontBreak, 260 - case lbJT | prJT<<32: - return lbJT, LineDontBreak, 260 - case lbH3 | prJT<<32: - return lbJT, LineDontBreak, 260 + {lbAny, prJL}: {lbJL, LineCanBreak, 310}, + {lbAny, prJV}: {lbJV, LineCanBreak, 310}, + {lbAny, prJT}: {lbJT, LineCanBreak, 310}, + {lbAny, prH2}: {lbH2, LineCanBreak, 310}, + {lbAny, prH3}: {lbH3, LineCanBreak, 310}, + {lbJL, prJL}: {lbJL, LineDontBreak, 260}, + {lbJL, prJV}: {lbJV, LineDontBreak, 260}, + {lbJL, prH2}: {lbH2, LineDontBreak, 260}, + {lbJL, prH3}: {lbH3, LineDontBreak, 260}, + {lbJV, prJV}: {lbJV, LineDontBreak, 260}, + {lbJV, prJT}: {lbJT, LineDontBreak, 260}, + {lbH2, prJV}: {lbJV, LineDontBreak, 260}, + {lbH2, prJT}: {lbJT, LineDontBreak, 260}, + {lbJT, prJT}: {lbJT, LineDontBreak, 260}, + {lbH3, prJT}: {lbJT, LineDontBreak, 260}, // LB27. - case lbJL | prPO<<32: - return lbPO, LineDontBreak, 270 - case lbJV | prPO<<32: - return lbPO, LineDontBreak, 270 - case lbJT | prPO<<32: - return lbPO, LineDontBreak, 270 - case lbH2 | prPO<<32: - return lbPO, LineDontBreak, 270 - case lbH3 | prPO<<32: - return lbPO, LineDontBreak, 270 - case lbPR | prJL<<32: - return lbJL, LineDontBreak, 270 - case lbPR | prJV<<32: - return lbJV, LineDontBreak, 270 - case lbPR | prJT<<32: - return lbJT, LineDontBreak, 270 - case lbPR | prH2<<32: - return lbH2, LineDontBreak, 270 - case lbPR | prH3<<32: - return lbH3, LineDontBreak, 270 + {lbJL, prPO}: {lbPO, LineDontBreak, 270}, + {lbJV, prPO}: {lbPO, LineDontBreak, 270}, + {lbJT, prPO}: {lbPO, LineDontBreak, 270}, + {lbH2, prPO}: {lbPO, LineDontBreak, 270}, + {lbH3, prPO}: {lbPO, LineDontBreak, 270}, + {lbPR, prJL}: {lbJL, LineDontBreak, 270}, + {lbPR, prJV}: {lbJV, LineDontBreak, 270}, + {lbPR, prJT}: {lbJT, LineDontBreak, 270}, + {lbPR, prH2}: {lbH2, LineDontBreak, 270}, + {lbPR, prH3}: {lbH3, LineDontBreak, 270}, // LB28. - case lbAL | prAL<<32: - return lbAL, LineDontBreak, 280 - case lbAL | prHL<<32: - return lbHL, LineDontBreak, 280 - case lbHL | prAL<<32: - return lbAL, LineDontBreak, 280 - case lbHL | prHL<<32: - return lbHL, LineDontBreak, 280 + {lbAL, prAL}: {lbAL, LineDontBreak, 280}, + {lbAL, prHL}: {lbHL, LineDontBreak, 280}, + {lbHL, prAL}: {lbAL, LineDontBreak, 280}, + {lbHL, prHL}: {lbHL, LineDontBreak, 280}, // LB29. - case lbIS | prAL<<32: - return lbAL, LineDontBreak, 290 - case lbIS | prHL<<32: - return lbHL, LineDontBreak, 290 - case lbNUIS | prAL<<32: - return lbAL, LineDontBreak, 290 - case lbNUIS | prHL<<32: - return lbHL, LineDontBreak, 290 - - default: - return -1, -1, -1 - } + {lbIS, prAL}: {lbAL, LineDontBreak, 290}, + {lbIS, prHL}: {lbHL, LineDontBreak, 290}, + {lbNUIS, prAL}: {lbAL, LineDontBreak, 290}, + {lbNUIS, prHL}: {lbHL, LineDontBreak, 290}, } // transitionLineBreakState determines the new state of the line break parser @@ -449,7 +290,7 @@ func lbTransitions(state, prop int) (newState, lineBreak, rule int) { // further lookups. func transitionLineBreakState(state int, r rune, b []byte, str string) (newState int, lineBreak int) { // Determine the property of the next character. - nextProperty, generalCategory := propertyLineBreak(r) + nextProperty, generalCategory := propertyWithGenCat(lineBreakCodePoints, r) // Prepare. var forceNoBreak, isCPeaFWH bool @@ -465,7 +306,7 @@ func transitionLineBreakState(state int, r rune, b []byte, str string) (newState defer func() { // Transition into LB30. if newState == lbCP || newState == lbNUCP { - ea := propertyEastAsianWidth(r) + ea := property(eastAsianWidth, r) if ea != prF && ea != prW && ea != prH { newState |= lbCPeaFWHBit } @@ -511,27 +352,30 @@ func transitionLineBreakState(state int, r rune, b []byte, str string) (newState // Find the applicable transition in the table. var rule int - newState, lineBreak, rule = lbTransitions(state, nextProperty) - if newState < 0 { + transition, ok := lbTransitions[[2]int{state, nextProperty}] + if ok { + // We have a specific transition. We'll use it. + newState, lineBreak, rule = transition[0], transition[1], transition[2] + } else { // No specific transition found. Try the less specific ones. - anyPropProp, anyPropLineBreak, anyPropRule := lbTransitions(state, prAny) - anyStateProp, anyStateLineBreak, anyStateRule := lbTransitions(lbAny, nextProperty) - if anyPropProp >= 0 && anyStateProp >= 0 { + transAnyProp, okAnyProp := lbTransitions[[2]int{state, prAny}] + transAnyState, okAnyState := lbTransitions[[2]int{lbAny, nextProperty}] + if okAnyProp && okAnyState { // Both apply. We'll use a mix (see comments for grTransitions). - newState, lineBreak, rule = anyStateProp, anyStateLineBreak, anyStateRule - if anyPropRule < anyStateRule { - lineBreak, rule = anyPropLineBreak, anyPropRule + newState, lineBreak, rule = transAnyState[0], transAnyState[1], transAnyState[2] + if transAnyProp[2] < transAnyState[2] { + lineBreak, rule = transAnyProp[1], transAnyProp[2] } - } else if anyPropProp >= 0 { + } else if okAnyProp { // We only have a specific state. - newState, lineBreak, rule = anyPropProp, anyPropLineBreak, anyPropRule + newState, lineBreak, rule = transAnyProp[0], transAnyProp[1], transAnyProp[2] // This branch will probably never be reached because okAnyState will // always be true given the current transition map. But we keep it here // for future modifications to the transition map where this may not be // true anymore. - } else if anyStateProp >= 0 { + } else if okAnyState { // We only have a specific property. - newState, lineBreak, rule = anyStateProp, anyStateLineBreak, anyStateRule + newState, lineBreak, rule = transAnyState[0], transAnyState[1], transAnyState[2] } else { // No known transition. LB31: ALL ÷ ALL. newState, lineBreak, rule = lbAny, LineCanBreak, 310 @@ -570,7 +414,7 @@ func transitionLineBreakState(state int, r rune, b []byte, str string) (newState r, _ = utf8.DecodeRuneInString(str) } if r != utf8.RuneError { - pr, _ := propertyLineBreak(r) + pr, _ := propertyWithGenCat(lineBreakCodePoints, r) if pr == prNU { return lbNU, LineDontBreak } @@ -580,7 +424,7 @@ func transitionLineBreakState(state int, r rune, b []byte, str string) (newState // LB30 (part one). if rule > 300 { if (state == lbAL || state == lbHL || state == lbNU || state == lbNUNU) && nextProperty == prOP { - ea := propertyEastAsianWidth(r) + ea := property(eastAsianWidth, r) if ea != prF && ea != prW && ea != prH { return lbOP, LineDontBreak } @@ -616,7 +460,7 @@ func transitionLineBreakState(state int, r rune, b []byte, str string) (newState return prAny, LineDontBreak } } - graphemeProperty := propertyGraphemes(r) + graphemeProperty := property(graphemeCodePoints, r) if graphemeProperty == prExtendedPictographic && generalCategory == gcCn { return lbExtPicCn, LineCanBreak } diff --git a/vendor/github.com/rivo/uniseg/properties.go b/vendor/github.com/rivo/uniseg/properties.go index 6290e681..bc3c7bcf 100644 --- a/vendor/github.com/rivo/uniseg/properties.go +++ b/vendor/github.com/rivo/uniseg/properties.go @@ -160,49 +160,9 @@ func property(dictionary [][3]int, r rune) int { return propertySearch(dictionary, r)[2] } -// propertyLineBreak returns the Unicode property value and General Category -// (see constants above) of the given code point, as listed in the line break -// code points table, while fast tracking ASCII digits and letters. -func propertyLineBreak(r rune) (property, generalCategory int) { - if r >= 'a' && r <= 'z' { - return prAL, gcLl - } - if r >= 'A' && r <= 'Z' { - return prAL, gcLu - } - if r >= '0' && r <= '9' { - return prNU, gcNd - } - entry := propertySearch(lineBreakCodePoints, r) +// propertyWithGenCat returns the Unicode property value and General Category +// (see constants above) of the given code point. +func propertyWithGenCat(dictionary [][4]int, r rune) (property, generalCategory int) { + entry := propertySearch(dictionary, r) return entry[2], entry[3] } - -// propertyGraphemes returns the Unicode grapheme cluster property value of the -// given code point while fast tracking ASCII characters. -func propertyGraphemes(r rune) int { - if r >= 0x20 && r <= 0x7e { - return prAny - } - if r == 0x0a { - return prLF - } - if r == 0x0d { - return prCR - } - if r >= 0 && r <= 0x1f || r == 0x7f { - return prControl - } - return property(graphemeCodePoints, r) -} - -// propertyEastAsianWidth returns the Unicode East Asian Width property value of -// the given code point while fast tracking ASCII characters. -func propertyEastAsianWidth(r rune) int { - if r >= 0x20 && r <= 0x7e { - return prNa - } - if r >= 0 && r <= 0x1f || r == 0x7f { - return prN - } - return property(eastAsianWidth, r) -} diff --git a/vendor/github.com/rivo/uniseg/sentence.go b/vendor/github.com/rivo/uniseg/sentence.go index adc2a357..b7fc7099 100644 --- a/vendor/github.com/rivo/uniseg/sentence.go +++ b/vendor/github.com/rivo/uniseg/sentence.go @@ -3,7 +3,7 @@ package uniseg import "unicode/utf8" // FirstSentence returns the first sentence found in the given byte slice -// according to the rules of [Unicode Standard Annex #29, Sentence Boundaries]. +// according to the rules of Unicode Standard Annex #29, Sentence Boundaries. // This function can be called continuously to extract all sentences from a byte // slice, as illustrated in the example below. // @@ -17,8 +17,6 @@ import "unicode/utf8" // slice is the sub-slice of the input slice containing the identified sentence. // // Given an empty byte slice "b", the function returns nil values. -// -// [Unicode Standard Annex #29, Sentence Boundaries]: http://unicode.org/reports/tr29/#Sentence_Boundaries func FirstSentence(b []byte, state int) (sentence, rest []byte, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/github.com/rivo/uniseg/sentenceproperties.go b/vendor/github.com/rivo/uniseg/sentenceproperties.go index 67717ec1..ba0cf2de 100644 --- a/vendor/github.com/rivo/uniseg/sentenceproperties.go +++ b/vendor/github.com/rivo/uniseg/sentenceproperties.go @@ -1,13 +1,13 @@ -// Code generated via go generate from gen_properties.go. DO NOT EDIT. - package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. + // sentenceBreakCodePoints are taken from -// https://www.unicode.org/Public/15.0.0/ucd/auxiliary/SentenceBreakProperty.txt +// https://www.unicode.org/Public/14.0.0/ucd/auxiliary/SentenceBreakProperty.txt // and -// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt // ("Extended_Pictographic" only) -// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode +// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode // license agreement. var sentenceBreakCodePoints = [][3]int{ {0x0009, 0x0009, prSp}, // Cc @@ -843,7 +843,6 @@ var sentenceBreakCodePoints = [][3]int{ {0x0CE2, 0x0CE3, prExtend}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL {0x0CE6, 0x0CEF, prNumeric}, // Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE {0x0CF1, 0x0CF2, prOLetter}, // Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA - {0x0CF3, 0x0CF3, prExtend}, // Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT {0x0D00, 0x0D01, prExtend}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU {0x0D02, 0x0D03, prExtend}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA {0x0D04, 0x0D0C, prOLetter}, // Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L @@ -897,7 +896,7 @@ var sentenceBreakCodePoints = [][3]int{ {0x0EBD, 0x0EBD, prOLetter}, // Lo LAO SEMIVOWEL SIGN NYO {0x0EC0, 0x0EC4, prOLetter}, // Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI {0x0EC6, 0x0EC6, prOLetter}, // Lm LAO KO LA - {0x0EC8, 0x0ECE, prExtend}, // Mn [7] LAO TONE MAI EK..LAO YAMAKKAN + {0x0EC8, 0x0ECD, prExtend}, // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA {0x0ED0, 0x0ED9, prNumeric}, // Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE {0x0EDC, 0x0EDF, prOLetter}, // Lo [4] LAO HO NO..LAO LETTER KHMU NYO {0x0F00, 0x0F00, prOLetter}, // Lo TIBETAN SYLLABLE OM @@ -959,7 +958,7 @@ var sentenceBreakCodePoints = [][3]int{ {0x10C7, 0x10C7, prUpper}, // L& GEORGIAN CAPITAL LETTER YN {0x10CD, 0x10CD, prUpper}, // L& GEORGIAN CAPITAL LETTER AEN {0x10D0, 0x10FA, prOLetter}, // L& [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN - {0x10FC, 0x10FC, prLower}, // Lm MODIFIER LETTER GEORGIAN NAR + {0x10FC, 0x10FC, prOLetter}, // Lm MODIFIER LETTER GEORGIAN NAR {0x10FD, 0x10FF, prOLetter}, // L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN {0x1100, 0x1248, prOLetter}, // Lo [329] HANGUL CHOSEONG KIYEOK..ETHIOPIC SYLLABLE QWA {0x124A, 0x124D, prOLetter}, // Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE @@ -2035,7 +2034,7 @@ var sentenceBreakCodePoints = [][3]int{ {0xA7D7, 0xA7D7, prLower}, // L& LATIN SMALL LETTER MIDDLE SCOTS S {0xA7D8, 0xA7D8, prUpper}, // L& LATIN CAPITAL LETTER SIGMOID S {0xA7D9, 0xA7D9, prLower}, // L& LATIN SMALL LETTER SIGMOID S - {0xA7F2, 0xA7F4, prLower}, // Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q + {0xA7F2, 0xA7F4, prOLetter}, // Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q {0xA7F5, 0xA7F5, prUpper}, // L& LATIN CAPITAL LETTER REVERSED HALF H {0xA7F6, 0xA7F6, prLower}, // L& LATIN SMALL LETTER REVERSED HALF H {0xA7F7, 0xA7F7, prOLetter}, // Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -2141,7 +2140,7 @@ var sentenceBreakCodePoints = [][3]int{ {0xAB30, 0xAB5A, prLower}, // L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG {0xAB5C, 0xAB5F, prLower}, // Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK {0xAB60, 0xAB68, prLower}, // L& [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE - {0xAB69, 0xAB69, prLower}, // Lm MODIFIER LETTER SMALL TURNED W + {0xAB69, 0xAB69, prOLetter}, // Lm MODIFIER LETTER SMALL TURNED W {0xAB70, 0xABBF, prLower}, // L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA {0xABC0, 0xABE2, prOLetter}, // Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM {0xABE3, 0xABE4, prExtend}, // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP @@ -2335,7 +2334,6 @@ var sentenceBreakCodePoints = [][3]int{ {0x10E80, 0x10EA9, prOLetter}, // Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET {0x10EAB, 0x10EAC, prExtend}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK {0x10EB0, 0x10EB1, prOLetter}, // Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE - {0x10EFD, 0x10EFF, prExtend}, // Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA {0x10F00, 0x10F1C, prOLetter}, // Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL {0x10F27, 0x10F27, prOLetter}, // Lo OLD SOGDIAN LIGATURE AYIN-DALETH {0x10F30, 0x10F45, prOLetter}, // Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -2410,8 +2408,6 @@ var sentenceBreakCodePoints = [][3]int{ {0x11238, 0x11239, prSTerm}, // Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA {0x1123B, 0x1123C, prSTerm}, // Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK {0x1123E, 0x1123E, prExtend}, // Mn KHOJKI SIGN SUKUN - {0x1123F, 0x11240, prOLetter}, // Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I - {0x11241, 0x11241, prExtend}, // Mn KHOJKI VOWEL SIGN VOCALIC R {0x11280, 0x11286, prOLetter}, // Lo [7] MULTANI LETTER A..MULTANI LETTER GA {0x11288, 0x11288, prOLetter}, // Lo MULTANI LETTER GHA {0x1128A, 0x1128D, prOLetter}, // Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -2607,29 +2603,13 @@ var sentenceBreakCodePoints = [][3]int{ {0x11EF3, 0x11EF4, prExtend}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U {0x11EF5, 0x11EF6, prExtend}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O {0x11EF7, 0x11EF8, prSTerm}, // Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION - {0x11F00, 0x11F01, prExtend}, // Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA - {0x11F02, 0x11F02, prOLetter}, // Lo KAWI SIGN REPHA - {0x11F03, 0x11F03, prExtend}, // Mc KAWI SIGN VISARGA - {0x11F04, 0x11F10, prOLetter}, // Lo [13] KAWI LETTER A..KAWI LETTER O - {0x11F12, 0x11F33, prOLetter}, // Lo [34] KAWI LETTER KA..KAWI LETTER JNYA - {0x11F34, 0x11F35, prExtend}, // Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA - {0x11F36, 0x11F3A, prExtend}, // Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R - {0x11F3E, 0x11F3F, prExtend}, // Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI - {0x11F40, 0x11F40, prExtend}, // Mn KAWI VOWEL SIGN EU - {0x11F41, 0x11F41, prExtend}, // Mc KAWI SIGN KILLER - {0x11F42, 0x11F42, prExtend}, // Mn KAWI CONJOINER - {0x11F43, 0x11F44, prSTerm}, // Po [2] KAWI DANDA..KAWI DOUBLE DANDA - {0x11F50, 0x11F59, prNumeric}, // Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE {0x11FB0, 0x11FB0, prOLetter}, // Lo LISU LETTER YHA {0x12000, 0x12399, prOLetter}, // Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U {0x12400, 0x1246E, prOLetter}, // Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM {0x12480, 0x12543, prOLetter}, // Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU {0x12F90, 0x12FF0, prOLetter}, // Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 - {0x13000, 0x1342F, prOLetter}, // Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D - {0x13430, 0x1343F, prFormat}, // Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE - {0x13440, 0x13440, prExtend}, // Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY - {0x13441, 0x13446, prOLetter}, // Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN - {0x13447, 0x13455, prExtend}, // Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED + {0x13000, 0x1342E, prOLetter}, // Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 + {0x13430, 0x13438, prFormat}, // Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT {0x14400, 0x14646, prOLetter}, // Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 {0x16800, 0x16A38, prOLetter}, // Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ {0x16A40, 0x16A5E, prOLetter}, // Lo [31] MRO LETTER TA..MRO LETTER TEK @@ -2668,9 +2648,7 @@ var sentenceBreakCodePoints = [][3]int{ {0x1AFF5, 0x1AFFB, prOLetter}, // Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 {0x1AFFD, 0x1AFFE, prOLetter}, // Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 {0x1B000, 0x1B122, prOLetter}, // Lo [291] KATAKANA LETTER ARCHAIC E..KATAKANA LETTER ARCHAIC WU - {0x1B132, 0x1B132, prOLetter}, // Lo HIRAGANA LETTER SMALL KO {0x1B150, 0x1B152, prOLetter}, // Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO - {0x1B155, 0x1B155, prOLetter}, // Lo KATAKANA LETTER SMALL KO {0x1B164, 0x1B167, prOLetter}, // Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N {0x1B170, 0x1B2FB, prOLetter}, // Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB {0x1BC00, 0x1BC6A, prOLetter}, // Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M @@ -2760,14 +2738,11 @@ var sentenceBreakCodePoints = [][3]int{ {0x1DF00, 0x1DF09, prLower}, // L& [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK {0x1DF0A, 0x1DF0A, prOLetter}, // Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK {0x1DF0B, 0x1DF1E, prLower}, // L& [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL - {0x1DF25, 0x1DF2A, prLower}, // L& [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK {0x1E000, 0x1E006, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE {0x1E008, 0x1E018, prExtend}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU {0x1E01B, 0x1E021, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI {0x1E023, 0x1E024, prExtend}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS {0x1E026, 0x1E02A, prExtend}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA - {0x1E030, 0x1E06D, prLower}, // Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE - {0x1E08F, 0x1E08F, prExtend}, // Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I {0x1E100, 0x1E12C, prOLetter}, // Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W {0x1E130, 0x1E136, prExtend}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D {0x1E137, 0x1E13D, prOLetter}, // Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER @@ -2778,10 +2753,6 @@ var sentenceBreakCodePoints = [][3]int{ {0x1E2C0, 0x1E2EB, prOLetter}, // Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH {0x1E2EC, 0x1E2EF, prExtend}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI {0x1E2F0, 0x1E2F9, prNumeric}, // Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE - {0x1E4D0, 0x1E4EA, prOLetter}, // Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL - {0x1E4EB, 0x1E4EB, prOLetter}, // Lm NAG MUNDARI SIGN OJOD - {0x1E4EC, 0x1E4EF, prExtend}, // Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH - {0x1E4F0, 0x1E4F9, prNumeric}, // Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE {0x1E7E0, 0x1E7E6, prOLetter}, // Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO {0x1E7E8, 0x1E7EB, prOLetter}, // Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE {0x1E7ED, 0x1E7EE, prOLetter}, // Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -2832,13 +2803,12 @@ var sentenceBreakCodePoints = [][3]int{ {0x1F676, 0x1F678, prClose}, // So [3] SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT..SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT {0x1FBF0, 0x1FBF9, prNumeric}, // Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE {0x20000, 0x2A6DF, prOLetter}, // Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF - {0x2A700, 0x2B739, prOLetter}, // Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 + {0x2A700, 0x2B738, prOLetter}, // Lo [4153] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B738 {0x2B740, 0x2B81D, prOLetter}, // Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D {0x2B820, 0x2CEA1, prOLetter}, // Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 {0x2CEB0, 0x2EBE0, prOLetter}, // Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 {0x2F800, 0x2FA1D, prOLetter}, // Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D {0x30000, 0x3134A, prOLetter}, // Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A - {0x31350, 0x323AF, prOLetter}, // Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF {0xE0001, 0xE0001, prFormat}, // Cf LANGUAGE TAG {0xE0020, 0xE007F, prExtend}, // Cf [96] TAG SPACE..CANCEL TAG {0xE0100, 0xE01EF, prExtend}, // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 diff --git a/vendor/github.com/rivo/uniseg/sentencerules.go b/vendor/github.com/rivo/uniseg/sentencerules.go index 0b29c7bd..58c04794 100644 --- a/vendor/github.com/rivo/uniseg/sentencerules.go +++ b/vendor/github.com/rivo/uniseg/sentencerules.go @@ -18,178 +18,104 @@ const ( sbSB8aSp ) -// sbTransitions implements the sentence break parser's state transitions. It's -// anologous to [grTransitions], see comments there for details. -// -// Unicode version 15.0.0. -func sbTransitions(state, prop int) (newState int, sentenceBreak bool, rule int) { - switch uint64(state) | uint64(prop)<<32 { +// The sentence break parser's breaking instructions. +const ( + sbDontBreak = iota + sbBreak +) + +// The sentence break parser's state transitions. It's anologous to +// grTransitions, see comments there for details. Unicode version 14.0.0. +var sbTransitions = map[[2]int][3]int{ // SB3. - case sbAny | prCR<<32: - return sbCR, false, 9990 - case sbCR | prLF<<32: - return sbParaSep, false, 30 + {sbAny, prCR}: {sbCR, sbDontBreak, 9990}, + {sbCR, prLF}: {sbParaSep, sbDontBreak, 30}, // SB4. - case sbAny | prSep<<32: - return sbParaSep, false, 9990 - case sbAny | prLF<<32: - return sbParaSep, false, 9990 - case sbParaSep | prAny<<32: - return sbAny, true, 40 - case sbCR | prAny<<32: - return sbAny, true, 40 + {sbAny, prSep}: {sbParaSep, sbDontBreak, 9990}, + {sbAny, prLF}: {sbParaSep, sbDontBreak, 9990}, + {sbParaSep, prAny}: {sbAny, sbBreak, 40}, + {sbCR, prAny}: {sbAny, sbBreak, 40}, // SB6. - case sbAny | prATerm<<32: - return sbATerm, false, 9990 - case sbATerm | prNumeric<<32: - return sbAny, false, 60 - case sbSB7 | prNumeric<<32: - return sbAny, false, 60 // Because ATerm also appears in SB7. + {sbAny, prATerm}: {sbATerm, sbDontBreak, 9990}, + {sbATerm, prNumeric}: {sbAny, sbDontBreak, 60}, + {sbSB7, prNumeric}: {sbAny, sbDontBreak, 60}, // Because ATerm also appears in SB7. // SB7. - case sbAny | prUpper<<32: - return sbUpper, false, 9990 - case sbAny | prLower<<32: - return sbLower, false, 9990 - case sbUpper | prATerm<<32: - return sbSB7, false, 70 - case sbLower | prATerm<<32: - return sbSB7, false, 70 - case sbSB7 | prUpper<<32: - return sbUpper, false, 70 + {sbAny, prUpper}: {sbUpper, sbDontBreak, 9990}, + {sbAny, prLower}: {sbLower, sbDontBreak, 9990}, + {sbUpper, prATerm}: {sbSB7, sbDontBreak, 70}, + {sbLower, prATerm}: {sbSB7, sbDontBreak, 70}, + {sbSB7, prUpper}: {sbUpper, sbDontBreak, 70}, // SB8a. - case sbAny | prSTerm<<32: - return sbSTerm, false, 9990 - case sbATerm | prSContinue<<32: - return sbAny, false, 81 - case sbATerm | prATerm<<32: - return sbATerm, false, 81 - case sbATerm | prSTerm<<32: - return sbSTerm, false, 81 - case sbSB7 | prSContinue<<32: - return sbAny, false, 81 - case sbSB7 | prATerm<<32: - return sbATerm, false, 81 - case sbSB7 | prSTerm<<32: - return sbSTerm, false, 81 - case sbSB8Close | prSContinue<<32: - return sbAny, false, 81 - case sbSB8Close | prATerm<<32: - return sbATerm, false, 81 - case sbSB8Close | prSTerm<<32: - return sbSTerm, false, 81 - case sbSB8Sp | prSContinue<<32: - return sbAny, false, 81 - case sbSB8Sp | prATerm<<32: - return sbATerm, false, 81 - case sbSB8Sp | prSTerm<<32: - return sbSTerm, false, 81 - case sbSTerm | prSContinue<<32: - return sbAny, false, 81 - case sbSTerm | prATerm<<32: - return sbATerm, false, 81 - case sbSTerm | prSTerm<<32: - return sbSTerm, false, 81 - case sbSB8aClose | prSContinue<<32: - return sbAny, false, 81 - case sbSB8aClose | prATerm<<32: - return sbATerm, false, 81 - case sbSB8aClose | prSTerm<<32: - return sbSTerm, false, 81 - case sbSB8aSp | prSContinue<<32: - return sbAny, false, 81 - case sbSB8aSp | prATerm<<32: - return sbATerm, false, 81 - case sbSB8aSp | prSTerm<<32: - return sbSTerm, false, 81 + {sbAny, prSTerm}: {sbSTerm, sbDontBreak, 9990}, + {sbATerm, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbATerm, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbATerm, prSTerm}: {sbSTerm, sbDontBreak, 81}, + {sbSB7, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbSB7, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbSB7, prSTerm}: {sbSTerm, sbDontBreak, 81}, + {sbSB8Close, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbSB8Close, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbSB8Close, prSTerm}: {sbSTerm, sbDontBreak, 81}, + {sbSB8Sp, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbSB8Sp, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbSB8Sp, prSTerm}: {sbSTerm, sbDontBreak, 81}, + {sbSTerm, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbSTerm, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbSTerm, prSTerm}: {sbSTerm, sbDontBreak, 81}, + {sbSB8aClose, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbSB8aClose, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbSB8aClose, prSTerm}: {sbSTerm, sbDontBreak, 81}, + {sbSB8aSp, prSContinue}: {sbAny, sbDontBreak, 81}, + {sbSB8aSp, prATerm}: {sbATerm, sbDontBreak, 81}, + {sbSB8aSp, prSTerm}: {sbSTerm, sbDontBreak, 81}, // SB9. - case sbATerm | prClose<<32: - return sbSB8Close, false, 90 - case sbSB7 | prClose<<32: - return sbSB8Close, false, 90 - case sbSB8Close | prClose<<32: - return sbSB8Close, false, 90 - case sbATerm | prSp<<32: - return sbSB8Sp, false, 90 - case sbSB7 | prSp<<32: - return sbSB8Sp, false, 90 - case sbSB8Close | prSp<<32: - return sbSB8Sp, false, 90 - case sbSTerm | prClose<<32: - return sbSB8aClose, false, 90 - case sbSB8aClose | prClose<<32: - return sbSB8aClose, false, 90 - case sbSTerm | prSp<<32: - return sbSB8aSp, false, 90 - case sbSB8aClose | prSp<<32: - return sbSB8aSp, false, 90 - case sbATerm | prSep<<32: - return sbParaSep, false, 90 - case sbATerm | prCR<<32: - return sbParaSep, false, 90 - case sbATerm | prLF<<32: - return sbParaSep, false, 90 - case sbSB7 | prSep<<32: - return sbParaSep, false, 90 - case sbSB7 | prCR<<32: - return sbParaSep, false, 90 - case sbSB7 | prLF<<32: - return sbParaSep, false, 90 - case sbSB8Close | prSep<<32: - return sbParaSep, false, 90 - case sbSB8Close | prCR<<32: - return sbParaSep, false, 90 - case sbSB8Close | prLF<<32: - return sbParaSep, false, 90 - case sbSTerm | prSep<<32: - return sbParaSep, false, 90 - case sbSTerm | prCR<<32: - return sbParaSep, false, 90 - case sbSTerm | prLF<<32: - return sbParaSep, false, 90 - case sbSB8aClose | prSep<<32: - return sbParaSep, false, 90 - case sbSB8aClose | prCR<<32: - return sbParaSep, false, 90 - case sbSB8aClose | prLF<<32: - return sbParaSep, false, 90 + {sbATerm, prClose}: {sbSB8Close, sbDontBreak, 90}, + {sbSB7, prClose}: {sbSB8Close, sbDontBreak, 90}, + {sbSB8Close, prClose}: {sbSB8Close, sbDontBreak, 90}, + {sbATerm, prSp}: {sbSB8Sp, sbDontBreak, 90}, + {sbSB7, prSp}: {sbSB8Sp, sbDontBreak, 90}, + {sbSB8Close, prSp}: {sbSB8Sp, sbDontBreak, 90}, + {sbSTerm, prClose}: {sbSB8aClose, sbDontBreak, 90}, + {sbSB8aClose, prClose}: {sbSB8aClose, sbDontBreak, 90}, + {sbSTerm, prSp}: {sbSB8aSp, sbDontBreak, 90}, + {sbSB8aClose, prSp}: {sbSB8aSp, sbDontBreak, 90}, + {sbATerm, prSep}: {sbParaSep, sbDontBreak, 90}, + {sbATerm, prCR}: {sbParaSep, sbDontBreak, 90}, + {sbATerm, prLF}: {sbParaSep, sbDontBreak, 90}, + {sbSB7, prSep}: {sbParaSep, sbDontBreak, 90}, + {sbSB7, prCR}: {sbParaSep, sbDontBreak, 90}, + {sbSB7, prLF}: {sbParaSep, sbDontBreak, 90}, + {sbSB8Close, prSep}: {sbParaSep, sbDontBreak, 90}, + {sbSB8Close, prCR}: {sbParaSep, sbDontBreak, 90}, + {sbSB8Close, prLF}: {sbParaSep, sbDontBreak, 90}, + {sbSTerm, prSep}: {sbParaSep, sbDontBreak, 90}, + {sbSTerm, prCR}: {sbParaSep, sbDontBreak, 90}, + {sbSTerm, prLF}: {sbParaSep, sbDontBreak, 90}, + {sbSB8aClose, prSep}: {sbParaSep, sbDontBreak, 90}, + {sbSB8aClose, prCR}: {sbParaSep, sbDontBreak, 90}, + {sbSB8aClose, prLF}: {sbParaSep, sbDontBreak, 90}, // SB10. - case sbSB8Sp | prSp<<32: - return sbSB8Sp, false, 100 - case sbSB8aSp | prSp<<32: - return sbSB8aSp, false, 100 - case sbSB8Sp | prSep<<32: - return sbParaSep, false, 100 - case sbSB8Sp | prCR<<32: - return sbParaSep, false, 100 - case sbSB8Sp | prLF<<32: - return sbParaSep, false, 100 + {sbSB8Sp, prSp}: {sbSB8Sp, sbDontBreak, 100}, + {sbSB8aSp, prSp}: {sbSB8aSp, sbDontBreak, 100}, + {sbSB8Sp, prSep}: {sbParaSep, sbDontBreak, 100}, + {sbSB8Sp, prCR}: {sbParaSep, sbDontBreak, 100}, + {sbSB8Sp, prLF}: {sbParaSep, sbDontBreak, 100}, // SB11. - case sbATerm | prAny<<32: - return sbAny, true, 110 - case sbSB7 | prAny<<32: - return sbAny, true, 110 - case sbSB8Close | prAny<<32: - return sbAny, true, 110 - case sbSB8Sp | prAny<<32: - return sbAny, true, 110 - case sbSTerm | prAny<<32: - return sbAny, true, 110 - case sbSB8aClose | prAny<<32: - return sbAny, true, 110 - case sbSB8aSp | prAny<<32: - return sbAny, true, 110 + {sbATerm, prAny}: {sbAny, sbBreak, 110}, + {sbSB7, prAny}: {sbAny, sbBreak, 110}, + {sbSB8Close, prAny}: {sbAny, sbBreak, 110}, + {sbSB8Sp, prAny}: {sbAny, sbBreak, 110}, + {sbSTerm, prAny}: {sbAny, sbBreak, 110}, + {sbSB8aClose, prAny}: {sbAny, sbBreak, 110}, + {sbSB8aSp, prAny}: {sbAny, sbBreak, 110}, // We'll always break after ParaSep due to SB4. - - default: - return -1, false, -1 - } } // transitionSentenceBreakState determines the new state of the sentence break @@ -215,27 +141,30 @@ func transitionSentenceBreakState(state int, r rune, b []byte, str string) (newS // Find the applicable transition in the table. var rule int - newState, sentenceBreak, rule = sbTransitions(state, nextProperty) - if newState < 0 { + transition, ok := sbTransitions[[2]int{state, nextProperty}] + if ok { + // We have a specific transition. We'll use it. + newState, sentenceBreak, rule = transition[0], transition[1] == sbBreak, transition[2] + } else { // No specific transition found. Try the less specific ones. - anyPropState, anyPropProp, anyPropRule := sbTransitions(state, prAny) - anyStateState, anyStateProp, anyStateRule := sbTransitions(sbAny, nextProperty) - if anyPropState >= 0 && anyStateState >= 0 { + transAnyProp, okAnyProp := sbTransitions[[2]int{state, prAny}] + transAnyState, okAnyState := sbTransitions[[2]int{sbAny, nextProperty}] + if okAnyProp && okAnyState { // Both apply. We'll use a mix (see comments for grTransitions). - newState, sentenceBreak, rule = anyStateState, anyStateProp, anyStateRule - if anyPropRule < anyStateRule { - sentenceBreak, rule = anyPropProp, anyPropRule + newState, sentenceBreak, rule = transAnyState[0], transAnyState[1] == sbBreak, transAnyState[2] + if transAnyProp[2] < transAnyState[2] { + sentenceBreak, rule = transAnyProp[1] == sbBreak, transAnyProp[2] } - } else if anyPropState >= 0 { + } else if okAnyProp { // We only have a specific state. - newState, sentenceBreak, rule = anyPropState, anyPropProp, anyPropRule + newState, sentenceBreak, rule = transAnyProp[0], transAnyProp[1] == sbBreak, transAnyProp[2] // This branch will probably never be reached because okAnyState will // always be true given the current transition map. But we keep it here // for future modifications to the transition map where this may not be // true anymore. - } else if anyStateState >= 0 { + } else if okAnyState { // We only have a specific property. - newState, sentenceBreak, rule = anyStateState, anyStateProp, anyStateRule + newState, sentenceBreak, rule = transAnyState[0], transAnyState[1] == sbBreak, transAnyState[2] } else { // No known transition. SB999: Any × Any. newState, sentenceBreak, rule = sbAny, false, 9990 diff --git a/vendor/github.com/rivo/uniseg/step.go b/vendor/github.com/rivo/uniseg/step.go index 9b72c5e5..55e7f121 100644 --- a/vendor/github.com/rivo/uniseg/step.go +++ b/vendor/github.com/rivo/uniseg/step.go @@ -83,12 +83,10 @@ const ( // has much better performance and makes no allocations. It lends itself well to // large byte slices. // -// Note that in accordance with [UAX #14 LB3], the final segment will end with +// Note that in accordance with UAX #14 LB3, the final segment will end with // a mandatory line break (boundaries&MaskLine == LineMustBreak). You can choose // to ignore this by checking if the length of the "rest" slice is 0 and calling // [HasTrailingLineBreak] or [HasTrailingLineBreakInString] on the last rune. -// -// [UAX #14 LB3]: https://www.unicode.org/reports/tr14/#Algorithm func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { @@ -100,7 +98,7 @@ func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState i if len(b) <= length { // If we're already past the end, there is nothing else to parse. var prop int if state < 0 { - prop = propertyGraphemes(r) + prop = property(graphemeCodePoints, r) } else { prop = state >> shiftPropState } @@ -150,14 +148,16 @@ func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState i return b[:length], b[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState) | (prop << shiftPropState) } - if firstProp == prExtendedPictographic { + if r == vs16 { + width = 2 + } else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL { + width += runeWidth(r, prop) + } else if firstProp == prExtendedPictographic { if r == vs15 { width = 1 - } else if r == vs16 { + } else { width = 2 } - } else if firstProp != prRegionalIndicator && firstProp != prL { - width += runeWidth(r, prop) } length += l @@ -177,7 +177,7 @@ func StepString(str string, state int) (cluster, rest string, boundaries int, ne // Extract the first rune. r, length := utf8.DecodeRuneInString(str) if len(str) <= length { // If we're already past the end, there is nothing else to parse. - prop := propertyGraphemes(r) + prop := property(graphemeCodePoints, r) return str, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (runeWidth(r, prop) << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) } @@ -224,14 +224,16 @@ func StepString(str string, state int) (cluster, rest string, boundaries int, ne return str[:length], str[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState) | (prop << shiftPropState) } - if firstProp == prExtendedPictographic { + if r == vs16 { + width = 2 + } else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL { + width += runeWidth(r, prop) + } else if firstProp == prExtendedPictographic { if r == vs15 { width = 1 - } else if r == vs16 { + } else { width = 2 } - } else if firstProp != prRegionalIndicator && firstProp != prL { - width += runeWidth(r, prop) } length += l diff --git a/vendor/github.com/rivo/uniseg/width.go b/vendor/github.com/rivo/uniseg/width.go index 975a9f13..12a57cc2 100644 --- a/vendor/github.com/rivo/uniseg/width.go +++ b/vendor/github.com/rivo/uniseg/width.go @@ -1,10 +1,5 @@ package uniseg -// EastAsianAmbiguousWidth specifies the monospace width for East Asian -// characters classified as Ambiguous. The default is 1 but some rare fonts -// render them with a width of 2. -var EastAsianAmbiguousWidth = 1 - // runeWidth returns the monospace width for the given rune. The provided // grapheme property is a value mapped by the [graphemeCodePoints] table. // @@ -38,11 +33,9 @@ func runeWidth(r rune, graphemeProperty int) int { return 4 } - switch propertyEastAsianWidth(r) { + switch property(eastAsianWidth, r) { case prW, prF: return 2 - case prA: - return EastAsianAmbiguousWidth } return 1 diff --git a/vendor/github.com/rivo/uniseg/word.go b/vendor/github.com/rivo/uniseg/word.go index 34fba7f2..785af1e8 100644 --- a/vendor/github.com/rivo/uniseg/word.go +++ b/vendor/github.com/rivo/uniseg/word.go @@ -3,7 +3,7 @@ package uniseg import "unicode/utf8" // FirstWord returns the first word found in the given byte slice according to -// the rules of [Unicode Standard Annex #29, Word Boundaries]. This function can +// the rules of Unicode Standard Annex #29, Word Boundaries. This function can // be called continuously to extract all words from a byte slice, as illustrated // in the example below. // @@ -17,8 +17,6 @@ import "unicode/utf8" // the sub-slice of the input slice containing the identified word. // // Given an empty byte slice "b", the function returns nil values. -// -// [Unicode Standard Annex #29, Word Boundaries]: http://unicode.org/reports/tr29/#Word_Boundaries func FirstWord(b []byte, state int) (word, rest []byte, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/github.com/rivo/uniseg/wordproperties.go b/vendor/github.com/rivo/uniseg/wordproperties.go index 277ca100..805cc536 100644 --- a/vendor/github.com/rivo/uniseg/wordproperties.go +++ b/vendor/github.com/rivo/uniseg/wordproperties.go @@ -1,13 +1,13 @@ -// Code generated via go generate from gen_properties.go. DO NOT EDIT. - package uniseg +// Code generated via go generate from gen_properties.go. DO NOT EDIT. + // workBreakCodePoints are taken from -// https://www.unicode.org/Public/15.0.0/ucd/auxiliary/WordBreakProperty.txt +// https://www.unicode.org/Public/14.0.0/ucd/auxiliary/WordBreakProperty.txt // and -// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt +// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt // ("Extended_Pictographic" only) -// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode +// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode // license agreement. var workBreakCodePoints = [][3]int{ {0x000A, 0x000A, prLF}, // Cc @@ -318,7 +318,6 @@ var workBreakCodePoints = [][3]int{ {0x0CE2, 0x0CE3, prExtend}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL {0x0CE6, 0x0CEF, prNumeric}, // Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE {0x0CF1, 0x0CF2, prALetter}, // Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA - {0x0CF3, 0x0CF3, prExtend}, // Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT {0x0D00, 0x0D01, prExtend}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU {0x0D02, 0x0D03, prExtend}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA {0x0D04, 0x0D0C, prALetter}, // Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L @@ -358,7 +357,7 @@ var workBreakCodePoints = [][3]int{ {0x0E50, 0x0E59, prNumeric}, // Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE {0x0EB1, 0x0EB1, prExtend}, // Mn LAO VOWEL SIGN MAI KAN {0x0EB4, 0x0EBC, prExtend}, // Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO - {0x0EC8, 0x0ECE, prExtend}, // Mn [7] LAO TONE MAI EK..LAO YAMAKKAN + {0x0EC8, 0x0ECD, prExtend}, // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA {0x0ED0, 0x0ED9, prNumeric}, // Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE {0x0F00, 0x0F00, prALetter}, // Lo TIBETAN SYLLABLE OM {0x0F18, 0x0F19, prExtend}, // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS @@ -1094,7 +1093,6 @@ var workBreakCodePoints = [][3]int{ {0x10E80, 0x10EA9, prALetter}, // Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET {0x10EAB, 0x10EAC, prExtend}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK {0x10EB0, 0x10EB1, prALetter}, // Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE - {0x10EFD, 0x10EFF, prExtend}, // Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA {0x10F00, 0x10F1C, prALetter}, // Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL {0x10F27, 0x10F27, prALetter}, // Lo OLD SOGDIAN LIGATURE AYIN-DALETH {0x10F30, 0x10F45, prALetter}, // Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -1159,8 +1157,6 @@ var workBreakCodePoints = [][3]int{ {0x11235, 0x11235, prExtend}, // Mc KHOJKI SIGN VIRAMA {0x11236, 0x11237, prExtend}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA {0x1123E, 0x1123E, prExtend}, // Mn KHOJKI SIGN SUKUN - {0x1123F, 0x11240, prALetter}, // Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I - {0x11241, 0x11241, prExtend}, // Mn KHOJKI VOWEL SIGN VOCALIC R {0x11280, 0x11286, prALetter}, // Lo [7] MULTANI LETTER A..MULTANI LETTER GA {0x11288, 0x11288, prALetter}, // Lo MULTANI LETTER GHA {0x1128A, 0x1128D, prALetter}, // Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -1341,28 +1337,13 @@ var workBreakCodePoints = [][3]int{ {0x11EE0, 0x11EF2, prALetter}, // Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA {0x11EF3, 0x11EF4, prExtend}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U {0x11EF5, 0x11EF6, prExtend}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O - {0x11F00, 0x11F01, prExtend}, // Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA - {0x11F02, 0x11F02, prALetter}, // Lo KAWI SIGN REPHA - {0x11F03, 0x11F03, prExtend}, // Mc KAWI SIGN VISARGA - {0x11F04, 0x11F10, prALetter}, // Lo [13] KAWI LETTER A..KAWI LETTER O - {0x11F12, 0x11F33, prALetter}, // Lo [34] KAWI LETTER KA..KAWI LETTER JNYA - {0x11F34, 0x11F35, prExtend}, // Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA - {0x11F36, 0x11F3A, prExtend}, // Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R - {0x11F3E, 0x11F3F, prExtend}, // Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI - {0x11F40, 0x11F40, prExtend}, // Mn KAWI VOWEL SIGN EU - {0x11F41, 0x11F41, prExtend}, // Mc KAWI SIGN KILLER - {0x11F42, 0x11F42, prExtend}, // Mn KAWI CONJOINER - {0x11F50, 0x11F59, prNumeric}, // Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE {0x11FB0, 0x11FB0, prALetter}, // Lo LISU LETTER YHA {0x12000, 0x12399, prALetter}, // Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U {0x12400, 0x1246E, prALetter}, // Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM {0x12480, 0x12543, prALetter}, // Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU {0x12F90, 0x12FF0, prALetter}, // Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 - {0x13000, 0x1342F, prALetter}, // Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D - {0x13430, 0x1343F, prFormat}, // Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE - {0x13440, 0x13440, prExtend}, // Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY - {0x13441, 0x13446, prALetter}, // Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN - {0x13447, 0x13455, prExtend}, // Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED + {0x13000, 0x1342E, prALetter}, // Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 + {0x13430, 0x13438, prFormat}, // Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT {0x14400, 0x14646, prALetter}, // Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 {0x16800, 0x16A38, prALetter}, // Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ {0x16A40, 0x16A5E, prALetter}, // Lo [31] MRO LETTER TA..MRO LETTER TEK @@ -1393,7 +1374,6 @@ var workBreakCodePoints = [][3]int{ {0x1AFFD, 0x1AFFE, prKatakana}, // Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 {0x1B000, 0x1B000, prKatakana}, // Lo KATAKANA LETTER ARCHAIC E {0x1B120, 0x1B122, prKatakana}, // Lo [3] KATAKANA LETTER ARCHAIC YI..KATAKANA LETTER ARCHAIC WU - {0x1B155, 0x1B155, prKatakana}, // Lo KATAKANA LETTER SMALL KO {0x1B164, 0x1B167, prKatakana}, // Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N {0x1BC00, 0x1BC6A, prALetter}, // Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M {0x1BC70, 0x1BC7C, prALetter}, // Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK @@ -1451,14 +1431,11 @@ var workBreakCodePoints = [][3]int{ {0x1DF00, 0x1DF09, prALetter}, // L& [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK {0x1DF0A, 0x1DF0A, prALetter}, // Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK {0x1DF0B, 0x1DF1E, prALetter}, // L& [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL - {0x1DF25, 0x1DF2A, prALetter}, // L& [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK {0x1E000, 0x1E006, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE {0x1E008, 0x1E018, prExtend}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU {0x1E01B, 0x1E021, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI {0x1E023, 0x1E024, prExtend}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS {0x1E026, 0x1E02A, prExtend}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA - {0x1E030, 0x1E06D, prALetter}, // Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE - {0x1E08F, 0x1E08F, prExtend}, // Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I {0x1E100, 0x1E12C, prALetter}, // Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W {0x1E130, 0x1E136, prExtend}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D {0x1E137, 0x1E13D, prALetter}, // Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER @@ -1469,10 +1446,6 @@ var workBreakCodePoints = [][3]int{ {0x1E2C0, 0x1E2EB, prALetter}, // Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH {0x1E2EC, 0x1E2EF, prExtend}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI {0x1E2F0, 0x1E2F9, prNumeric}, // Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE - {0x1E4D0, 0x1E4EA, prALetter}, // Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL - {0x1E4EB, 0x1E4EB, prALetter}, // Lm NAG MUNDARI SIGN OJOD - {0x1E4EC, 0x1E4EF, prExtend}, // Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH - {0x1E4F0, 0x1E4F9, prNumeric}, // Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE {0x1E7E0, 0x1E7E6, prALetter}, // Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO {0x1E7E8, 0x1E7EB, prALetter}, // Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE {0x1E7ED, 0x1E7EE, prALetter}, // Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -1767,8 +1740,7 @@ var workBreakCodePoints = [][3]int{ {0x1F6D3, 0x1F6D4, prExtendedPictographic}, // E0.0 [2] (🛓..🛔) STUPA..PAGODA {0x1F6D5, 0x1F6D5, prExtendedPictographic}, // E12.0 [1] (🛕) hindu temple {0x1F6D6, 0x1F6D7, prExtendedPictographic}, // E13.0 [2] (🛖..🛗) hut..elevator - {0x1F6D8, 0x1F6DB, prExtendedPictographic}, // E0.0 [4] (🛘..🛛) .. - {0x1F6DC, 0x1F6DC, prExtendedPictographic}, // E15.0 [1] (🛜) wireless + {0x1F6D8, 0x1F6DC, prExtendedPictographic}, // E0.0 [5] (🛘..🛜) .. {0x1F6DD, 0x1F6DF, prExtendedPictographic}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy {0x1F6E0, 0x1F6E5, prExtendedPictographic}, // E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat {0x1F6E6, 0x1F6E8, prExtendedPictographic}, // E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE @@ -1785,7 +1757,7 @@ var workBreakCodePoints = [][3]int{ {0x1F6FA, 0x1F6FA, prExtendedPictographic}, // E12.0 [1] (🛺) auto rickshaw {0x1F6FB, 0x1F6FC, prExtendedPictographic}, // E13.0 [2] (🛻..🛼) pickup truck..roller skate {0x1F6FD, 0x1F6FF, prExtendedPictographic}, // E0.0 [3] (🛽..🛿) .. - {0x1F774, 0x1F77F, prExtendedPictographic}, // E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS + {0x1F774, 0x1F77F, prExtendedPictographic}, // E0.0 [12] (🝴..🝿) .. {0x1F7D5, 0x1F7DF, prExtendedPictographic}, // E0.0 [11] (🟕..🟟) CIRCLED TRIANGLE.. {0x1F7E0, 0x1F7EB, prExtendedPictographic}, // E12.0 [12] (🟠..🟫) orange circle..brown square {0x1F7EC, 0x1F7EF, prExtendedPictographic}, // E0.0 [4] (🟬..🟯) .. @@ -1844,37 +1816,30 @@ var workBreakCodePoints = [][3]int{ {0x1FA00, 0x1FA6F, prExtendedPictographic}, // E0.0 [112] (🨀..🩯) NEUTRAL CHESS KING.. {0x1FA70, 0x1FA73, prExtendedPictographic}, // E12.0 [4] (🩰..🩳) ballet shoes..shorts {0x1FA74, 0x1FA74, prExtendedPictographic}, // E13.0 [1] (🩴) thong sandal - {0x1FA75, 0x1FA77, prExtendedPictographic}, // E15.0 [3] (🩵..🩷) light blue heart..pink heart + {0x1FA75, 0x1FA77, prExtendedPictographic}, // E0.0 [3] (🩵..🩷) .. {0x1FA78, 0x1FA7A, prExtendedPictographic}, // E12.0 [3] (🩸..🩺) drop of blood..stethoscope {0x1FA7B, 0x1FA7C, prExtendedPictographic}, // E14.0 [2] (🩻..🩼) x-ray..crutch {0x1FA7D, 0x1FA7F, prExtendedPictographic}, // E0.0 [3] (🩽..🩿) .. {0x1FA80, 0x1FA82, prExtendedPictographic}, // E12.0 [3] (🪀..🪂) yo-yo..parachute {0x1FA83, 0x1FA86, prExtendedPictographic}, // E13.0 [4] (🪃..🪆) boomerang..nesting dolls - {0x1FA87, 0x1FA88, prExtendedPictographic}, // E15.0 [2] (🪇..🪈) maracas..flute - {0x1FA89, 0x1FA8F, prExtendedPictographic}, // E0.0 [7] (🪉..🪏) .. + {0x1FA87, 0x1FA8F, prExtendedPictographic}, // E0.0 [9] (🪇..🪏) .. {0x1FA90, 0x1FA95, prExtendedPictographic}, // E12.0 [6] (🪐..🪕) ringed planet..banjo {0x1FA96, 0x1FAA8, prExtendedPictographic}, // E13.0 [19] (🪖..🪨) military helmet..rock {0x1FAA9, 0x1FAAC, prExtendedPictographic}, // E14.0 [4] (🪩..🪬) mirror ball..hamsa - {0x1FAAD, 0x1FAAF, prExtendedPictographic}, // E15.0 [3] (🪭..🪯) folding hand fan..khanda + {0x1FAAD, 0x1FAAF, prExtendedPictographic}, // E0.0 [3] (🪭..🪯) .. {0x1FAB0, 0x1FAB6, prExtendedPictographic}, // E13.0 [7] (🪰..🪶) fly..feather {0x1FAB7, 0x1FABA, prExtendedPictographic}, // E14.0 [4] (🪷..🪺) lotus..nest with eggs - {0x1FABB, 0x1FABD, prExtendedPictographic}, // E15.0 [3] (🪻..🪽) hyacinth..wing - {0x1FABE, 0x1FABE, prExtendedPictographic}, // E0.0 [1] (🪾) - {0x1FABF, 0x1FABF, prExtendedPictographic}, // E15.0 [1] (🪿) goose + {0x1FABB, 0x1FABF, prExtendedPictographic}, // E0.0 [5] (🪻..🪿) .. {0x1FAC0, 0x1FAC2, prExtendedPictographic}, // E13.0 [3] (🫀..🫂) anatomical heart..people hugging {0x1FAC3, 0x1FAC5, prExtendedPictographic}, // E14.0 [3] (🫃..🫅) pregnant man..person with crown - {0x1FAC6, 0x1FACD, prExtendedPictographic}, // E0.0 [8] (🫆..🫍) .. - {0x1FACE, 0x1FACF, prExtendedPictographic}, // E15.0 [2] (🫎..🫏) moose..donkey + {0x1FAC6, 0x1FACF, prExtendedPictographic}, // E0.0 [10] (🫆..🫏) .. {0x1FAD0, 0x1FAD6, prExtendedPictographic}, // E13.0 [7] (🫐..🫖) blueberries..teapot {0x1FAD7, 0x1FAD9, prExtendedPictographic}, // E14.0 [3] (🫗..🫙) pouring liquid..jar - {0x1FADA, 0x1FADB, prExtendedPictographic}, // E15.0 [2] (🫚..🫛) ginger root..pea pod - {0x1FADC, 0x1FADF, prExtendedPictographic}, // E0.0 [4] (🫜..🫟) .. + {0x1FADA, 0x1FADF, prExtendedPictographic}, // E0.0 [6] (🫚..🫟) .. {0x1FAE0, 0x1FAE7, prExtendedPictographic}, // E14.0 [8] (🫠..🫧) melting face..bubbles - {0x1FAE8, 0x1FAE8, prExtendedPictographic}, // E15.0 [1] (🫨) shaking face - {0x1FAE9, 0x1FAEF, prExtendedPictographic}, // E0.0 [7] (🫩..🫯) .. + {0x1FAE8, 0x1FAEF, prExtendedPictographic}, // E0.0 [8] (🫨..🫯) .. {0x1FAF0, 0x1FAF6, prExtendedPictographic}, // E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands - {0x1FAF7, 0x1FAF8, prExtendedPictographic}, // E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand - {0x1FAF9, 0x1FAFF, prExtendedPictographic}, // E0.0 [7] (🫹..🫿) .. + {0x1FAF7, 0x1FAFF, prExtendedPictographic}, // E0.0 [9] (🫷..🫿) .. {0x1FBF0, 0x1FBF9, prNumeric}, // Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE {0x1FC00, 0x1FFFD, prExtendedPictographic}, // E0.0[1022] (🰀..🿽) .. {0xE0001, 0xE0001, prFormat}, // Cf LANGUAGE TAG diff --git a/vendor/github.com/rivo/uniseg/wordrules.go b/vendor/github.com/rivo/uniseg/wordrules.go index 57a8c683..325407e4 100644 --- a/vendor/github.com/rivo/uniseg/wordrules.go +++ b/vendor/github.com/rivo/uniseg/wordrules.go @@ -22,121 +22,82 @@ const ( wbZWJBit = 16 // This bit is set for any states followed by at least one zero-width joiner (see WB4 and WB3c). ) -// wbTransitions implements the word break parser's state transitions. It's -// anologous to [grTransitions], see comments there for details. -// -// Unicode version 15.0.0. -func wbTransitions(state, prop int) (newState int, wordBreak bool, rule int) { - switch uint64(state) | uint64(prop)<<32 { +// The word break parser's breaking instructions. +const ( + wbDontBreak = iota + wbBreak +) + +// The word break parser's state transitions. It's anologous to grTransitions, +// see comments there for details. Unicode version 14.0.0. +var wbTransitions = map[[2]int][3]int{ // WB3b. - case wbAny | prNewline<<32: - return wbNewline, true, 32 - case wbAny | prCR<<32: - return wbCR, true, 32 - case wbAny | prLF<<32: - return wbLF, true, 32 + {wbAny, prNewline}: {wbNewline, wbBreak, 32}, + {wbAny, prCR}: {wbCR, wbBreak, 32}, + {wbAny, prLF}: {wbLF, wbBreak, 32}, // WB3a. - case wbNewline | prAny<<32: - return wbAny, true, 31 - case wbCR | prAny<<32: - return wbAny, true, 31 - case wbLF | prAny<<32: - return wbAny, true, 31 + {wbNewline, prAny}: {wbAny, wbBreak, 31}, + {wbCR, prAny}: {wbAny, wbBreak, 31}, + {wbLF, prAny}: {wbAny, wbBreak, 31}, // WB3. - case wbCR | prLF<<32: - return wbLF, false, 30 + {wbCR, prLF}: {wbLF, wbDontBreak, 30}, // WB3d. - case wbAny | prWSegSpace<<32: - return wbWSegSpace, true, 9990 - case wbWSegSpace | prWSegSpace<<32: - return wbWSegSpace, false, 34 + {wbAny, prWSegSpace}: {wbWSegSpace, wbBreak, 9990}, + {wbWSegSpace, prWSegSpace}: {wbWSegSpace, wbDontBreak, 34}, // WB5. - case wbAny | prALetter<<32: - return wbALetter, true, 9990 - case wbAny | prHebrewLetter<<32: - return wbHebrewLetter, true, 9990 - case wbALetter | prALetter<<32: - return wbALetter, false, 50 - case wbALetter | prHebrewLetter<<32: - return wbHebrewLetter, false, 50 - case wbHebrewLetter | prALetter<<32: - return wbALetter, false, 50 - case wbHebrewLetter | prHebrewLetter<<32: - return wbHebrewLetter, false, 50 + {wbAny, prALetter}: {wbALetter, wbBreak, 9990}, + {wbAny, prHebrewLetter}: {wbHebrewLetter, wbBreak, 9990}, + {wbALetter, prALetter}: {wbALetter, wbDontBreak, 50}, + {wbALetter, prHebrewLetter}: {wbHebrewLetter, wbDontBreak, 50}, + {wbHebrewLetter, prALetter}: {wbALetter, wbDontBreak, 50}, + {wbHebrewLetter, prHebrewLetter}: {wbHebrewLetter, wbDontBreak, 50}, // WB7. Transitions to wbWB7 handled by transitionWordBreakState(). - case wbWB7 | prALetter<<32: - return wbALetter, false, 70 - case wbWB7 | prHebrewLetter<<32: - return wbHebrewLetter, false, 70 + {wbWB7, prALetter}: {wbALetter, wbDontBreak, 70}, + {wbWB7, prHebrewLetter}: {wbHebrewLetter, wbDontBreak, 70}, // WB7a. - case wbHebrewLetter | prSingleQuote<<32: - return wbAny, false, 71 + {wbHebrewLetter, prSingleQuote}: {wbAny, wbDontBreak, 71}, // WB7c. Transitions to wbWB7c handled by transitionWordBreakState(). - case wbWB7c | prHebrewLetter<<32: - return wbHebrewLetter, false, 73 + {wbWB7c, prHebrewLetter}: {wbHebrewLetter, wbDontBreak, 73}, // WB8. - case wbAny | prNumeric<<32: - return wbNumeric, true, 9990 - case wbNumeric | prNumeric<<32: - return wbNumeric, false, 80 + {wbAny, prNumeric}: {wbNumeric, wbBreak, 9990}, + {wbNumeric, prNumeric}: {wbNumeric, wbDontBreak, 80}, // WB9. - case wbALetter | prNumeric<<32: - return wbNumeric, false, 90 - case wbHebrewLetter | prNumeric<<32: - return wbNumeric, false, 90 + {wbALetter, prNumeric}: {wbNumeric, wbDontBreak, 90}, + {wbHebrewLetter, prNumeric}: {wbNumeric, wbDontBreak, 90}, // WB10. - case wbNumeric | prALetter<<32: - return wbALetter, false, 100 - case wbNumeric | prHebrewLetter<<32: - return wbHebrewLetter, false, 100 + {wbNumeric, prALetter}: {wbALetter, wbDontBreak, 100}, + {wbNumeric, prHebrewLetter}: {wbHebrewLetter, wbDontBreak, 100}, // WB11. Transitions to wbWB11 handled by transitionWordBreakState(). - case wbWB11 | prNumeric<<32: - return wbNumeric, false, 110 + {wbWB11, prNumeric}: {wbNumeric, wbDontBreak, 110}, // WB13. - case wbAny | prKatakana<<32: - return wbKatakana, true, 9990 - case wbKatakana | prKatakana<<32: - return wbKatakana, false, 130 + {wbAny, prKatakana}: {wbKatakana, wbBreak, 9990}, + {wbKatakana, prKatakana}: {wbKatakana, wbDontBreak, 130}, // WB13a. - case wbAny | prExtendNumLet<<32: - return wbExtendNumLet, true, 9990 - case wbALetter | prExtendNumLet<<32: - return wbExtendNumLet, false, 131 - case wbHebrewLetter | prExtendNumLet<<32: - return wbExtendNumLet, false, 131 - case wbNumeric | prExtendNumLet<<32: - return wbExtendNumLet, false, 131 - case wbKatakana | prExtendNumLet<<32: - return wbExtendNumLet, false, 131 - case wbExtendNumLet | prExtendNumLet<<32: - return wbExtendNumLet, false, 131 + {wbAny, prExtendNumLet}: {wbExtendNumLet, wbBreak, 9990}, + {wbALetter, prExtendNumLet}: {wbExtendNumLet, wbDontBreak, 131}, + {wbHebrewLetter, prExtendNumLet}: {wbExtendNumLet, wbDontBreak, 131}, + {wbNumeric, prExtendNumLet}: {wbExtendNumLet, wbDontBreak, 131}, + {wbKatakana, prExtendNumLet}: {wbExtendNumLet, wbDontBreak, 131}, + {wbExtendNumLet, prExtendNumLet}: {wbExtendNumLet, wbDontBreak, 131}, // WB13b. - case wbExtendNumLet | prALetter<<32: - return wbALetter, false, 132 - case wbExtendNumLet | prHebrewLetter<<32: - return wbHebrewLetter, false, 132 - case wbExtendNumLet | prNumeric<<32: - return wbNumeric, false, 132 - case wbExtendNumLet | prKatakana<<32: - return wbKatakana, false, 132 - - default: - return -1, false, -1 - } + {wbExtendNumLet, prALetter}: {wbALetter, wbDontBreak, 132}, + {wbExtendNumLet, prHebrewLetter}: {wbHebrewLetter, wbDontBreak, 132}, + {wbExtendNumLet, prNumeric}: {wbNumeric, wbDontBreak, 132}, + {wbExtendNumLet, prKatakana}: {prKatakana, wbDontBreak, 132}, } // transitionWordBreakState determines the new state of the word break parser @@ -180,27 +141,30 @@ func transitionWordBreakState(state int, r rune, b []byte, str string) (newState // Find the applicable transition in the table. var rule int - newState, wordBreak, rule = wbTransitions(state, nextProperty) - if newState < 0 { + transition, ok := wbTransitions[[2]int{state, nextProperty}] + if ok { + // We have a specific transition. We'll use it. + newState, wordBreak, rule = transition[0], transition[1] == wbBreak, transition[2] + } else { // No specific transition found. Try the less specific ones. - anyPropState, anyPropWordBreak, anyPropRule := wbTransitions(state, prAny) - anyStateState, anyStateWordBreak, anyStateRule := wbTransitions(wbAny, nextProperty) - if anyPropState >= 0 && anyStateState >= 0 { + transAnyProp, okAnyProp := wbTransitions[[2]int{state, prAny}] + transAnyState, okAnyState := wbTransitions[[2]int{wbAny, nextProperty}] + if okAnyProp && okAnyState { // Both apply. We'll use a mix (see comments for grTransitions). - newState, wordBreak, rule = anyStateState, anyStateWordBreak, anyStateRule - if anyPropRule < anyStateRule { - wordBreak, rule = anyPropWordBreak, anyPropRule + newState, wordBreak, rule = transAnyState[0], transAnyState[1] == wbBreak, transAnyState[2] + if transAnyProp[2] < transAnyState[2] { + wordBreak, rule = transAnyProp[1] == wbBreak, transAnyProp[2] } - } else if anyPropState >= 0 { + } else if okAnyProp { // We only have a specific state. - newState, wordBreak, rule = anyPropState, anyPropWordBreak, anyPropRule + newState, wordBreak, rule = transAnyProp[0], transAnyProp[1] == wbBreak, transAnyProp[2] // This branch will probably never be reached because okAnyState will // always be true given the current transition map. But we keep it here // for future modifications to the transition map where this may not be // true anymore. - } else if anyStateState >= 0 { + } else if okAnyState { // We only have a specific property. - newState, wordBreak, rule = anyStateState, anyStateWordBreak, anyStateRule + newState, wordBreak, rule = transAnyState[0], transAnyState[1] == wbBreak, transAnyState[2] } else { // No known transition. WB999: Any ÷ Any. newState, wordBreak, rule = wbAny, true, 9990 diff --git a/vendor/github.com/rs/cors/.travis.yml b/vendor/github.com/rs/cors/.travis.yml new file mode 100644 index 00000000..9a68b567 --- /dev/null +++ b/vendor/github.com/rs/cors/.travis.yml @@ -0,0 +1,9 @@ +language: go +go: +- "1.10" +- "1.11" +- "1.12" +- tip +matrix: + allow_failures: + - go: tip diff --git a/vendor/github.com/rs/cors/README.md b/vendor/github.com/rs/cors/README.md index c7fbea00..ecc83b29 100644 --- a/vendor/github.com/rs/cors/README.md +++ b/vendor/github.com/rs/cors/README.md @@ -1,4 +1,4 @@ -# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![Go Coverage](https://github.com/rs/cors/wiki/coverage.svg)](https://raw.githack.com/wiki/rs/cors/coverage.html) +# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![build](https://img.shields.io/travis/rs/cors.svg?style=flat)](https://travis-ci.org/rs/cors) [![Coverage](http://gocover.io/_badge/github.com/rs/cors)](http://gocover.io/github.com/rs/cors) CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang. @@ -88,37 +88,27 @@ handler = c.Handler(handler) * **AllowedOrigins** `[]string`: A list of origins a cross-domain request can be executed from. If the special `*` value is present in the list, all origins will be allowed. An origin may contain a wildcard (`*`) to replace 0 or more characters (i.e.: `http://*.domain.com`). Usage of wildcards implies a small performance penality. Only one wildcard can be used per origin. The default value is `*`. * **AllowOriginFunc** `func (origin string) bool`: A custom function to validate the origin. It takes the origin as an argument and returns true if allowed, or false otherwise. If this option is set, the content of `AllowedOrigins` is ignored. -* **AllowOriginRequestFunc** `func (r *http.Request, origin string) bool`: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise. If this option is set, the contents of `AllowedOrigins` and `AllowOriginFunc` are ignored. -Deprecated: use `AllowOriginVaryRequestFunc` instead. -* **AllowOriginVaryRequestFunc** `func(r *http.Request, origin string) (bool, []string)`: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise with a list of headers used to take that decision if any so they can be added to the Vary header. If this option is set, the contents of `AllowedOrigins`, `AllowOriginFunc` and `AllowOriginRequestFunc` are ignored. +* **AllowOriginRequestFunc** `func (r *http.Request origin string) bool`: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins` and `AllowOriginFunc` is ignored * **AllowedMethods** `[]string`: A list of methods the client is allowed to use with cross-domain requests. Default value is simple methods (`GET` and `POST`). * **AllowedHeaders** `[]string`: A list of non simple headers the client is allowed to use with cross-domain requests. -* **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification. +* **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification * **AllowCredentials** `bool`: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is `false`. -* **AllowPrivateNetwork** `bool`: Indicates whether to accept cross-origin requests over a private network. * **MaxAge** `int`: Indicates how long (in seconds) the results of a preflight request can be cached. The default is `0` which stands for no max age. * **OptionsPassthrough** `bool`: Instructs preflight to let other potential next handlers to process the `OPTIONS` method. Turn this on if your application handles `OPTIONS`. -* **OptionsSuccessStatus** `int`: Provides a status code to use for successful OPTIONS requests. Default value is `http.StatusNoContent` (`204`). * **Debug** `bool`: Debugging flag adds additional output to debug server side CORS issues. See [API documentation](http://godoc.org/github.com/rs/cors) for more info. ## Benchmarks -``` -goos: darwin -goarch: arm64 -pkg: github.com/rs/cors -BenchmarkWithout-10 135325480 8.124 ns/op 0 B/op 0 allocs/op -BenchmarkDefault-10 24082140 51.40 ns/op 0 B/op 0 allocs/op -BenchmarkAllowedOrigin-10 16424518 88.25 ns/op 0 B/op 0 allocs/op -BenchmarkPreflight-10 8010259 147.3 ns/op 0 B/op 0 allocs/op -BenchmarkPreflightHeader-10 6850962 175.0 ns/op 0 B/op 0 allocs/op -BenchmarkWildcard/match-10 253275342 4.714 ns/op 0 B/op 0 allocs/op -BenchmarkWildcard/too_short-10 1000000000 0.6235 ns/op 0 B/op 0 allocs/op -PASS -ok github.com/rs/cors 99.131s -``` + BenchmarkWithout 20000000 64.6 ns/op 8 B/op 1 allocs/op + BenchmarkDefault 3000000 469 ns/op 114 B/op 2 allocs/op + BenchmarkAllowedOrigin 3000000 608 ns/op 114 B/op 2 allocs/op + BenchmarkPreflight 20000000 73.2 ns/op 0 B/op 0 allocs/op + BenchmarkPreflightHeader 20000000 73.6 ns/op 0 B/op 0 allocs/op + BenchmarkParseHeaderList 2000000 847 ns/op 184 B/op 6 allocs/op + BenchmarkParse…Single 5000000 290 ns/op 32 B/op 3 allocs/op + BenchmarkParse…Normalized 2000000 776 ns/op 160 B/op 6 allocs/op ## Licenses diff --git a/vendor/github.com/rs/cors/cors.go b/vendor/github.com/rs/cors/cors.go index da80d343..27309346 100644 --- a/vendor/github.com/rs/cors/cors.go +++ b/vendor/github.com/rs/cors/cors.go @@ -4,15 +4,15 @@ as defined by http://www.w3.org/TR/cors/ You can configure it by passing an option struct to cors.New: - c := cors.New(cors.Options{ - AllowedOrigins: []string{"foo.com"}, - AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete}, - AllowCredentials: true, - }) + c := cors.New(cors.Options{ + AllowedOrigins: []string{"foo.com"}, + AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete}, + AllowCredentials: true, + }) Then insert the handler in the chain: - handler = c.Handler(handler) + handler = c.Handler(handler) See Options documentation for more options. @@ -26,14 +26,8 @@ import ( "os" "strconv" "strings" - - "github.com/rs/cors/internal" ) -var headerVaryOrigin = []string{"Origin"} -var headerOriginAll = []string{"*"} -var headerTrue = []string{"true"} - // Options is a configuration container to setup the CORS middleware. type Options struct { // AllowedOrigins is a list of origins a cross-domain request can be executed from. @@ -43,58 +37,36 @@ type Options struct { // Only one wildcard can be used per origin. // Default value is ["*"] AllowedOrigins []string - // AllowOriginFunc is a custom function to validate the origin. It take the - // origin as argument and returns true if allowed or false otherwise. If - // this option is set, the content of `AllowedOrigins` is ignored. + // AllowOriginFunc is a custom function to validate the origin. It take the origin + // as argument and returns true if allowed or false otherwise. If this option is + // set, the content of AllowedOrigins is ignored. AllowOriginFunc func(origin string) bool - // AllowOriginRequestFunc is a custom function to validate the origin. It - // takes the HTTP Request object and the origin as argument and returns true - // if allowed or false otherwise. If headers are used take the decision, - // consider using AllowOriginVaryRequestFunc instead. If this option is set, - // the contents of `AllowedOrigins`, `AllowOriginFunc` are ignored. - // - // Deprecated: use `AllowOriginVaryRequestFunc` instead. + // AllowOriginFunc is a custom function to validate the origin. It takes the HTTP Request object and the origin as + // argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins` + // and `AllowOriginFunc` is ignored. AllowOriginRequestFunc func(r *http.Request, origin string) bool - // AllowOriginVaryRequestFunc is a custom function to validate the origin. - // It takes the HTTP Request object and the origin as argument and returns - // true if allowed or false otherwise with a list of headers used to take - // that decision if any so they can be added to the Vary header. If this - // option is set, the contents of `AllowedOrigins`, `AllowOriginFunc` and - // `AllowOriginRequestFunc` are ignored. - AllowOriginVaryRequestFunc func(r *http.Request, origin string) (bool, []string) // AllowedMethods is a list of methods the client is allowed to use with // cross-domain requests. Default value is simple methods (HEAD, GET and POST). AllowedMethods []string // AllowedHeaders is list of non simple headers the client is allowed to use with // cross-domain requests. // If the special "*" value is present in the list, all headers will be allowed. - // Default value is []. + // Default value is [] but "Origin" is always appended to the list. AllowedHeaders []string // ExposedHeaders indicates which headers are safe to expose to the API of a CORS // API specification ExposedHeaders []string // MaxAge indicates how long (in seconds) the results of a preflight request - // can be cached. Default value is 0, which stands for no - // Access-Control-Max-Age header to be sent back, resulting in browsers - // using their default value (5s by spec). If you need to force a 0 max-age, - // set `MaxAge` to a negative value (ie: -1). + // can be cached MaxAge int // AllowCredentials indicates whether the request can include user credentials like // cookies, HTTP authentication or client side SSL certificates. AllowCredentials bool - // AllowPrivateNetwork indicates whether to accept cross-origin requests over a - // private network. - AllowPrivateNetwork bool // OptionsPassthrough instructs preflight to let other potential next handlers to // process the OPTIONS method. Turn this on if your application handles OPTIONS. OptionsPassthrough bool - // Provides a status code to use for successful OPTIONS requests. - // Default value is http.StatusNoContent (204). - OptionsSuccessStatus int // Debugging flag adds additional output to debug server side CORS issues Debug bool - // Adds a custom logger, implies Debug is true - Logger Logger } // Logger generic interface for logger @@ -111,66 +83,53 @@ type Cors struct { // List of allowed origins containing wildcards allowedWOrigins []wildcard // Optional origin validator function - allowOriginFunc func(r *http.Request, origin string) (bool, []string) + allowOriginFunc func(origin string) bool + // Optional origin validator (with request) function + allowOriginRequestFunc func(r *http.Request, origin string) bool // Normalized list of allowed headers - // Note: the Fetch standard guarantees that CORS-unsafe request-header names - // (i.e. the values listed in the Access-Control-Request-Headers header) - // are unique and sorted; - // see https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names. - allowedHeaders internal.SortedSet + allowedHeaders []string // Normalized list of allowed methods allowedMethods []string - // Pre-computed normalized list of exposed headers + // Normalized list of exposed headers exposedHeaders []string - // Pre-computed maxAge header value - maxAge []string + maxAge int // Set to true when allowed origins contains a "*" allowedOriginsAll bool // Set to true when allowed headers contains a "*" allowedHeadersAll bool - // Status code to use for successful OPTIONS requests - optionsSuccessStatus int - allowCredentials bool - allowPrivateNetwork bool - optionPassthrough bool - preflightVary []string + allowCredentials bool + optionPassthrough bool } // New creates a new Cors handler with the provided options. func New(options Options) *Cors { c := &Cors{ - allowCredentials: options.AllowCredentials, - allowPrivateNetwork: options.AllowPrivateNetwork, - optionPassthrough: options.OptionsPassthrough, - Log: options.Logger, + exposedHeaders: convert(options.ExposedHeaders, http.CanonicalHeaderKey), + allowOriginFunc: options.AllowOriginFunc, + allowOriginRequestFunc: options.AllowOriginRequestFunc, + allowCredentials: options.AllowCredentials, + maxAge: options.MaxAge, + optionPassthrough: options.OptionsPassthrough, } if options.Debug && c.Log == nil { c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags) } - // Allowed origins - switch { - case options.AllowOriginVaryRequestFunc != nil: - c.allowOriginFunc = options.AllowOriginVaryRequestFunc - case options.AllowOriginRequestFunc != nil: - c.allowOriginFunc = func(r *http.Request, origin string) (bool, []string) { - return options.AllowOriginRequestFunc(r, origin), nil - } - case options.AllowOriginFunc != nil: - c.allowOriginFunc = func(r *http.Request, origin string) (bool, []string) { - return options.AllowOriginFunc(origin), nil - } - case len(options.AllowedOrigins) == 0: - if c.allowOriginFunc == nil { + // Normalize options + // Note: for origins and methods matching, the spec requires a case-sensitive matching. + // As it may error prone, we chose to ignore the spec here. + + // Allowed Origins + if len(options.AllowedOrigins) == 0 { + if options.AllowOriginFunc == nil && options.AllowOriginRequestFunc == nil { // Default is all origins c.allowedOriginsAll = true } - default: + } else { c.allowedOrigins = []string{} c.allowedWOrigins = []wildcard{} for _, origin := range options.AllowedOrigins { - // Note: for origins matching, the spec requires a case-sensitive matching. - // As it may error prone, we chose to ignore the spec here. + // Normalize origin = strings.ToLower(origin) if origin == "*" { // If "*" is present in the list, turn the whole list into a match all @@ -189,19 +148,16 @@ func New(options Options) *Cors { } // Allowed Headers - // Note: the Fetch standard guarantees that CORS-unsafe request-header names - // (i.e. the values listed in the Access-Control-Request-Headers header) - // are lowercase; see https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names. if len(options.AllowedHeaders) == 0 { // Use sensible defaults - c.allowedHeaders = internal.NewSortedSet("accept", "content-type", "x-requested-with") + c.allowedHeaders = []string{"Origin", "Accept", "Content-Type", "X-Requested-With"} } else { - normalized := convert(options.AllowedHeaders, strings.ToLower) - c.allowedHeaders = internal.NewSortedSet(normalized...) + // Origin is always appended as some browsers will always request for this header at preflight + c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey) for _, h := range options.AllowedHeaders { if h == "*" { c.allowedHeadersAll = true - c.allowedHeaders = internal.SortedSet{} + c.allowedHeaders = nil break } } @@ -212,33 +168,7 @@ func New(options Options) *Cors { // Default is spec's "simple" methods c.allowedMethods = []string{http.MethodGet, http.MethodPost, http.MethodHead} } else { - c.allowedMethods = options.AllowedMethods - } - - // Options Success Status Code - if options.OptionsSuccessStatus == 0 { - c.optionsSuccessStatus = http.StatusNoContent - } else { - c.optionsSuccessStatus = options.OptionsSuccessStatus - } - - // Pre-compute exposed headers header value - if len(options.ExposedHeaders) > 0 { - c.exposedHeaders = []string{strings.Join(convert(options.ExposedHeaders, http.CanonicalHeaderKey), ", ")} - } - - // Pre-compute prefight Vary header to save allocations - if c.allowPrivateNetwork { - c.preflightVary = []string{"Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Private-Network"} - } else { - c.preflightVary = []string{"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"} - } - - // Precompute max-age - if options.MaxAge > 0 { - c.maxAge = []string{strconv.Itoa(options.MaxAge)} - } else if options.MaxAge < 0 { - c.maxAge = []string{"0"} + c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper) } return c @@ -281,7 +211,7 @@ func (c *Cors) Handler(h http.Handler) http.Handler { if c.optionPassthrough { h.ServeHTTP(w, r) } else { - w.WriteHeader(c.optionsSuccessStatus) + w.WriteHeader(http.StatusOK) } } else { c.logf("Handler: Actual request") @@ -296,8 +226,6 @@ func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("HandlerFunc: Preflight request") c.handlePreflight(w, r) - - w.WriteHeader(c.optionsSuccessStatus) } else { c.logf("HandlerFunc: Actual request") c.handleActualRequest(w, r) @@ -316,7 +244,7 @@ func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.Handl if c.optionPassthrough { next(w, r) } else { - w.WriteHeader(c.optionsSuccessStatus) + w.WriteHeader(http.StatusOK) } } else { c.logf("ServeHTTP: Actual request") @@ -337,21 +265,15 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { // Always set Vary headers // see https://github.com/rs/cors/issues/10, // https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001 - if vary, found := headers["Vary"]; found { - headers["Vary"] = append(vary, c.preflightVary[0]) - } else { - headers["Vary"] = c.preflightVary - } - allowed, additionalVaryHeaders := c.isOriginAllowed(r, origin) - if len(additionalVaryHeaders) > 0 { - headers.Add("Vary", strings.Join(convert(additionalVaryHeaders, http.CanonicalHeaderKey), ", ")) - } + headers.Add("Vary", "Origin") + headers.Add("Vary", "Access-Control-Request-Method") + headers.Add("Vary", "Access-Control-Request-Headers") if origin == "" { c.logf(" Preflight aborted: empty origin") return } - if !allowed { + if !c.isOriginAllowed(r, origin) { c.logf(" Preflight aborted: origin '%s' not allowed", origin) return } @@ -361,39 +283,32 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { c.logf(" Preflight aborted: method '%s' not allowed", reqMethod) return } - // Note: the Fetch standard guarantees that at most one - // Access-Control-Request-Headers header is present in the preflight request; - // see step 5.2 in https://fetch.spec.whatwg.org/#cors-preflight-fetch-0. - reqHeaders, found := first(r.Header, "Access-Control-Request-Headers") - if found && !c.allowedHeadersAll && !c.allowedHeaders.Subsumes(reqHeaders[0]) { - c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders[0]) + reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers")) + if !c.areHeadersAllowed(reqHeaders) { + c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders) return } if c.allowedOriginsAll { - headers["Access-Control-Allow-Origin"] = headerOriginAll + headers.Set("Access-Control-Allow-Origin", "*") } else { - headers["Access-Control-Allow-Origin"] = r.Header["Origin"] + headers.Set("Access-Control-Allow-Origin", origin) } // Spec says: Since the list of methods can be unbounded, simply returning the method indicated // by Access-Control-Request-Method (if supported) can be enough - headers["Access-Control-Allow-Methods"] = r.Header["Access-Control-Request-Method"] - if found && len(reqHeaders[0]) > 0 { + headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod)) + if len(reqHeaders) > 0 { + // Spec says: Since the list of headers can be unbounded, simply returning supported headers // from Access-Control-Request-Headers can be enough - headers["Access-Control-Allow-Headers"] = reqHeaders + headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", ")) } if c.allowCredentials { - headers["Access-Control-Allow-Credentials"] = headerTrue + headers.Set("Access-Control-Allow-Credentials", "true") } - if c.allowPrivateNetwork && r.Header.Get("Access-Control-Request-Private-Network") == "true" { - headers["Access-Control-Allow-Private-Network"] = headerTrue - } - if len(c.maxAge) > 0 { - headers["Access-Control-Max-Age"] = c.maxAge - } - if c.Log != nil { - c.logf(" Preflight response headers: %v", headers) + if c.maxAge > 0 { + headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge)) } + c.logf(" Preflight response headers: %v", headers) } // handleActualRequest handles simple cross-origin requests, actual request or redirects @@ -401,22 +316,13 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { headers := w.Header() origin := r.Header.Get("Origin") - allowed, additionalVaryHeaders := c.isOriginAllowed(r, origin) - // Always set Vary, see https://github.com/rs/cors/issues/10 - if vary := headers["Vary"]; vary == nil { - headers["Vary"] = headerVaryOrigin - } else { - headers["Vary"] = append(vary, headerVaryOrigin[0]) - } - if len(additionalVaryHeaders) > 0 { - headers.Add("Vary", strings.Join(convert(additionalVaryHeaders, http.CanonicalHeaderKey), ", ")) - } + headers.Add("Vary", "Origin") if origin == "" { c.logf(" Actual request no headers added: missing origin") return } - if !allowed { + if !c.isOriginAllowed(r, origin) { c.logf(" Actual request no headers added: origin '%s' not allowed", origin) return } @@ -427,22 +333,21 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { // We think it's a nice feature to be able to have control on those methods though. if !c.isMethodAllowed(r.Method) { c.logf(" Actual request no headers added: method '%s' not allowed", r.Method) + return } if c.allowedOriginsAll { - headers["Access-Control-Allow-Origin"] = headerOriginAll + headers.Set("Access-Control-Allow-Origin", "*") } else { - headers["Access-Control-Allow-Origin"] = r.Header["Origin"] + headers.Set("Access-Control-Allow-Origin", origin) } if len(c.exposedHeaders) > 0 { - headers["Access-Control-Expose-Headers"] = c.exposedHeaders + headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", ")) } if c.allowCredentials { - headers["Access-Control-Allow-Credentials"] = headerTrue - } - if c.Log != nil { - c.logf(" Actual response added headers: %v", headers) + headers.Set("Access-Control-Allow-Credentials", "true") } + c.logf(" Actual response added headers: %v", headers) } // convenience method. checks if a logger is set. @@ -452,43 +357,40 @@ func (c *Cors) logf(format string, a ...interface{}) { } } -// check the Origin of a request. No origin at all is also allowed. -func (c *Cors) OriginAllowed(r *http.Request) bool { - origin := r.Header.Get("Origin") - allowed, _ := c.isOriginAllowed(r, origin) - return allowed -} - // isOriginAllowed checks if a given origin is allowed to perform cross-domain requests // on the endpoint -func (c *Cors) isOriginAllowed(r *http.Request, origin string) (allowed bool, varyHeaders []string) { +func (c *Cors) isOriginAllowed(r *http.Request, origin string) bool { + if c.allowOriginRequestFunc != nil { + return c.allowOriginRequestFunc(r, origin) + } if c.allowOriginFunc != nil { - return c.allowOriginFunc(r, origin) + return c.allowOriginFunc(origin) } if c.allowedOriginsAll { - return true, nil + return true } origin = strings.ToLower(origin) for _, o := range c.allowedOrigins { if o == origin { - return true, nil + return true } } for _, w := range c.allowedWOrigins { if w.match(origin) { - return true, nil + return true } } - return false, nil + return false } // isMethodAllowed checks if a given method can be used as part of a cross-domain request -// on the endpoint +// on the endpoing func (c *Cors) isMethodAllowed(method string) bool { if len(c.allowedMethods) == 0 { // If no method allowed, always return false, even for preflight request return false } + method = strings.ToUpper(method) if method == http.MethodOptions { // Always allow preflight requests return true @@ -500,3 +402,24 @@ func (c *Cors) isMethodAllowed(method string) bool { } return false } + +// areHeadersAllowed checks if a given list of headers are allowed to used within +// a cross-domain request. +func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool { + if c.allowedHeadersAll || len(requestedHeaders) == 0 { + return true + } + for _, header := range requestedHeaders { + header = http.CanonicalHeaderKey(header) + found := false + for _, h := range c.allowedHeaders { + if h == header { + found = true + } + } + if !found { + return false + } + } + return true +} diff --git a/vendor/github.com/rs/cors/internal/sortedset.go b/vendor/github.com/rs/cors/internal/sortedset.go deleted file mode 100644 index 513da20f..00000000 --- a/vendor/github.com/rs/cors/internal/sortedset.go +++ /dev/null @@ -1,113 +0,0 @@ -// adapted from github.com/jub0bs/cors -package internal - -import ( - "sort" - "strings" -) - -// A SortedSet represents a mathematical set of strings sorted in -// lexicographical order. -// Each element has a unique position ranging from 0 (inclusive) -// to the set's cardinality (exclusive). -// The zero value represents an empty set. -type SortedSet struct { - m map[string]int - maxLen int -} - -// NewSortedSet returns a SortedSet that contains all of elems, -// but no other elements. -func NewSortedSet(elems ...string) SortedSet { - sort.Strings(elems) - m := make(map[string]int) - var maxLen int - i := 0 - for _, s := range elems { - if _, exists := m[s]; exists { - continue - } - m[s] = i - i++ - maxLen = max(maxLen, len(s)) - } - return SortedSet{ - m: m, - maxLen: maxLen, - } -} - -// Size returns the cardinality of set. -func (set SortedSet) Size() int { - return len(set.m) -} - -// String sorts joins the elements of set (in lexicographical order) -// with a comma and returns the resulting string. -func (set SortedSet) String() string { - elems := make([]string, len(set.m)) - for elem, i := range set.m { - elems[i] = elem // safe indexing, by construction of SortedSet - } - return strings.Join(elems, ",") -} - -// Subsumes reports whether csv is a sequence of comma-separated names that are -// - all elements of set, -// - sorted in lexicographically order, -// - unique. -func (set SortedSet) Subsumes(csv string) bool { - if csv == "" { - return true - } - posOfLastNameSeen := -1 - chunkSize := set.maxLen + 1 // (to accommodate for at least one comma) - for { - // As a defense against maliciously long names in csv, - // we only process at most chunkSize bytes per iteration. - end := min(len(csv), chunkSize) - comma := strings.IndexByte(csv[:end], ',') - var name string - if comma == -1 { - name = csv - } else { - name = csv[:comma] - } - pos, found := set.m[name] - if !found { - return false - } - // The names in csv are expected to be sorted in lexicographical order - // and appear at most once in csv. - // Therefore, the positions (in set) of the names that - // appear in csv should form a strictly increasing sequence. - // If that's not actually the case, bail out. - if pos <= posOfLastNameSeen { - return false - } - posOfLastNameSeen = pos - if comma < 0 { // We've now processed all the names in csv. - break - } - csv = csv[comma+1:] - } - return true -} - -// TODO: when updating go directive to 1.21 or later, -// use min builtin instead. -func min(a, b int) int { - if a < b { - return a - } - return b -} - -// TODO: when updating go directive to 1.21 or later, -// use max builtin instead. -func max(a, b int) int { - if a > b { - return a - } - return b -} diff --git a/vendor/github.com/rs/cors/utils.go b/vendor/github.com/rs/cors/utils.go index 7019f45c..db83ac3e 100644 --- a/vendor/github.com/rs/cors/utils.go +++ b/vendor/github.com/rs/cors/utils.go @@ -1,9 +1,10 @@ package cors -import ( - "net/http" - "strings" -) +import "strings" + +const toLower = 'a' - 'A' + +type converter func(string) string type wildcard struct { prefix string @@ -11,24 +12,60 @@ type wildcard struct { } func (w wildcard) match(s string) bool { - return len(s) >= len(w.prefix)+len(w.suffix) && - strings.HasPrefix(s, w.prefix) && - strings.HasSuffix(s, w.suffix) + return len(s) >= len(w.prefix)+len(w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix) } // convert converts a list of string using the passed converter function -func convert(s []string, f func(string) string) []string { - out := make([]string, len(s)) - for i := range s { - out[i] = f(s[i]) +func convert(s []string, c converter) []string { + out := []string{} + for _, i := range s { + out = append(out, c(i)) } return out } -func first(hdrs http.Header, k string) ([]string, bool) { - v, found := hdrs[k] - if !found || len(v) == 0 { - return nil, false +// parseHeaderList tokenize + normalize a string containing a list of headers +func parseHeaderList(headerList string) []string { + l := len(headerList) + h := make([]byte, 0, l) + upper := true + // Estimate the number headers in order to allocate the right splice size + t := 0 + for i := 0; i < l; i++ { + if headerList[i] == ',' { + t++ + } + } + headers := make([]string, 0, t) + for i := 0; i < l; i++ { + b := headerList[i] + switch { + case b >= 'a' && b <= 'z': + if upper { + h = append(h, b-toLower) + } else { + h = append(h, b) + } + case b >= 'A' && b <= 'Z': + if !upper { + h = append(h, b+toLower) + } else { + h = append(h, b) + } + case b == '-' || b == '_' || (b >= '0' && b <= '9'): + h = append(h, b) + } + + if b == ' ' || b == ',' || i == l-1 { + if len(h) > 0 { + // Flush the found header + headers = append(headers, string(h)) + h = h[:0] + upper = true + } + } else { + upper = b == '-' || b == '_' + } } - return v[:1], true + return headers } diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go index 21006bc3..81f19628 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go @@ -141,44 +141,9 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c.CPU = int32(t) case "vendorId", "vendor_id": c.VendorID = value - case "CPU implementer": - if v, err := strconv.ParseUint(value, 0, 8); err == nil { - switch v { - case 0x41: - c.VendorID = "ARM" - case 0x42: - c.VendorID = "Broadcom" - case 0x43: - c.VendorID = "Cavium" - case 0x44: - c.VendorID = "DEC" - case 0x46: - c.VendorID = "Fujitsu" - case 0x48: - c.VendorID = "HiSilicon" - case 0x49: - c.VendorID = "Infineon" - case 0x4d: - c.VendorID = "Motorola/Freescale" - case 0x4e: - c.VendorID = "NVIDIA" - case 0x50: - c.VendorID = "APM" - case 0x51: - c.VendorID = "Qualcomm" - case 0x56: - c.VendorID = "Marvell" - case 0x61: - c.VendorID = "Apple" - case 0x69: - c.VendorID = "Intel" - case 0xc0: - c.VendorID = "Ampere" - } - } case "cpu family": c.Family = value - case "model", "CPU part": + case "model": c.Model = value case "model name", "cpu": c.ModelName = value @@ -188,7 +153,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c.Family = "POWER" c.VendorID = "IBM" } - case "stepping", "revision", "CPU revision": + case "stepping", "revision": val := value if key == "revision" { diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go index 4e3dea02..d97688d4 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go @@ -179,7 +179,7 @@ func parseISAInfo(cmdOutput string) ([]string, error) { return flags, nil } -var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processors? \(([\d-]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`) +var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processor \(([\d]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`) const ( psrNumCoresOffset = 1 diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go index 0176c477..ad1750b5 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go @@ -5,10 +5,9 @@ package cpu import ( "context" "fmt" - "strings" "unsafe" - "github.com/yusufpapurcu/wmi" + "github.com/StackExchange/wmi" "github.com/shirou/gopsutil/internal/common" "golang.org/x/sys/windows" ) @@ -19,14 +18,7 @@ var ( ) type Win32_Processor struct { - Win32_ProcessorWithoutLoadPct - LoadPercentage *uint16 -} - -// LoadPercentage takes a linearly more time as the number of sockets increases. -// For vSphere by default corespersocket = 1, meaning for a 40 vCPU VM Get Processor Info -// could take more than half a minute. -type Win32_ProcessorWithoutLoadPct struct { + LoadPercentage *uint16 Family uint16 Manufacturer string Name string @@ -112,9 +104,8 @@ func Info() ([]InfoStat, error) { func InfoWithContext(ctx context.Context) ([]InfoStat, error) { var ret []InfoStat - var dst []Win32_ProcessorWithoutLoadPct + var dst []Win32_Processor q := wmi.CreateQuery(&dst, "") - q = strings.ReplaceAll(q, "Win32_ProcessorWithoutLoadPct", "Win32_Processor") if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil { return ret, err } @@ -251,9 +242,8 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { } // physical cores https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L499 // for the time being, try with unreliable and slow WMI call… - var dst []Win32_ProcessorWithoutLoadPct + var dst []Win32_Processor q := wmi.CreateQuery(&dst, "") - q = strings.ReplaceAll(q, "Win32_ProcessorWithoutLoadPct", "Win32_Processor") if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil { return 0, err } diff --git a/vendor/github.com/shirou/gopsutil/internal/common/binary.go b/vendor/github.com/shirou/gopsutil/internal/common/binary.go index bf385fd4..9b5dc55b 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/binary.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/binary.go @@ -253,7 +253,7 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error { b[0] = *v case uint8: bs = b[:1] - b[0] = v + b[0] = byte(v) case []uint8: bs = v case *int16: diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common.go b/vendor/github.com/shirou/gopsutil/internal/common/common.go index 63462885..ebf70ea0 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common.go @@ -94,7 +94,7 @@ func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ... var ErrNotImplementedError = errors.New("not implemented yet") -// ReadFile reads contents from a file. +// ReadFile reads contents from a file func ReadFile(filename string) (string, error) { content, err := ioutil.ReadFile(filename) @@ -111,7 +111,7 @@ func ReadLines(filename string) ([]string, error) { return ReadLinesOffsetN(filename, 0, -1) } -// ReadLinesOffsetN reads contents from file and splits them by new line. +// ReadLines reads contents from file and splits them by new line. // The offset tells at which line number to start. // The count determines the number of lines to read (starting from offset): // n >= 0: at most n lines @@ -165,7 +165,7 @@ func UintToString(orig []uint8) string { size = i break } - ret[i] = o + ret[i] = byte(o) } if size == -1 { size = len(orig) @@ -224,31 +224,31 @@ func ReadInts(filename string) ([]int64, error) { return ret, nil } -// HexToUint32 parses Hex to uint32 without error. +// Parse Hex to uint32 without error func HexToUint32(hex string) uint32 { vv, _ := strconv.ParseUint(hex, 16, 32) return uint32(vv) } -// mustParseInt32 parses to int32 without error. +// Parse to int32 without error func mustParseInt32(val string) int32 { vv, _ := strconv.ParseInt(val, 10, 32) return int32(vv) } -// mustParseUint64 parses to uint64 without error. +// Parse to uint64 without error func mustParseUint64(val string) uint64 { vv, _ := strconv.ParseInt(val, 10, 64) return uint64(vv) } -// mustParseFloat64 parses to Float64 without error. +// Parse to Float64 without error func mustParseFloat64(val string) float64 { vv, _ := strconv.ParseFloat(val, 64) return vv } -// StringsHas checks the target string slice contains src or not. +// StringsHas checks the target string slice contains src or not func StringsHas(target []string, src string) bool { for _, t := range target { if strings.TrimSpace(t) == src { @@ -258,7 +258,7 @@ func StringsHas(target []string, src string) bool { return false } -// StringsContains checks the src in any string of the target string slice. +// StringsContains checks the src in any string of the target string slice func StringsContains(target []string, src string) bool { for _, t := range target { if strings.Contains(t, src) { @@ -308,7 +308,7 @@ func PathExists(filename string) bool { return false } -// GetEnv retrieves the environment variable key. If it does not exist it returns the default. +//GetEnv retrieves the environment variable key. If it does not exist it returns the default. func GetEnv(key string, dfault string, combineWith ...string) string { value := os.Getenv(key) if value == "" { @@ -352,16 +352,6 @@ func HostDev(combineWith ...string) string { return GetEnv("HOST_DEV", "/dev", combineWith...) } -// MockEnv set environment variable and return revert function. -// MockEnv should be used testing only. -func MockEnv(key string, value string) func() { - original := os.Getenv(key) - os.Setenv(key, value) - return func() { - os.Setenv(key, original) - } -} - // getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running // sysctl commands (see DoSysctrl). func getSysctrlEnv(env []string) []string { diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go index ca01c755..73499899 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go @@ -26,8 +26,8 @@ func DoSysctrl(mib string) ([]string, error) { return []string{}, err } v := strings.Replace(string(out), "{ ", "", 1) - v = strings.Replace(v, " }", "", 1) - values := strings.Fields(v) + v = strings.Replace(string(v), " }", "", 1) + values := strings.Fields(string(v)) return values, nil } @@ -55,6 +55,7 @@ func NumProcs() (uint64, error) { } func BootTimeWithContext(ctx context.Context) (uint64, error) { + system, role, err := Virtualization() if err != nil { return 0, err @@ -75,18 +76,6 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { return 0, err } - if statFile == "uptime" { - if len(lines) != 1 { - return 0, fmt.Errorf("wrong uptime format") - } - f := strings.Fields(lines[0]) - b, err := strconv.ParseFloat(f[0], 64) - if err != nil { - return 0, err - } - t := uint64(time.Now().Unix()) - uint64(b) - return t, nil - } if statFile == "stat" { for _, line := range lines { if strings.HasPrefix(line, "btime") { @@ -102,6 +91,17 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { return t, nil } } + } else if statFile == "uptime" { + if len(lines) != 1 { + return 0, fmt.Errorf("wrong uptime format") + } + f := strings.Fields(lines[0]) + b, err := strconv.ParseFloat(f[0], 64) + if err != nil { + return 0, err + } + t := uint64(time.Now().Unix()) - uint64(b) + return t, nil } return 0, fmt.Errorf("could not find btime") @@ -111,7 +111,7 @@ func Virtualization() (string, string, error) { return VirtualizationWithContext(context.Background()) } -// required variables for concurrency safe virtualization caching. +// required variables for concurrency safe virtualization caching var ( cachedVirtMap map[string]string cachedVirtMutex sync.RWMutex @@ -137,8 +137,10 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { if PathExists(filepath.Join(filename, "capabilities")) { contents, err := ReadLines(filepath.Join(filename, "capabilities")) - if err == nil && StringsContains(contents, "control_d") { - role = "host" + if err == nil { + if StringsContains(contents, "control_d") { + role = "host" + } } } } @@ -147,17 +149,16 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { - switch { - case StringsContains(contents, "kvm"): + if StringsContains(contents, "kvm") { system = "kvm" role = "host" - case StringsContains(contents, "vboxdrv"): + } else if StringsContains(contents, "vboxdrv") { system = "vbox" role = "host" - case StringsContains(contents, "vboxguest"): + } else if StringsContains(contents, "vboxguest") { system = "vbox" role = "guest" - case StringsContains(contents, "vmware"): + } else if StringsContains(contents, "vmware") { system = "vmware" role = "guest" } @@ -200,6 +201,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { if PathExists(filepath.Join(filename, "self", "status")) { contents, err := ReadLines(filepath.Join(filename, "self", "status")) if err == nil { + if StringsContains(contents, "s_context:") || StringsContains(contents, "VxID:") { system = "linux-vserver" @@ -222,17 +224,16 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { if PathExists(filepath.Join(filename, "self", "cgroup")) { contents, err := ReadLines(filepath.Join(filename, "self", "cgroup")) if err == nil { - switch { - case StringsContains(contents, "lxc"): + if StringsContains(contents, "lxc") { system = "lxc" role = "guest" - case StringsContains(contents, "docker"): + } else if StringsContains(contents, "docker") { system = "docker" role = "guest" - case StringsContains(contents, "machine-rkt"): + } else if StringsContains(contents, "machine-rkt") { system = "rkt" role = "guest" - case PathExists("/usr/bin/lxc-version"): + } else if PathExists("/usr/bin/lxc-version") { system = "lxc" role = "host" } @@ -280,7 +281,7 @@ func GetOSRelease() (platform string, version string, err error) { return platform, version, nil } -// trimQuotes removes quotes in the source string. +// Remove quotes of the source string func trimQuotes(s string) string { if len(s) >= 2 { if s[0] == '"' && s[len(s)-1] == '"' { diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go b/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go index 60520281..9e393bcf 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go @@ -41,7 +41,8 @@ func CallLsofWithContext(ctx context.Context, invoke Invoker, pid int32, args .. } func CallPgrepWithContext(ctx context.Context, invoke Invoker, pid int32) ([]int32, error) { - cmd := []string{"-P", strconv.Itoa(int(pid))} + var cmd []string + cmd = []string{"-P", strconv.Itoa(int(pid))} pgrep, err := exec.LookPath("pgrep") if err != nil { return []int32{}, err diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go index ba20136d..2471bae1 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go @@ -6,12 +6,11 @@ import ( "context" "fmt" "path/filepath" - "reflect" "strings" "syscall" "unsafe" - "github.com/yusufpapurcu/wmi" + "github.com/StackExchange/wmi" "golang.org/x/sys/windows" ) @@ -49,18 +48,11 @@ const ( PDH_INVALID_DATA = 0xc0000bc6 PDH_INVALID_HANDLE = 0xC0000bbc PDH_NO_DATA = 0x800007d5 - - STATUS_BUFFER_OVERFLOW = 0x80000005 - STATUS_BUFFER_TOO_SMALL = 0xC0000023 - STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 ) const ( ProcessBasicInformation = 0 ProcessWow64Information = 26 - ProcessQueryInformation = windows.PROCESS_DUP_HANDLE | windows.PROCESS_QUERY_INFORMATION - - SystemExtendedHandleInformationClass = 64 ) var ( @@ -235,66 +227,3 @@ func ConvertDOSPath(p string) string { } return p } - -type NtStatus uint32 - -func (s NtStatus) Error() error { - if s == 0 { - return nil - } - return fmt.Errorf("NtStatus 0x%08x", uint32(s)) -} - -func (s NtStatus) IsError() bool { - return s>>30 == 3 -} - -type SystemExtendedHandleTableEntryInformation struct { - Object uintptr - UniqueProcessId uintptr - HandleValue uintptr - GrantedAccess uint32 - CreatorBackTraceIndex uint16 - ObjectTypeIndex uint16 - HandleAttributes uint32 - Reserved uint32 -} - -type SystemExtendedHandleInformation struct { - NumberOfHandles uintptr - Reserved uintptr - Handles [1]SystemExtendedHandleTableEntryInformation -} - -// CallWithExpandingBuffer https://github.com/hillu/go-ntdll -func CallWithExpandingBuffer(fn func() NtStatus, buf *[]byte, resultLength *uint32) NtStatus { - for { - if st := fn(); st == STATUS_BUFFER_OVERFLOW || st == STATUS_BUFFER_TOO_SMALL || st == STATUS_INFO_LENGTH_MISMATCH { - if int(*resultLength) <= cap(*buf) { - (*reflect.SliceHeader)(unsafe.Pointer(buf)).Len = int(*resultLength) - } else { - *buf = make([]byte, int(*resultLength)) - } - continue - } else { - if !st.IsError() { - *buf = (*buf)[:int(*resultLength)] - } - return st - } - } -} - -func NtQuerySystemInformation( - SystemInformationClass uint32, - SystemInformation *byte, - SystemInformationLength uint32, - ReturnLength *uint32, -) NtStatus { - r0, _, _ := ProcNtQuerySystemInformation.Call( - uintptr(SystemInformationClass), - uintptr(unsafe.Pointer(SystemInformation)), - uintptr(SystemInformationLength), - uintptr(unsafe.Pointer(ReturnLength))) - return NtStatus(r0) -} diff --git a/vendor/github.com/supranational/blst/bindings/go/README.md b/vendor/github.com/supranational/blst/bindings/go/README.md index 961853ed..29058389 100644 --- a/vendor/github.com/supranational/blst/bindings/go/README.md +++ b/vendor/github.com/supranational/blst/bindings/go/README.md @@ -1,4 +1,4 @@ -# blst [![Lint Status](https://github.com/supranational/blst/workflows/golang-lint/badge.svg)](https://github.com/supranational/blst/actions/workflows/golang-lint.yml) +# blst The `blst` package provides a Go interface to the blst BLS12-381 signature library. @@ -13,9 +13,9 @@ go test The generate.py script is used to generate both min-pk and min-sig variants of the binding from a common code base. It consumes the `*.tgo` files along with `blst_minpk_test.go` and produces `blst.go` and `blst_minsig_test.go`. The .tgo files can treated as if they were .go files, including the use of gofmt and goimports. The generate script will filter out extra imports while processing and automatically run goimports on the final blst.go file. -After running generate.py, `go build` and `go test` can be run as usual. Cgo will compile `cgo_server.c`, which includes the required C implementation files, and `cgo_assembly.S`, which includes appropriate pre-generated assembly code for the platform. To compile on Windows one has to have MinGW gcc on the `%PATH%`. +After running generate.py, `go build` and `go test` can be run as usual. Cgo will compile `server.c`, which includes the required C implementation files, and `assembly.S`, which includes appropriate pre-generated assembly code for the platform. To compile on Windows one has to have MinGW gcc on the `%PATH%`. -If the test or target application crashes with an "illegal instruction" exception [after copying to an older system], rebuild with `CGO_CFLAGS` environment variable set to `-O2 -D__BLST_PORTABLE__`. Don't forget `-O2`! +If the test or target application crashes with an "illegal instruction" exception [after copying to an older system], rebuild with `CGO_CFLAGS` environment variable set to `-O -D__BLST_PORTABLE__`. Don't forget `-O`! ## Usage There are two primary modes of operation that can be chosen based on type definitions in the application. diff --git a/vendor/github.com/supranational/blst/bindings/go/blst.go b/vendor/github.com/supranational/blst/bindings/go/blst.go index b0713780..c890f55e 100644 --- a/vendor/github.com/supranational/blst/bindings/go/blst.go +++ b/vendor/github.com/supranational/blst/bindings/go/blst.go @@ -1,7 +1,7 @@ -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// DO NOT MODIFY THIS FILE!! +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// DO NOT EDIT THIS FILE!! // The file is generated from *.tgo by generate.py -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /* * Copyright Supranational LLC * Licensed under the Apache License, Version 2.0, see LICENSE for details. @@ -12,9 +12,7 @@ package blst // #cgo CFLAGS: -I${SRCDIR}/.. -I${SRCDIR}/../../build -I${SRCDIR}/../../src -D__BLST_CGO__ -fno-builtin-memcpy -fno-builtin-memset // #cgo amd64 CFLAGS: -D__ADX__ -mno-avx -// // no-asm 64-bit platforms from https://go.dev/doc/install/source -// #cgo loong64 mips64 mips64le ppc64 ppc64le riscv64 s390x CFLAGS: -D__BLST_NO_ASM__ -// +// #cgo mips64 mips64le ppc64 ppc64le riscv64 s390x CFLAGS: -D__BLST_NO_ASM__ // #include "blst.h" // // #if defined(__x86_64__) && (defined(__unix__) || defined(__APPLE__)) @@ -35,6 +33,10 @@ package blst // } // #endif // +// static size_t go_pairing_sizeof(size_t DST_len) +// { return (blst_pairing_sizeof() + DST_len + sizeof(blst_pairing) - 1) / +// sizeof(blst_pairing); +// } // static void go_pairing_init(blst_pairing *new_ctx, bool hash_or_encode, // const byte *DST, size_t DST_len) // { if (DST != NULL) { @@ -141,18 +143,7 @@ package blst // for (i = 2; i < n; i++) // blst_fp12_mul(dst, dst, &in[i]); // } -// static bool go_p1_affine_validate(const blst_p1_affine *p, bool infcheck) -// { if (infcheck && blst_p1_affine_is_inf(p)) -// return 0; -// return blst_p1_affine_in_g1(p); -// } -// static bool go_p2_affine_validate(const blst_p2_affine *p, bool infcheck) -// { if (infcheck && blst_p2_affine_is_inf(p)) -// return 0; -// return blst_p2_affine_in_g2(p); -// } import "C" - import ( "fmt" "math/bits" @@ -212,11 +203,6 @@ func SetMaxProcs(max int) { maxProcs = max } -var cgo_pairingSizeOf = C.blst_pairing_sizeof() -var cgo_p1Generator = *C.blst_p1_generator() -var cgo_p2Generator = *C.blst_p2_generator() -var cgo_fp12One = *C.blst_fp12_one() - // Secret key func (sk *SecretKey) Zeroize() { var zero SecretKey @@ -226,14 +212,18 @@ func (sk *SecretKey) Zeroize() { func KeyGen(ikm []byte, optional ...[]byte) *SecretKey { var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } if len(ikm) < 32 { return nil } C.blst_keygen(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -246,11 +236,15 @@ func KeyGenV3(ikm []byte, optional ...[]byte) *SecretKey { } var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } C.blst_keygen_v3(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -263,12 +257,16 @@ func KeyGenV45(ikm []byte, salt []byte, optional ...[]byte) *SecretKey { } var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } C.blst_keygen_v4_5(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), (*C.byte)(&salt[0]), C.size_t(len(salt)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -281,12 +279,16 @@ func KeyGenV5(ikm []byte, salt []byte, optional ...[]byte) *SecretKey { } var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } C.blst_keygen_v5(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), (*C.byte)(&salt[0]), C.size_t(len(salt)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -315,14 +317,14 @@ func (master *SecretKey) DeriveChildEip2333(child_index uint32) *SecretKey { } // Pairing -func pairingSizeOf(DST_len C.size_t) int { - return int((cgo_pairingSizeOf + DST_len + 7) / 8) -} - func PairingCtx(hash_or_encode bool, DST []byte) Pairing { DST_len := C.size_t(len(DST)) - ctx := make([]C.blst_pairing, pairingSizeOf(DST_len)) - C.go_pairing_init(&ctx[0], C.bool(hash_or_encode), ptrOrNil(DST), DST_len) + ctx := make([]C.blst_pairing, int(C.go_pairing_sizeof(DST_len))) + var uDST *C.byte + if DST_len > 0 { + uDST = (*C.byte)(&DST[0]) + } + C.go_pairing_init(&ctx[0], C.bool(hash_or_encode), uDST, DST_len) return ctx } @@ -336,7 +338,7 @@ func PairingMerge(ctx Pairing, ctx1 Pairing) int { } func PairingFinalVerify(ctx Pairing, optional ...*Fp12) bool { - var gtsig *Fp12 + var gtsig *Fp12 = nil if len(optional) > 0 { gtsig = optional[0] } @@ -354,7 +356,7 @@ func PairingAsFp12(ctx Pairing) *Fp12 { } func Fp12One() Fp12 { - return cgo_fp12One + return *C.blst_fp12_one() } func Fp12FinalVerify(pt1 *Fp12, pt2 *Fp12) bool { @@ -447,14 +449,6 @@ func (pt1 *Fp12) Equals(pt2 *Fp12) bool { return *pt1 == *pt2 } -func ptrOrNil(bytes []byte) *C.byte { - var ptr *C.byte - if len(bytes) > 0 { - ptr = (*C.byte)(&bytes[0]) - } - return ptr -} - // // MIN-PK // @@ -469,7 +463,8 @@ func (pk *P1Affine) From(s *Scalar) *P1Affine { } func (pk *P1Affine) KeyValidate() bool { - return bool(C.go_p1_affine_validate(pk, true)) + return !bool(C.blst_p1_affine_is_inf(pk)) && + bool(C.blst_p1_affine_in_g1(pk)) } // sigInfcheck, check for infinity, is a way to avoid going @@ -477,7 +472,10 @@ func (pk *P1Affine) KeyValidate() bool { // always cryptographically safe, but application might want // to guard against obviously bogus individual[!] signatures. func (sig *P2Affine) SigValidate(sigInfcheck bool) bool { - return bool(C.go_p2_affine_validate(sig, C.bool(sigInfcheck))) + if sigInfcheck && bool(C.blst_p2_affine_is_inf(sig)) { + return false + } + return bool(C.blst_p2_affine_in_g2(sig)) } // @@ -561,8 +559,9 @@ func (sig *P2Affine) AggregateVerify(sigGroupcheck bool, pkFn := func(i uint32, _ *P1Affine) (*P1Affine, []byte) { if useAugs { return pks[i], augs[i] + } else { + return pks[i], nil } - return pks[i], nil } return coreAggregateVerifyPkInG1(sigFn, sigGroupcheck, pkFn, pksVerify, @@ -571,7 +570,7 @@ func (sig *P2Affine) AggregateVerify(sigGroupcheck bool, // Aggregate verify with compressed signature and public keys // Uses a dummy signature to get the correct type -func (_ *P2Affine) AggregateVerifyCompressed(sig []byte, sigGroupcheck bool, +func (dummy *P2Affine) AggregateVerifyCompressed(sig []byte, sigGroupcheck bool, pks [][]byte, pksVerify bool, msgs []Message, dst []byte, optional ...bool) bool { // useHash bool, usePksAsAugs bool @@ -665,7 +664,7 @@ func coreAggregateVerifyPkInG1(sigFn sigGetterP2, sigGroupcheck bool, // main thread has completed its miller loop before // proceeding. mutex.Lock() - mutex.Unlock() //nolint:staticcheck + mutex.Unlock() } // Pull Public Key and augmentation blob @@ -736,8 +735,12 @@ func CoreVerifyPkInG1(pk *P1Affine, sig *P2Affine, hash_or_encode bool, msg Message, dst []byte, optional ...[]byte) int { var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } } if runtime.NumGoroutine() < maxProcs { @@ -754,10 +757,19 @@ func CoreVerifyPkInG1(pk *P1Affine, sig *P2Affine, hash_or_encode bool, return C.BLST_SUCCESS } + var udst *C.byte + if len(dst) > 0 { + udst = (*C.byte)(&dst[0]) + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) + } + return int(C.blst_core_verify_pk_in_g1(pk, sig, C.bool(hash_or_encode), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug)))) + umsg, C.size_t(len(msg)), + udst, C.size_t(len(dst)), + uaug, C.size_t(len(aug)))) } // pks are assumed to be verified for proof of possession, @@ -782,7 +794,7 @@ func (sig *P2Affine) FastAggregateVerify(sigGroupcheck bool, return sig.Verify(sigGroupcheck, pkAff, false, msg, dst, optional...) } -func (_ *P2Affine) MultipleAggregateVerify(sigs []*P2Affine, +func (dummy *P2Affine) MultipleAggregateVerify(sigs []*P2Affine, sigsGroupcheck bool, pks []*P1Affine, pksVerify bool, msgs []Message, dst []byte, randFn func(*Scalar), randBits int, optional ...interface{}) bool { // useHash @@ -799,7 +811,7 @@ func (_ *P2Affine) MultipleAggregateVerify(sigs []*P2Affine, } paramsFn := - func(work uint32, _ *P2Affine, _ *P1Affine, rand *Scalar) ( + func(work uint32, sig *P2Affine, pk *P1Affine, rand *Scalar) ( *P2Affine, *P1Affine, *Scalar, []byte) { randFn(rand) var aug []byte @@ -920,7 +932,7 @@ func (agg *P2Aggregate) Aggregate(elmts []*P2Affine, return true } getter := func(i uint32, _ *P2Affine) *P2Affine { return elmts[i] } - return agg.coreAggregate(getter, groupcheck, len(elmts)) + return agg.aggregate(getter, groupcheck, len(elmts)) } // Aggregate compressed elements @@ -936,7 +948,7 @@ func (agg *P2Aggregate) AggregateCompressed(elmts [][]byte, } return p } - return agg.coreAggregate(getter, groupcheck, len(elmts)) + return agg.aggregate(getter, groupcheck, len(elmts)) } func (agg *P2Aggregate) AddAggregate(other *P2Aggregate) { @@ -969,7 +981,7 @@ func (agg *P2Aggregate) ToAffine() *P2Affine { return agg.v.ToAffine() } -func (agg *P2Aggregate) coreAggregate(getter aggGetterP2, groupcheck bool, +func (agg *P2Aggregate) aggregate(getter aggGetterP2, groupcheck bool, n int) bool { if n == 0 { @@ -1071,7 +1083,8 @@ func (pk *P2Affine) From(s *Scalar) *P2Affine { } func (pk *P2Affine) KeyValidate() bool { - return bool(C.go_p2_affine_validate(pk, true)) + return !bool(C.blst_p2_affine_is_inf(pk)) && + bool(C.blst_p2_affine_in_g2(pk)) } // sigInfcheck, check for infinity, is a way to avoid going @@ -1079,7 +1092,10 @@ func (pk *P2Affine) KeyValidate() bool { // always cryptographically safe, but application might want // to guard against obviously bogus individual[!] signatures. func (sig *P1Affine) SigValidate(sigInfcheck bool) bool { - return bool(C.go_p1_affine_validate(sig, C.bool(sigInfcheck))) + if sigInfcheck && bool(C.blst_p1_affine_is_inf(sig)) { + return false + } + return bool(C.blst_p1_affine_in_g1(sig)) } // @@ -1163,8 +1179,9 @@ func (sig *P1Affine) AggregateVerify(sigGroupcheck bool, pkFn := func(i uint32, _ *P2Affine) (*P2Affine, []byte) { if useAugs { return pks[i], augs[i] + } else { + return pks[i], nil } - return pks[i], nil } return coreAggregateVerifyPkInG2(sigFn, sigGroupcheck, pkFn, pksVerify, @@ -1173,7 +1190,7 @@ func (sig *P1Affine) AggregateVerify(sigGroupcheck bool, // Aggregate verify with compressed signature and public keys // Uses a dummy signature to get the correct type -func (_ *P1Affine) AggregateVerifyCompressed(sig []byte, sigGroupcheck bool, +func (dummy *P1Affine) AggregateVerifyCompressed(sig []byte, sigGroupcheck bool, pks [][]byte, pksVerify bool, msgs []Message, dst []byte, optional ...bool) bool { // useHash bool, usePksAsAugs bool @@ -1267,7 +1284,7 @@ func coreAggregateVerifyPkInG2(sigFn sigGetterP1, sigGroupcheck bool, // main thread has completed its miller loop before // proceeding. mutex.Lock() - mutex.Unlock() //nolint:staticcheck + mutex.Unlock() } // Pull Public Key and augmentation blob @@ -1338,8 +1355,12 @@ func CoreVerifyPkInG2(pk *P2Affine, sig *P1Affine, hash_or_encode bool, msg Message, dst []byte, optional ...[]byte) int { var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } } if runtime.NumGoroutine() < maxProcs { @@ -1356,10 +1377,19 @@ func CoreVerifyPkInG2(pk *P2Affine, sig *P1Affine, hash_or_encode bool, return C.BLST_SUCCESS } + var udst *C.byte + if len(dst) > 0 { + udst = (*C.byte)(&dst[0]) + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) + } + return int(C.blst_core_verify_pk_in_g2(pk, sig, C.bool(hash_or_encode), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug)))) + umsg, C.size_t(len(msg)), + udst, C.size_t(len(dst)), + uaug, C.size_t(len(aug)))) } // pks are assumed to be verified for proof of possession, @@ -1384,7 +1414,7 @@ func (sig *P1Affine) FastAggregateVerify(sigGroupcheck bool, return sig.Verify(sigGroupcheck, pkAff, false, msg, dst, optional...) } -func (_ *P1Affine) MultipleAggregateVerify(sigs []*P1Affine, +func (dummy *P1Affine) MultipleAggregateVerify(sigs []*P1Affine, sigsGroupcheck bool, pks []*P2Affine, pksVerify bool, msgs []Message, dst []byte, randFn func(*Scalar), randBits int, optional ...interface{}) bool { // useHash @@ -1401,7 +1431,7 @@ func (_ *P1Affine) MultipleAggregateVerify(sigs []*P1Affine, } paramsFn := - func(work uint32, _ *P1Affine, _ *P2Affine, rand *Scalar) ( + func(work uint32, sig *P1Affine, pk *P2Affine, rand *Scalar) ( *P1Affine, *P2Affine, *Scalar, []byte) { randFn(rand) var aug []byte @@ -1522,7 +1552,7 @@ func (agg *P1Aggregate) Aggregate(elmts []*P1Affine, return true } getter := func(i uint32, _ *P1Affine) *P1Affine { return elmts[i] } - return agg.coreAggregate(getter, groupcheck, len(elmts)) + return agg.aggregate(getter, groupcheck, len(elmts)) } // Aggregate compressed elements @@ -1538,7 +1568,7 @@ func (agg *P1Aggregate) AggregateCompressed(elmts [][]byte, } return p } - return agg.coreAggregate(getter, groupcheck, len(elmts)) + return agg.aggregate(getter, groupcheck, len(elmts)) } func (agg *P1Aggregate) AddAggregate(other *P1Aggregate) { @@ -1571,7 +1601,7 @@ func (agg *P1Aggregate) ToAffine() *P1Affine { return agg.v.ToAffine() } -func (agg *P1Aggregate) coreAggregate(getter aggGetterP1, groupcheck bool, +func (agg *P1Aggregate) aggregate(getter aggGetterP1, groupcheck bool, n int) bool { if n == 0 { @@ -1662,15 +1692,23 @@ func PairingAggregatePkInG1(ctx Pairing, PK *P1Affine, pkValidate bool, sig *P2Affine, sigGroupcheck bool, msg []byte, optional ...[]byte) int { // aug var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) } r := C.blst_pairing_chk_n_aggr_pk_in_g1(&ctx[0], PK, C.bool(pkValidate), sig, C.bool(sigGroupcheck), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(aug), C.size_t(len(aug))) + umsg, C.size_t(len(msg)), + uaug, C.size_t(len(aug))) return int(r) } @@ -1680,16 +1718,24 @@ func PairingMulNAggregatePkInG1(ctx Pairing, PK *P1Affine, pkValidate bool, rand *Scalar, randBits int, msg []byte, optional ...[]byte) int { // aug var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) } r := C.blst_pairing_chk_n_mul_n_aggr_pk_in_g1(&ctx[0], PK, C.bool(pkValidate), sig, C.bool(sigGroupcheck), &rand.b[0], C.size_t(randBits), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(aug), C.size_t(len(aug))) + umsg, C.size_t(len(msg)), + uaug, C.size_t(len(aug))) return int(r) } @@ -1734,7 +1780,7 @@ func (p1 *P1Affine) InG1() bool { return bool(C.blst_p1_affine_in_g1(p1)) } -func (_ *P1Affine) BatchUncompress(in [][]byte) []*P1Affine { +func (dummy *P1Affine) BatchUncompress(in [][]byte) []*P1Affine { // Allocate space for all of the resulting points. Later we'll save pointers // and return those so that the result could be used in other functions, // such as MultipleAggregateVerify. @@ -1868,7 +1914,7 @@ func (p1 *P1) Sub(pointIf interface{}) *P1 { } func P1Generator() *P1 { - return &cgo_p1Generator + return C.blst_p1_generator() } // 'acc += point * scalar', passing 'nil' for 'point' means "use the @@ -1928,14 +1974,29 @@ func HashToG1(msg []byte, dst []byte, optional ...[]byte) *P1 { // aug var q P1 + // Handle zero length message + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + var aug []byte + var augC *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + augC = (*C.byte)(&aug[0]) + } } - C.blst_hash_to_g1(&q, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug))) + C.blst_hash_to_g1(&q, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst)), + augC, C.size_t(len(aug))) return &q } @@ -1943,14 +2004,29 @@ func EncodeToG1(msg []byte, dst []byte, optional ...[]byte) *P1 { // aug var q P1 + // Handle zero length message + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + var aug []byte + var augC *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + augC = (*C.byte)(&aug[0]) + } } - C.blst_encode_to_g1(&q, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug))) + C.blst_encode_to_g1(&q, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst)), + augC, C.size_t(len(aug))) return &q } @@ -2155,7 +2231,7 @@ func P1AffinesMult(pointsIf interface{}, scalarsIf interface{}, nbits int) *P1 { p_scalars = &scalars[0] case []Scalar: if nbits > 248 { - scalarsBySlice[0] = &val[0].b[0] + scalarsBySlice[0] = (*C.byte)(&val[0].b[0]) p_scalars = &scalarsBySlice[0] } else { p_scalars = &scalars[0] @@ -2255,7 +2331,7 @@ func P1AffinesMult(pointsIf interface{}, scalarsIf interface{}, nbits int) *P1 { p_scalars = &scalars[x] case []Scalar: if nbits > 248 { - scalarsBySlice[0] = &val[x].b[0] + scalarsBySlice[0] = (*C.byte)(&val[x].b[0]) p_scalars = &scalarsBySlice[0] } else { p_scalars = &scalars[x] @@ -2324,15 +2400,23 @@ func PairingAggregatePkInG2(ctx Pairing, PK *P2Affine, pkValidate bool, sig *P1Affine, sigGroupcheck bool, msg []byte, optional ...[]byte) int { // aug var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) } r := C.blst_pairing_chk_n_aggr_pk_in_g2(&ctx[0], PK, C.bool(pkValidate), sig, C.bool(sigGroupcheck), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(aug), C.size_t(len(aug))) + umsg, C.size_t(len(msg)), + uaug, C.size_t(len(aug))) return int(r) } @@ -2342,16 +2426,24 @@ func PairingMulNAggregatePkInG2(ctx Pairing, PK *P2Affine, pkValidate bool, rand *Scalar, randBits int, msg []byte, optional ...[]byte) int { // aug var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) } r := C.blst_pairing_chk_n_mul_n_aggr_pk_in_g2(&ctx[0], PK, C.bool(pkValidate), sig, C.bool(sigGroupcheck), &rand.b[0], C.size_t(randBits), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(aug), C.size_t(len(aug))) + umsg, C.size_t(len(msg)), + uaug, C.size_t(len(aug))) return int(r) } @@ -2396,7 +2488,7 @@ func (p2 *P2Affine) InG2() bool { return bool(C.blst_p2_affine_in_g2(p2)) } -func (_ *P2Affine) BatchUncompress(in [][]byte) []*P2Affine { +func (dummy *P2Affine) BatchUncompress(in [][]byte) []*P2Affine { // Allocate space for all of the resulting points. Later we'll save pointers // and return those so that the result could be used in other functions, // such as MultipleAggregateVerify. @@ -2530,7 +2622,7 @@ func (p2 *P2) Sub(pointIf interface{}) *P2 { } func P2Generator() *P2 { - return &cgo_p2Generator + return C.blst_p2_generator() } // 'acc += point * scalar', passing 'nil' for 'point' means "use the @@ -2590,14 +2682,29 @@ func HashToG2(msg []byte, dst []byte, optional ...[]byte) *P2 { // aug var q P2 + // Handle zero length message + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + var aug []byte + var augC *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + augC = (*C.byte)(&aug[0]) + } } - C.blst_hash_to_g2(&q, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug))) + C.blst_hash_to_g2(&q, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst)), + augC, C.size_t(len(aug))) return &q } @@ -2605,14 +2712,29 @@ func EncodeToG2(msg []byte, dst []byte, optional ...[]byte) *P2 { // aug var q P2 + // Handle zero length message + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + var aug []byte + var augC *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + augC = (*C.byte)(&aug[0]) + } } - C.blst_encode_to_g2(&q, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug))) + C.blst_encode_to_g2(&q, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst)), + augC, C.size_t(len(aug))) return &q } @@ -2817,7 +2939,7 @@ func P2AffinesMult(pointsIf interface{}, scalarsIf interface{}, nbits int) *P2 { p_scalars = &scalars[0] case []Scalar: if nbits > 248 { - scalarsBySlice[0] = &val[0].b[0] + scalarsBySlice[0] = (*C.byte)(&val[0].b[0]) p_scalars = &scalarsBySlice[0] } else { p_scalars = &scalars[0] @@ -2917,7 +3039,7 @@ func P2AffinesMult(pointsIf interface{}, scalarsIf interface{}, nbits int) *P2 { p_scalars = &scalars[x] case []Scalar: if nbits > 248 { - scalarsBySlice[0] = &val[x].b[0] + scalarsBySlice[0] = (*C.byte)(&val[x].b[0]) p_scalars = &scalarsBySlice[0] } else { p_scalars = &scalars[x] @@ -3003,6 +3125,15 @@ func parseOpts(optional ...interface{}) ([]byte, [][]byte, bool, bool) { return augSingle, aug, useHash, true } +func bytesAllZero(s []byte) bool { + for _, v := range s { + if v != 0 { + return false + } + } + return true +} + // These methods are inefficient because of cgo call overhead. For this // reason they should be used primarily for prototyping with a goal to // formulate interfaces that would process multiple scalars per cgo call. @@ -3074,8 +3205,18 @@ func (s *Scalar) HashTo(msg []byte, dst []byte) bool { func HashToScalar(msg []byte, dst []byte) *Scalar { var ret Scalar - if C.go_hash_to_scalar(&ret, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst))) { + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + + if C.go_hash_to_scalar(&ret, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst))) { return &ret } @@ -3158,7 +3299,7 @@ func PrintBytes(val []byte, name string) { func (s *Scalar) Print(name string) { arr := s.ToBEndian() - PrintBytes(arr, name) + PrintBytes(arr[:], name) } func (p *P1Affine) Print(name string) { @@ -3232,15 +3373,26 @@ func (e1 *P2) Equals(e2 *P2) bool { func expandMessageXmd(msg []byte, dst []byte, len_in_bytes int) []byte { ret := make([]byte, len_in_bytes) + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + C.blst_expand_message_xmd((*C.byte)(&ret[0]), C.size_t(len(ret)), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst))) + msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst))) return ret } -func breakdown(nbits, window, ncpus int) (nx int, ny int, wnd int) { +func breakdown(nbits, window, ncpus int) (int, int, int) { + var nx, ny, wnd int - if nbits > window*ncpus { //nolint:nestif + if nbits > window*ncpus { nx = 1 wnd = bits.Len(uint(ncpus) / 4) if (window + wnd) > 18 { diff --git a/vendor/github.com/supranational/blst/bindings/go/blst.tgo b/vendor/github.com/supranational/blst/bindings/go/blst.tgo index 32887e06..654dc284 100644 --- a/vendor/github.com/supranational/blst/bindings/go/blst.tgo +++ b/vendor/github.com/supranational/blst/bindings/go/blst.tgo @@ -8,9 +8,7 @@ package blst // #cgo CFLAGS: -I${SRCDIR}/.. -I${SRCDIR}/../../build -I${SRCDIR}/../../src -D__BLST_CGO__ -fno-builtin-memcpy -fno-builtin-memset // #cgo amd64 CFLAGS: -D__ADX__ -mno-avx -// // no-asm 64-bit platforms from https://go.dev/doc/install/source -// #cgo loong64 mips64 mips64le ppc64 ppc64le riscv64 s390x CFLAGS: -D__BLST_NO_ASM__ -// +// #cgo mips64 mips64le ppc64 ppc64le riscv64 s390x CFLAGS: -D__BLST_NO_ASM__ // #include "blst.h" // // #if defined(__x86_64__) && (defined(__unix__) || defined(__APPLE__)) @@ -31,6 +29,10 @@ package blst // } // #endif // +// static size_t go_pairing_sizeof(size_t DST_len) +// { return (blst_pairing_sizeof() + DST_len + sizeof(blst_pairing) - 1) / +// sizeof(blst_pairing); +// } // static void go_pairing_init(blst_pairing *new_ctx, bool hash_or_encode, // const byte *DST, size_t DST_len) // { if (DST != NULL) { @@ -137,18 +139,7 @@ package blst // for (i = 2; i < n; i++) // blst_fp12_mul(dst, dst, &in[i]); // } -// static bool go_p1_affine_validate(const blst_p1_affine *p, bool infcheck) -// { if (infcheck && blst_p1_affine_is_inf(p)) -// return 0; -// return blst_p1_affine_in_g1(p); -// } -// static bool go_p2_affine_validate(const blst_p2_affine *p, bool infcheck) -// { if (infcheck && blst_p2_affine_is_inf(p)) -// return 0; -// return blst_p2_affine_in_g2(p); -// } import "C" - import "runtime" const BLST_SCALAR_BYTES = 256 / 8 @@ -202,11 +193,6 @@ func SetMaxProcs(max int) { maxProcs = max } -var cgo_pairingSizeOf = C.blst_pairing_sizeof() -var cgo_p1Generator = *C.blst_p1_generator() -var cgo_p2Generator = *C.blst_p2_generator() -var cgo_fp12One = *C.blst_fp12_one() - // // Secret key // @@ -218,14 +204,18 @@ func (sk *SecretKey) Zeroize() { func KeyGen(ikm []byte, optional ...[]byte) *SecretKey { var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } if len(ikm) < 32 { return nil } C.blst_keygen(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -238,11 +228,15 @@ func KeyGenV3(ikm []byte, optional ...[]byte) *SecretKey { } var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } C.blst_keygen_v3(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -255,12 +249,16 @@ func KeyGenV45(ikm []byte, salt []byte, optional ...[]byte) *SecretKey { } var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } C.blst_keygen_v4_5(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), (*C.byte)(&salt[0]), C.size_t(len(salt)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -273,12 +271,16 @@ func KeyGenV5(ikm []byte, salt []byte, optional ...[]byte) *SecretKey { } var sk SecretKey var info []byte + var infoP *C.byte if len(optional) > 0 { info = optional[0] + if len(info) > 0 { + infoP = (*C.byte)(&info[0]) + } } C.blst_keygen_v5(&sk, (*C.byte)(&ikm[0]), C.size_t(len(ikm)), (*C.byte)(&salt[0]), C.size_t(len(salt)), - ptrOrNil(info), C.size_t(len(info))) + infoP, C.size_t(len(info))) // Postponing secret key zeroing till garbage collection can be too // late to be effective, but every little bit helps... runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() }) @@ -309,14 +311,14 @@ func (master *SecretKey) DeriveChildEip2333(child_index uint32) *SecretKey { // // Pairing // -func pairingSizeOf(DST_len C.size_t) int { - return int((cgo_pairingSizeOf + DST_len + 7) / 8) -} - func PairingCtx(hash_or_encode bool, DST []byte) Pairing { DST_len := C.size_t(len(DST)) - ctx := make([]C.blst_pairing, pairingSizeOf(DST_len)) - C.go_pairing_init(&ctx[0], C.bool(hash_or_encode), ptrOrNil(DST), DST_len) + ctx := make([]C.blst_pairing, int(C.go_pairing_sizeof(DST_len))) + var uDST *C.byte + if DST_len > 0 { + uDST = (*C.byte)(&DST[0]) + } + C.go_pairing_init(&ctx[0], C.bool(hash_or_encode), uDST, DST_len) return ctx } @@ -330,7 +332,7 @@ func PairingMerge(ctx Pairing, ctx1 Pairing) int { } func PairingFinalVerify(ctx Pairing, optional ...*Fp12) bool { - var gtsig *Fp12 + var gtsig *Fp12 = nil if len(optional) > 0 { gtsig = optional[0] } @@ -348,7 +350,7 @@ func PairingAsFp12(ctx Pairing) *Fp12 { } func Fp12One() Fp12 { - return cgo_fp12One + return *C.blst_fp12_one() } func Fp12FinalVerify(pt1 *Fp12, pt2 *Fp12) bool { @@ -440,11 +442,3 @@ func (pt *Fp12) ToBendian() []byte { func (pt1 *Fp12) Equals(pt2 *Fp12) bool { return *pt1 == *pt2 } - -func ptrOrNil(bytes []byte) *C.byte { - var ptr *C.byte - if len(bytes) > 0 { - ptr = (*C.byte)(&bytes[0]) - } - return ptr -} diff --git a/vendor/github.com/supranational/blst/bindings/go/blst_minpk.tgo b/vendor/github.com/supranational/blst/bindings/go/blst_minpk.tgo index c449fba4..5d8c60ee 100644 --- a/vendor/github.com/supranational/blst/bindings/go/blst_minpk.tgo +++ b/vendor/github.com/supranational/blst/bindings/go/blst_minpk.tgo @@ -15,7 +15,8 @@ func (pk *P1Affine) From(s *Scalar) *P1Affine { } func (pk *P1Affine) KeyValidate() bool { - return bool(C.go_p1_affine_validate(pk, true)) + return !bool(C.blst_p1_affine_is_inf(pk)) && + bool(C.blst_p1_affine_in_g1(pk)) } // sigInfcheck, check for infinity, is a way to avoid going @@ -23,7 +24,10 @@ func (pk *P1Affine) KeyValidate() bool { // always cryptographically safe, but application might want // to guard against obviously bogus individual[!] signatures. func (sig *P2Affine) SigValidate(sigInfcheck bool) bool { - return bool(C.go_p2_affine_validate(sig, C.bool(sigInfcheck))) + if sigInfcheck && bool(C.blst_p2_affine_is_inf(sig)) { + return false + } + return bool(C.blst_p2_affine_in_g2(sig)) } // @@ -107,8 +111,9 @@ func (sig *P2Affine) AggregateVerify(sigGroupcheck bool, pkFn := func(i uint32, _ *P1Affine) (*P1Affine, []byte) { if useAugs { return pks[i], augs[i] + } else { + return pks[i], nil } - return pks[i], nil } return coreAggregateVerifyPkInG1(sigFn, sigGroupcheck, pkFn, pksVerify, @@ -117,7 +122,7 @@ func (sig *P2Affine) AggregateVerify(sigGroupcheck bool, // Aggregate verify with compressed signature and public keys // Uses a dummy signature to get the correct type -func (_ *P2Affine) AggregateVerifyCompressed(sig []byte, sigGroupcheck bool, +func (dummy *P2Affine) AggregateVerifyCompressed(sig []byte, sigGroupcheck bool, pks [][]byte, pksVerify bool, msgs []Message, dst []byte, optional ...bool) bool { // useHash bool, usePksAsAugs bool @@ -211,7 +216,7 @@ func coreAggregateVerifyPkInG1(sigFn sigGetterP2, sigGroupcheck bool, // main thread has completed its miller loop before // proceeding. mutex.Lock() - mutex.Unlock() //nolint:staticcheck + mutex.Unlock() } // Pull Public Key and augmentation blob @@ -282,8 +287,12 @@ func CoreVerifyPkInG1(pk *P1Affine, sig *P2Affine, hash_or_encode bool, msg Message, dst []byte, optional ...[]byte) int { var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } } if runtime.NumGoroutine() < maxProcs { @@ -300,10 +309,19 @@ func CoreVerifyPkInG1(pk *P1Affine, sig *P2Affine, hash_or_encode bool, return C.BLST_SUCCESS } + var udst *C.byte + if len(dst) > 0 { + udst = (*C.byte)(&dst[0]) + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) + } + return int(C.blst_core_verify_pk_in_g1(pk, sig, C.bool(hash_or_encode), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug)))) + umsg, C.size_t(len(msg)), + udst, C.size_t(len(dst)), + uaug, C.size_t(len(aug)))) } // pks are assumed to be verified for proof of possession, @@ -328,7 +346,7 @@ func (sig *P2Affine) FastAggregateVerify(sigGroupcheck bool, return sig.Verify(sigGroupcheck, pkAff, false, msg, dst, optional...) } -func (_ *P2Affine) MultipleAggregateVerify(sigs []*P2Affine, +func (dummy *P2Affine) MultipleAggregateVerify(sigs []*P2Affine, sigsGroupcheck bool, pks []*P1Affine, pksVerify bool, msgs []Message, dst []byte, randFn func(*Scalar), randBits int, optional ...interface{}) bool { // useHash @@ -345,7 +363,7 @@ func (_ *P2Affine) MultipleAggregateVerify(sigs []*P2Affine, } paramsFn := - func(work uint32, _ *P2Affine, _ *P1Affine, rand *Scalar) ( + func(work uint32, sig *P2Affine, pk *P1Affine, rand *Scalar) ( *P2Affine, *P1Affine, *Scalar, []byte) { randFn(rand) var aug []byte @@ -466,7 +484,7 @@ func (agg *P2Aggregate) Aggregate(elmts []*P2Affine, return true } getter := func(i uint32, _ *P2Affine) *P2Affine { return elmts[i] } - return agg.coreAggregate(getter, groupcheck, len(elmts)) + return agg.aggregate(getter, groupcheck, len(elmts)) } // Aggregate compressed elements @@ -482,7 +500,7 @@ func (agg *P2Aggregate) AggregateCompressed(elmts [][]byte, } return p } - return agg.coreAggregate(getter, groupcheck, len(elmts)) + return agg.aggregate(getter, groupcheck, len(elmts)) } func (agg *P2Aggregate) AddAggregate(other *P2Aggregate) { @@ -515,7 +533,7 @@ func (agg *P2Aggregate) ToAffine() *P2Affine { return agg.v.ToAffine() } -func (agg *P2Aggregate) coreAggregate(getter aggGetterP2, groupcheck bool, +func (agg *P2Aggregate) aggregate(getter aggGetterP2, groupcheck bool, n int) bool { if n == 0 { diff --git a/vendor/github.com/supranational/blst/bindings/go/blst_misc.tgo b/vendor/github.com/supranational/blst/bindings/go/blst_misc.tgo index a6e5d90d..ed6609f8 100644 --- a/vendor/github.com/supranational/blst/bindings/go/blst_misc.tgo +++ b/vendor/github.com/supranational/blst/bindings/go/blst_misc.tgo @@ -23,6 +23,15 @@ func parseOpts(optional ...interface{}) ([]byte, [][]byte, bool, bool) { return augSingle, aug, useHash, true } +func bytesAllZero(s []byte) bool { + for _, v := range s { + if v != 0 { + return false + } + } + return true +} + // // These methods are inefficient because of cgo call overhead. For this // reason they should be used primarily for prototyping with a goal to @@ -96,8 +105,18 @@ func (s *Scalar) HashTo(msg []byte, dst []byte) bool { func HashToScalar(msg []byte, dst []byte) *Scalar { var ret Scalar - if C.go_hash_to_scalar(&ret, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst))) { + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + + if C.go_hash_to_scalar(&ret, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst))) { return &ret } @@ -180,7 +199,7 @@ func PrintBytes(val []byte, name string) { func (s *Scalar) Print(name string) { arr := s.ToBEndian() - PrintBytes(arr, name) + PrintBytes(arr[:], name) } func (p *P1Affine) Print(name string) { @@ -254,15 +273,26 @@ func (e1 *P2) Equals(e2 *P2) bool { func expandMessageXmd(msg []byte, dst []byte, len_in_bytes int) []byte { ret := make([]byte, len_in_bytes) + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + C.blst_expand_message_xmd((*C.byte)(&ret[0]), C.size_t(len(ret)), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst))) + msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst))) return ret } -func breakdown(nbits, window, ncpus int) (nx int, ny int, wnd int) { +func breakdown(nbits, window, ncpus int) (int, int, int) { + var nx, ny, wnd int - if nbits > window*ncpus { //nolint:nestif + if nbits > window*ncpus { nx = 1 wnd = bits.Len(uint(ncpus)/4) if (window + wnd) > 18 { diff --git a/vendor/github.com/supranational/blst/bindings/go/blst_px.tgo b/vendor/github.com/supranational/blst/bindings/go/blst_px.tgo index 187d79d3..11600652 100644 --- a/vendor/github.com/supranational/blst/bindings/go/blst_px.tgo +++ b/vendor/github.com/supranational/blst/bindings/go/blst_px.tgo @@ -2,15 +2,23 @@ func PairingAggregatePkInG1(ctx Pairing, PK *P1Affine, pkValidate bool, sig *P2Affine, sigGroupcheck bool, msg []byte, optional ...[]byte) int { // aug var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) } r := C.blst_pairing_chk_n_aggr_pk_in_g1(&ctx[0], PK, C.bool(pkValidate), sig, C.bool(sigGroupcheck), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(aug), C.size_t(len(aug))) + umsg, C.size_t(len(msg)), + uaug, C.size_t(len(aug))) return int(r) } @@ -20,16 +28,24 @@ func PairingMulNAggregatePkInG1(ctx Pairing, PK *P1Affine, pkValidate bool, rand *Scalar, randBits int, msg []byte, optional ...[]byte) int { // aug var aug []byte + var uaug *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + uaug = (*C.byte)(&aug[0]) + } + } + var umsg *C.byte + if len(msg) > 0 { + umsg = (*C.byte)(&msg[0]) } r := C.blst_pairing_chk_n_mul_n_aggr_pk_in_g1(&ctx[0], PK, C.bool(pkValidate), sig, C.bool(sigGroupcheck), &rand.b[0], C.size_t(randBits), - ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(aug), C.size_t(len(aug))) + umsg, C.size_t(len(msg)), + uaug, C.size_t(len(aug))) return int(r) } @@ -74,7 +90,7 @@ func (p1 *P1Affine) InG1() bool { return bool(C.blst_p1_affine_in_g1(p1)) } -func (_ *P1Affine) BatchUncompress(in [][]byte) []*P1Affine { +func (dummy *P1Affine) BatchUncompress(in [][]byte) []*P1Affine { // Allocate space for all of the resulting points. Later we'll save pointers // and return those so that the result could be used in other functions, // such as MultipleAggregateVerify. @@ -208,7 +224,7 @@ func (p1 *P1) Sub(pointIf interface{}) *P1 { } func P1Generator() *P1 { - return &cgo_p1Generator + return C.blst_p1_generator() } // 'acc += point * scalar', passing 'nil' for 'point' means "use the @@ -269,14 +285,29 @@ func HashToG1(msg []byte, dst []byte, optional ...[]byte) *P1 { // aug var q P1 + // Handle zero length message + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + var aug []byte + var augC *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + augC = (*C.byte)(&aug[0]) + } } - C.blst_hash_to_g1(&q, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug))) + C.blst_hash_to_g1(&q, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst)), + augC, C.size_t(len(aug))) return &q } @@ -284,14 +315,29 @@ func EncodeToG1(msg []byte, dst []byte, optional ...[]byte) *P1 { // aug var q P1 + // Handle zero length message + var msgC *C.byte + if len(msg) > 0 { + msgC = (*C.byte)(&msg[0]) + } + + var dstC *C.byte + if len(dst) > 0 { + dstC = (*C.byte)(&dst[0]) + } + var aug []byte + var augC *C.byte if len(optional) > 0 { aug = optional[0] + if len(aug) > 0 { + augC = (*C.byte)(&aug[0]) + } } - C.blst_encode_to_g1(&q, ptrOrNil(msg), C.size_t(len(msg)), - ptrOrNil(dst), C.size_t(len(dst)), - ptrOrNil(aug), C.size_t(len(aug))) + C.blst_encode_to_g1(&q, msgC, C.size_t(len(msg)), + dstC, C.size_t(len(dst)), + augC, C.size_t(len(aug))) return &q } @@ -496,7 +542,7 @@ func P1AffinesMult(pointsIf interface{}, scalarsIf interface{}, nbits int) *P1 { p_scalars = &scalars[0] case []Scalar: if nbits > 248 { - scalarsBySlice[0] = &val[0].b[0] + scalarsBySlice[0] = (*C.byte)(&val[0].b[0]) p_scalars = &scalarsBySlice[0] } else { p_scalars = &scalars[0] @@ -594,7 +640,7 @@ func P1AffinesMult(pointsIf interface{}, scalarsIf interface{}, nbits int) *P1 { p_scalars = &scalars[x] case []Scalar: if nbits > 248 { - scalarsBySlice[0] = &val[x].b[0] + scalarsBySlice[0] = (*C.byte)(&val[x].b[0]) p_scalars = &scalarsBySlice[0] } else { p_scalars = &scalars[x] diff --git a/vendor/github.com/supranational/blst/bindings/go/generate.py b/vendor/github.com/supranational/blst/bindings/go/generate.py index d40fad21..df311108 100644 --- a/vendor/github.com/supranational/blst/bindings/go/generate.py +++ b/vendor/github.com/supranational/blst/bindings/go/generate.py @@ -61,10 +61,10 @@ def remap(fout, fin, mapping, dont_touch, removeImports): fout = open(outFile, "w") -print("// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) -print("// DO NOT MODIFY THIS FILE!!", file=fout) +print("//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) +print("// DO NOT EDIT THIS FILE!!", file=fout) print("// The file is generated from *.tgo by " + here[-1], file=fout) -print("// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) +print("//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) fin = open('blst.tgo', "r") concatFile(fout, fin, False) @@ -119,10 +119,10 @@ def remap(fout, fin, mapping, dont_touch, removeImports): # Generate min-sig tests fout = open('blst_minsig_test.go', "w") -print("// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) +print("//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) print("// DO NOT EDIT THIS FILE!!", file=fout) print("// The file is generated from blst_minpk_test.go by " + here[-1], file=fout) -print("// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) +print("//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", file=fout) mapping.append(('MinPk', 'MinSig')) diff --git a/vendor/github.com/supranational/blst/bindings/go/rb_tree.go b/vendor/github.com/supranational/blst/bindings/go/rb_tree.go index 49044715..2e373595 100644 --- a/vendor/github.com/supranational/blst/bindings/go/rb_tree.go +++ b/vendor/github.com/supranational/blst/bindings/go/rb_tree.go @@ -69,7 +69,7 @@ func (tree *rbTree) insert(data *[]byte) bool { /* re-balance |tree| */ for k >= 2 /* && IS_RED(y = nodes[k-1]) */ { y := nodes[k-1] - if y.colour == black { //nolint:gosimple + if y.colour == black { break } @@ -77,7 +77,7 @@ func (tree *rbTree) insert(data *[]byte) bool { x := nodes[k-2] /* |z|'s grandparent */ s := x.leafs[ydir^1] /* |z|'s uncle */ - if s != nil && s.colour == red { //nolint:gosimple,revive + if s != nil && s.colour == red { x.colour = red y.colour = black s.colour = black diff --git a/vendor/github.com/tklauser/go-sysconf/.cirrus.yml b/vendor/github.com/tklauser/go-sysconf/.cirrus.yml index 33e6595c..1b27f196 100644 --- a/vendor/github.com/tklauser/go-sysconf/.cirrus.yml +++ b/vendor/github.com/tklauser/go-sysconf/.cirrus.yml @@ -1,10 +1,10 @@ env: CIRRUS_CLONE_DEPTH: 1 - GO_VERSION: go1.22.2 + GO_VERSION: go1.20 -freebsd_13_task: +freebsd_12_task: freebsd_instance: - image_family: freebsd-13-2 + image_family: freebsd-12-3 install_script: | pkg install -y go GOBIN=$PWD/bin go install golang.org/dl/${GO_VERSION}@latest @@ -12,9 +12,9 @@ freebsd_13_task: build_script: bin/${GO_VERSION} build -v ./... test_script: bin/${GO_VERSION} test -race ./... -freebsd_14_task: +freebsd_13_task: freebsd_instance: - image_family: freebsd-14-0 + image_family: freebsd-13-0 install_script: | pkg install -y go GOBIN=$PWD/bin go install golang.org/dl/${GO_VERSION}@latest diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_bsd.go b/vendor/github.com/tklauser/go-sysconf/sysconf_bsd.go index ec81c02a..7c96157b 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_bsd.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_bsd.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. //go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_darwin.go b/vendor/github.com/tklauser/go-sysconf/sysconf_darwin.go index b471ec10..3f5d83f6 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_darwin.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_darwin.go @@ -16,10 +16,6 @@ const ( _HOST_NAME_MAX = _MAXHOSTNAMELEN - 1 _LOGIN_NAME_MAX = _MAXLOGNAME _SYMLOOP_MAX = _MAXSYMLINKS - - // _PTHREAD_STACK_MIN changed in macOS 14 - _PTHREAD_STACK_MIN_LT_MACOS14 = 0x2000 - _PTHREAD_STACK_MIN_GE_MACOS14 = 0x4000 ) var uname struct { @@ -27,21 +23,6 @@ var uname struct { macOSMajor int } -func getMacOSMajor() int { - uname.Once.Do(func() { - var u unix.Utsname - err := unix.Uname(&u) - if err != nil { - return - } - rel := unix.ByteSliceToString(u.Release[:]) - ver := strings.Split(rel, ".") - maj, _ := strconv.Atoi(ver[0]) - uname.macOSMajor = maj - }) - return uname.macOSMajor -} - // sysconf implements sysconf(4) as in the Darwin libc (derived from the FreeBSD // libc), version 1534.81.1. // See https://github.com/apple-oss-distributions/Libc/tree/Libc-1534.81.1. @@ -110,10 +91,7 @@ func sysconf(name int) (int64, error) { case SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT, nil case SC_THREAD_STACK_MIN: - if getMacOSMajor() < 23 { - return _PTHREAD_STACK_MIN_LT_MACOS14, nil - } - return _PTHREAD_STACK_MIN_GE_MACOS14, nil + return _PTHREAD_STACK_MIN, nil case SC_THREAD_THREADS_MAX: return -1, nil case SC_TIMER_MAX: @@ -162,7 +140,18 @@ func sysconf(name int) (int64, error) { } return _POSIX_SEMAPHORES, nil case SC_SPAWN: - if getMacOSMajor() < 22 { + uname.Once.Do(func() { + var u unix.Utsname + err := unix.Uname(&u) + if err != nil { + return + } + rel := unix.ByteSliceToString(u.Release[:]) + ver := strings.Split(rel, ".") + maj, _ := strconv.Atoi(ver[0]) + uname.macOSMajor = maj + }) + if uname.macOSMajor < 22 { return -1, nil } // macOS 13 (Ventura) and later diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_generic.go b/vendor/github.com/tklauser/go-sysconf/sysconf_generic.go index 7dcc6f4c..248bdc99 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_generic.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_generic.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_linux.go b/vendor/github.com/tklauser/go-sysconf/sysconf_linux.go index 9af70070..5fb49ac7 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_linux.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_linux.go @@ -6,6 +6,7 @@ package sysconf import ( "bufio" + "io/ioutil" "os" "runtime" "strconv" @@ -25,7 +26,7 @@ const ( ) func readProcFsInt64(path string, fallback int64) int64 { - data, err := os.ReadFile(path) + data, err := ioutil.ReadFile(path) if err != nil { return fallback } @@ -85,16 +86,10 @@ func getNprocsProcStat() (int64, error) { s := bufio.NewScanner(f) for s.Scan() { if line := strings.TrimSpace(s.Text()); strings.HasPrefix(line, "cpu") { - cpu, _, found := strings.Cut(line, " ") - if found { - // skip first line with accumulated values - if cpu == "cpu" { - continue - } - _, err := strconv.ParseInt(cpu[len("cpu"):], 10, 64) - if err == nil { - count++ - } + l := strings.SplitN(line, " ", 2) + _, err := strconv.ParseInt(l[0][3:], 10, 64) + if err == nil { + count++ } } else { // The current format of /proc/stat has all the @@ -103,9 +98,6 @@ func getNprocsProcStat() (int64, error) { break } } - if err := s.Err(); err != nil { - return -1, err - } return count, nil } diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_netbsd.go b/vendor/github.com/tklauser/go-sysconf/sysconf_netbsd.go index 40f6c345..325d4a6a 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_netbsd.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_netbsd.go @@ -25,10 +25,10 @@ const ( _POSIX2_UPE = -1 ) -var clktck struct { - sync.Once - v int64 -} +var ( + clktck int64 + clktckOnce sync.Once +) func sysconfPOSIX(name int) (int64, error) { // NetBSD does not define all _POSIX_* values used in sysconf_posix.go @@ -42,6 +42,7 @@ func sysconf(name int) (int64, error) { // Duplicate the relevant values here. switch name { + // 1003.1 case SC_ARG_MAX: return sysctl32("kern.argmax"), nil @@ -54,14 +55,13 @@ func sysconf(name int) (int64, error) { } return -1, nil case SC_CLK_TCK: - // TODO: use sync.OnceValue once Go 1.21 is the minimal supported version - clktck.Do(func() { - clktck.v = -1 + clktckOnce.Do(func() { + clktck = -1 if ci, err := unix.SysctlClockinfo("kern.clockrate"); err == nil { - clktck.v = int64(ci.Hz) + clktck = int64(ci.Hz) } }) - return clktck.v, nil + return clktck, nil case SC_NGROUPS_MAX: return sysctl32("kern.ngroups"), nil case SC_JOB_CONTROL: diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_posix.go b/vendor/github.com/tklauser/go-sysconf/sysconf_posix.go index 830d8220..e61c0bc7 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_posix.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_posix.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. //go:build darwin || dragonfly || freebsd || linux || openbsd +// +build darwin dragonfly freebsd linux openbsd package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/sysconf_unsupported.go b/vendor/github.com/tklauser/go-sysconf/sysconf_unsupported.go index 5aa9119d..478d6920 100644 --- a/vendor/github.com/tklauser/go-sysconf/sysconf_unsupported.go +++ b/vendor/github.com/tklauser/go-sysconf/sysconf_unsupported.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. //go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris +// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_darwin.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_darwin.go index 80b64393..6fadf3db 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_darwin.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_darwin.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_darwin.go //go:build darwin +// +build darwin package sysconf @@ -234,6 +235,7 @@ const ( _PTHREAD_DESTRUCTOR_ITERATIONS = 0x4 _PTHREAD_KEYS_MAX = 0x200 + _PTHREAD_STACK_MIN = 0x2000 ) const ( diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_dragonfly.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_dragonfly.go index dae56570..0864cd44 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_dragonfly.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_dragonfly.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_dragonfly.go //go:build dragonfly +// +build dragonfly package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_freebsd.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_freebsd.go index 068f8a7e..9885411a 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_freebsd.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_freebsd.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_freebsd.go //go:build freebsd +// +build freebsd package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_linux.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_linux.go index 12f289d7..8545a342 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_linux.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_linux.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_linux.go //go:build linux +// +build linux package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_netbsd.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_netbsd.go index 772af475..d2aaf077 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_netbsd.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_netbsd.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_netbsd.go //go:build netbsd +// +build netbsd package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_openbsd.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_openbsd.go index 625b098f..badc66cb 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_openbsd.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_openbsd.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_openbsd.go //go:build openbsd +// +build openbsd package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_solaris.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_solaris.go index c155cf57..29b6f874 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_solaris.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_defs_solaris.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_defs_solaris.go //go:build solaris +// +build solaris package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_386.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_386.go index b5d48074..478fe63a 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_386.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_386.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_freebsd.go //go:build freebsd && 386 +// +build freebsd,386 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_amd64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_amd64.go index 89c880aa..7f58a4d8 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_amd64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_amd64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_freebsd.go //go:build freebsd && amd64 +// +build freebsd,amd64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm.go index 7b65fdd6..deb47595 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_freebsd.go //go:build freebsd && arm +// +build freebsd,arm package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm64.go index a86cb32b..556ba3da 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_arm64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_freebsd.go //go:build freebsd && arm64 +// +build freebsd,arm64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_riscv64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_riscv64.go index 6c847aee..b7cff760 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_riscv64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_freebsd_riscv64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_freebsd.go //go:build freebsd && riscv64 +// +build freebsd,riscv64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_386.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_386.go index 90963eb4..16ee7ea6 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_386.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_386.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && 386 +// +build linux,386 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_amd64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_amd64.go index 28ad6f18..39aee349 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_amd64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_amd64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && amd64 +// +build linux,amd64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm.go index ffbcf37d..2e401164 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && arm +// +build linux,arm package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm64.go index cc9f4d88..362403ab 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_arm64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && arm64 +// +build linux,arm64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_loong64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_loong64.go index f62b15a6..95a71f4a 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_loong64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_loong64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && loong64 +// +build linux,loong64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips.go index 37f492a8..868b0ffb 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && mips +// +build linux,mips package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64.go index ae7b7f9c..5949f3d7 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && mips64 +// +build linux,mips64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64le.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64le.go index fe14670f..1853419a 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64le.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mips64le.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && mips64le +// +build linux,mips64le package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mipsle.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mipsle.go index d204585b..ff41b346 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mipsle.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_mipsle.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && mipsle +// +build linux,mipsle package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64.go index 9ec78d33..38874372 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && ppc64 +// +build linux,ppc64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64le.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64le.go index a5420672..6d76929a 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64le.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_ppc64le.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && ppc64le +// +build linux,ppc64le package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_riscv64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_riscv64.go index bfb92392..3d7d71b3 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_riscv64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_riscv64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && riscv64 +// +build linux,riscv64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_s390x.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_s390x.go index 6e935c87..9cf8529f 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_s390x.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_linux_s390x.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_linux.go //go:build linux && s390x +// +build linux,s390x package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_386.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_386.go index ea0b24a8..3cd64dd6 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_386.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_386.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_netbsd.go //go:build netbsd && 386 +// +build netbsd,386 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_amd64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_amd64.go index 2d377e25..02fc1d0e 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_amd64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_amd64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_netbsd.go //go:build netbsd && amd64 +// +build netbsd,amd64 package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm.go index 4a6d8367..16f9b6e7 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_netbsd.go //go:build netbsd && arm +// +build netbsd,arm package sysconf diff --git a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm64.go b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm64.go index 49fb6725..e530339c 100644 --- a/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm64.go +++ b/vendor/github.com/tklauser/go-sysconf/zsysconf_values_netbsd_arm64.go @@ -2,6 +2,7 @@ // cgo -godefs sysconf_values_netbsd.go //go:build netbsd && arm64 +// +build netbsd,arm64 package sysconf diff --git a/vendor/github.com/tklauser/numcpus/.cirrus.yml b/vendor/github.com/tklauser/numcpus/.cirrus.yml index 33e6595c..69c6ced5 100644 --- a/vendor/github.com/tklauser/numcpus/.cirrus.yml +++ b/vendor/github.com/tklauser/numcpus/.cirrus.yml @@ -1,23 +1,13 @@ env: CIRRUS_CLONE_DEPTH: 1 - GO_VERSION: go1.22.2 + GO_VERSION: go1.20 -freebsd_13_task: +freebsd_12_task: freebsd_instance: - image_family: freebsd-13-2 + image_family: freebsd-12-3 install_script: | pkg install -y go GOBIN=$PWD/bin go install golang.org/dl/${GO_VERSION}@latest bin/${GO_VERSION} download - build_script: bin/${GO_VERSION} build -v ./... - test_script: bin/${GO_VERSION} test -race ./... - -freebsd_14_task: - freebsd_instance: - image_family: freebsd-14-0 - install_script: | - pkg install -y go - GOBIN=$PWD/bin go install golang.org/dl/${GO_VERSION}@latest - bin/${GO_VERSION} download - build_script: bin/${GO_VERSION} build -v ./... - test_script: bin/${GO_VERSION} test -race ./... + build_script: bin/${GO_VERSION} build -buildvcs=false -v ./... + test_script: bin/${GO_VERSION} test -buildvcs=false -race ./... diff --git a/vendor/github.com/tklauser/numcpus/numcpus_bsd.go b/vendor/github.com/tklauser/numcpus/numcpus_bsd.go index efd8db0f..9e77e38e 100644 --- a/vendor/github.com/tklauser/numcpus/numcpus_bsd.go +++ b/vendor/github.com/tklauser/numcpus/numcpus_bsd.go @@ -13,6 +13,7 @@ // limitations under the License. //go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd package numcpus diff --git a/vendor/github.com/tklauser/numcpus/numcpus_linux.go b/vendor/github.com/tklauser/numcpus/numcpus_linux.go index 7e75cb06..1a30525b 100644 --- a/vendor/github.com/tklauser/numcpus/numcpus_linux.go +++ b/vendor/github.com/tklauser/numcpus/numcpus_linux.go @@ -15,6 +15,7 @@ package numcpus import ( + "io/ioutil" "os" "path/filepath" "strconv" @@ -34,7 +35,7 @@ func getFromCPUAffinity() (int, error) { } func readCPURange(file string) (int, error) { - buf, err := os.ReadFile(filepath.Join(sysfsCPUBasePath, file)) + buf, err := ioutil.ReadFile(filepath.Join(sysfsCPUBasePath, file)) if err != nil { return 0, err } @@ -47,16 +48,16 @@ func parseCPURange(cpus string) (int, error) { if len(cpuRange) == 0 { continue } - from, to, found := strings.Cut(cpuRange, "-") - first, err := strconv.ParseUint(from, 10, 32) + rangeOp := strings.SplitN(cpuRange, "-", 2) + first, err := strconv.ParseUint(rangeOp[0], 10, 32) if err != nil { return 0, err } - if !found { + if len(rangeOp) == 1 { n++ continue } - last, err := strconv.ParseUint(to, 10, 32) + last, err := strconv.ParseUint(rangeOp[1], 10, 32) if err != nil { return 0, err } @@ -88,7 +89,7 @@ func getConfigured() (int, error) { } func getKernelMax() (int, error) { - buf, err := os.ReadFile(filepath.Join(sysfsCPUBasePath, "kernel_max")) + buf, err := ioutil.ReadFile(filepath.Join(sysfsCPUBasePath, "kernel_max")) if err != nil { return 0, err } diff --git a/vendor/github.com/tklauser/numcpus/numcpus_solaris.go b/vendor/github.com/tklauser/numcpus/numcpus_solaris.go index f3b632fe..a2643237 100644 --- a/vendor/github.com/tklauser/numcpus/numcpus_solaris.go +++ b/vendor/github.com/tklauser/numcpus/numcpus_solaris.go @@ -13,6 +13,7 @@ // limitations under the License. //go:build solaris +// +build solaris package numcpus diff --git a/vendor/github.com/tklauser/numcpus/numcpus_unsupported.go b/vendor/github.com/tklauser/numcpus/numcpus_unsupported.go index e72355ec..4a0b7c43 100644 --- a/vendor/github.com/tklauser/numcpus/numcpus_unsupported.go +++ b/vendor/github.com/tklauser/numcpus/numcpus_unsupported.go @@ -13,6 +13,7 @@ // limitations under the License. //go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows +// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows package numcpus diff --git a/vendor/github.com/urfave/cli/v2/.gitignore b/vendor/github.com/urfave/cli/v2/.gitignore index 1ef91a60..d7d26b1f 100644 --- a/vendor/github.com/urfave/cli/v2/.gitignore +++ b/vendor/github.com/urfave/cli/v2/.gitignore @@ -4,7 +4,6 @@ .*envrc .envrc .idea -# goimports is installed here if not available /.local/ /site/ coverage.txt diff --git a/vendor/github.com/urfave/cli/v2/.golangci.yaml b/vendor/github.com/urfave/cli/v2/.golangci.yaml deleted file mode 100644 index 89b6e866..00000000 --- a/vendor/github.com/urfave/cli/v2/.golangci.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# https://golangci-lint.run/usage/configuration/ -linters: - enable: - - misspell diff --git a/vendor/github.com/urfave/cli/v2/app.go b/vendor/github.com/urfave/cli/v2/app.go index af072e76..19b76c9b 100644 --- a/vendor/github.com/urfave/cli/v2/app.go +++ b/vendor/github.com/urfave/cli/v2/app.go @@ -23,8 +23,8 @@ var ( fmt.Sprintf("See %s", appActionDeprecationURL), 2) ignoreFlagPrefix = "test." // this is to ignore test flags when adding flags from other packages - SuggestFlag SuggestFlagFunc = nil // initialized in suggestions.go unless built with urfave_cli_no_suggest - SuggestCommand SuggestCommandFunc = nil // initialized in suggestions.go unless built with urfave_cli_no_suggest + SuggestFlag SuggestFlagFunc = suggestFlag + SuggestCommand SuggestCommandFunc = suggestCommand SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate ) @@ -39,8 +39,6 @@ type App struct { Usage string // Text to override the USAGE section of help UsageText string - // Whether this command supports arguments - Args bool // Description of the program argument format. ArgsUsage string // Version of the program @@ -229,6 +227,8 @@ func (a *App) Setup() { a.separator.disabled = true } + var newCommands []*Command + for _, c := range a.Commands { cname := c.Name if c.HelpName != "" { @@ -237,7 +237,9 @@ func (a *App) Setup() { c.separator = a.separator c.HelpName = fmt.Sprintf("%s %s", a.HelpName, cname) c.flagCategories = newFlagCategoriesFromFlags(c.Flags) + newCommands = append(newCommands, c) } + a.Commands = newCommands if a.Command(helpCommand.Name) == nil && !a.HideHelp { if !a.HideHelpCommand { @@ -327,9 +329,6 @@ func (a *App) RunContext(ctx context.Context, arguments []string) (err error) { a.rootCommand = a.newRootCommand() cCtx.Command = a.rootCommand - if err := checkDuplicatedCmds(a.rootCommand); err != nil { - return err - } return a.rootCommand.Run(cCtx, arguments...) } @@ -364,9 +363,6 @@ func (a *App) suggestFlagFromError(err error, command string) (string, error) { hideHelp = hideHelp || cmd.HideHelp } - if SuggestFlag == nil { - return "", err - } suggestion := SuggestFlag(flags, flag, hideHelp) if len(suggestion) == 0 { return "", err @@ -459,6 +455,30 @@ func (a *App) handleExitCoder(cCtx *Context, err error) { } } +func (a *App) commandNames() []string { + var cmdNames []string + + for _, cmd := range a.Commands { + cmdNames = append(cmdNames, cmd.Names()...) + } + + return cmdNames +} + +func (a *App) validCommandName(checkCmdName string) bool { + valid := false + allCommandNames := a.commandNames() + + for _, cmdName := range allCommandNames { + if checkCmdName == cmdName { + valid = true + break + } + } + + return valid +} + func (a *App) argsWithDefaultCommand(oldArgs Args) Args { if a.DefaultCommand != "" { rawArgs := append([]string{a.DefaultCommand}, oldArgs.Slice()...) diff --git a/vendor/github.com/urfave/cli/v2/category.go b/vendor/github.com/urfave/cli/v2/category.go index 0986fffc..ccc043c2 100644 --- a/vendor/github.com/urfave/cli/v2/category.go +++ b/vendor/github.com/urfave/cli/v2/category.go @@ -104,17 +104,17 @@ func newFlagCategoriesFromFlags(fs []Flag) FlagCategories { var categorized bool for _, fl := range fs { if cf, ok := fl.(CategorizableFlag); ok { - if cat := cf.GetCategory(); cat != "" && cf.IsVisible() { + if cat := cf.GetCategory(); cat != "" { fc.AddFlag(cat, cf) categorized = true } } } - if categorized { + if categorized == true { for _, fl := range fs { if cf, ok := fl.(CategorizableFlag); ok { - if cf.GetCategory() == "" && cf.IsVisible() { + if cf.GetCategory() == "" { fc.AddFlag("", fl) } } diff --git a/vendor/github.com/urfave/cli/v2/command.go b/vendor/github.com/urfave/cli/v2/command.go index 472c1ff4..69a0fdf6 100644 --- a/vendor/github.com/urfave/cli/v2/command.go +++ b/vendor/github.com/urfave/cli/v2/command.go @@ -20,8 +20,6 @@ type Command struct { UsageText string // A longer explanation of how the command works Description string - // Whether this command supports arguments - Args bool // A short description of the arguments of this command ArgsUsage string // The category the command is part of @@ -132,12 +130,15 @@ func (c *Command) setup(ctx *Context) { } sort.Sort(c.categories.(*commandCategories)) + var newCmds []*Command for _, scmd := range c.Subcommands { if scmd.HelpName == "" { scmd.HelpName = fmt.Sprintf("%s %s", c.HelpName, scmd.Name) } scmd.separator = c.separator + newCmds = append(newCmds, scmd) } + c.Subcommands = newCmds if c.BashComplete == nil { c.BashComplete = DefaultCompleteWithFlags(c) @@ -148,9 +149,6 @@ func (c *Command) Run(cCtx *Context, arguments ...string) (err error) { if !c.isRoot { c.setup(cCtx) - if err := checkDuplicatedCmds(c); err != nil { - return err - } } a := args(arguments) @@ -406,16 +404,3 @@ func hasCommand(commands []*Command, command *Command) bool { return false } - -func checkDuplicatedCmds(parent *Command) error { - seen := make(map[string]struct{}) - for _, c := range parent.Subcommands { - for _, name := range c.Names() { - if _, exists := seen[name]; exists { - return fmt.Errorf("parent command [%s] has duplicated subcommand name or alias: %s", parent.Name, name) - } - seen[name] = struct{}{} - } - } - return nil -} diff --git a/vendor/github.com/urfave/cli/v2/context.go b/vendor/github.com/urfave/cli/v2/context.go index 8dd47652..a45c120b 100644 --- a/vendor/github.com/urfave/cli/v2/context.go +++ b/vendor/github.com/urfave/cli/v2/context.go @@ -144,7 +144,7 @@ func (cCtx *Context) Lineage() []*Context { return lineage } -// Count returns the num of occurrences of this flag +// Count returns the num of occurences of this flag func (cCtx *Context) Count(name string) int { if fs := cCtx.lookupFlagSet(name); fs != nil { if cf, ok := fs.Lookup(name).Value.(Countable); ok { diff --git a/vendor/github.com/urfave/cli/v2/flag_bool.go b/vendor/github.com/urfave/cli/v2/flag_bool.go index 01862ea7..369d18b7 100644 --- a/vendor/github.com/urfave/cli/v2/flag_bool.go +++ b/vendor/github.com/urfave/cli/v2/flag_bool.go @@ -84,10 +84,7 @@ func (f *BoolFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return fmt.Sprintf("%v", f.defaultValue) - } - return fmt.Sprintf("%v", f.Value) + return fmt.Sprintf("%v", f.defaultValue) } // GetEnvVars returns the env vars for this flag @@ -108,7 +105,6 @@ func (f *BoolFlag) RunAction(c *Context) error { func (f *BoolFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { diff --git a/vendor/github.com/urfave/cli/v2/flag_duration.go b/vendor/github.com/urfave/cli/v2/flag_duration.go index e600cc30..eac4cb83 100644 --- a/vendor/github.com/urfave/cli/v2/flag_duration.go +++ b/vendor/github.com/urfave/cli/v2/flag_duration.go @@ -32,10 +32,7 @@ func (f *DurationFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return f.defaultValue.String() - } - return f.Value.String() + return f.defaultValue.String() } // GetEnvVars returns the env vars for this flag @@ -47,7 +44,6 @@ func (f *DurationFlag) GetEnvVars() []string { func (f *DurationFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { diff --git a/vendor/github.com/urfave/cli/v2/flag_float64.go b/vendor/github.com/urfave/cli/v2/flag_float64.go index 6a4de5c8..bce26c19 100644 --- a/vendor/github.com/urfave/cli/v2/flag_float64.go +++ b/vendor/github.com/urfave/cli/v2/flag_float64.go @@ -32,10 +32,7 @@ func (f *Float64Flag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return fmt.Sprintf("%v", f.defaultValue) - } - return fmt.Sprintf("%v", f.Value) + return f.GetValue() } // GetEnvVars returns the env vars for this flag @@ -45,9 +42,6 @@ func (f *Float64Flag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *Float64Flag) Apply(set *flag.FlagSet) error { - f.defaultValue = f.Value - f.defaultValueSet = true - if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { valFloat, err := strconv.ParseFloat(val, 64) diff --git a/vendor/github.com/urfave/cli/v2/flag_generic.go b/vendor/github.com/urfave/cli/v2/flag_generic.go index 7528c934..039ffdfe 100644 --- a/vendor/github.com/urfave/cli/v2/flag_generic.go +++ b/vendor/github.com/urfave/cli/v2/flag_generic.go @@ -53,15 +53,9 @@ func (f *GenericFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - val := f.Value - if f.defaultValueSet { - val = f.defaultValue + if f.defaultValue != nil { + return f.defaultValue.String() } - - if val != nil { - return val.String() - } - return "" } @@ -76,7 +70,6 @@ func (f *GenericFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it if f.Value != nil { f.defaultValue = &stringGeneric{value: f.Value.String()} - f.defaultValueSet = true } if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { diff --git a/vendor/github.com/urfave/cli/v2/flag_int.go b/vendor/github.com/urfave/cli/v2/flag_int.go index 750e7ebf..d681270a 100644 --- a/vendor/github.com/urfave/cli/v2/flag_int.go +++ b/vendor/github.com/urfave/cli/v2/flag_int.go @@ -32,10 +32,7 @@ func (f *IntFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return fmt.Sprintf("%d", f.defaultValue) - } - return fmt.Sprintf("%d", f.Value) + return fmt.Sprintf("%d", f.defaultValue) } // GetEnvVars returns the env vars for this flag @@ -47,7 +44,6 @@ func (f *IntFlag) GetEnvVars() []string { func (f *IntFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { diff --git a/vendor/github.com/urfave/cli/v2/flag_int64.go b/vendor/github.com/urfave/cli/v2/flag_int64.go index 688c2671..6f8c8d27 100644 --- a/vendor/github.com/urfave/cli/v2/flag_int64.go +++ b/vendor/github.com/urfave/cli/v2/flag_int64.go @@ -32,10 +32,7 @@ func (f *Int64Flag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return fmt.Sprintf("%d", f.defaultValue) - } - return fmt.Sprintf("%d", f.Value) + return fmt.Sprintf("%d", f.defaultValue) } // GetEnvVars returns the env vars for this flag @@ -47,7 +44,6 @@ func (f *Int64Flag) GetEnvVars() []string { func (f *Int64Flag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { diff --git a/vendor/github.com/urfave/cli/v2/flag_path.go b/vendor/github.com/urfave/cli/v2/flag_path.go index 76cb3524..c4986779 100644 --- a/vendor/github.com/urfave/cli/v2/flag_path.go +++ b/vendor/github.com/urfave/cli/v2/flag_path.go @@ -33,14 +33,10 @@ func (f *PathFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - val := f.Value - if f.defaultValueSet { - val = f.defaultValue + if f.defaultValue == "" { + return f.defaultValue } - if val == "" { - return val - } - return fmt.Sprintf("%q", val) + return fmt.Sprintf("%q", f.defaultValue) } // GetEnvVars returns the env vars for this flag @@ -52,7 +48,6 @@ func (f *PathFlag) GetEnvVars() []string { func (f *PathFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { f.Value = val diff --git a/vendor/github.com/urfave/cli/v2/flag_string.go b/vendor/github.com/urfave/cli/v2/flag_string.go index 0f73e062..4e55a2ca 100644 --- a/vendor/github.com/urfave/cli/v2/flag_string.go +++ b/vendor/github.com/urfave/cli/v2/flag_string.go @@ -31,15 +31,10 @@ func (f *StringFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - val := f.Value - if f.defaultValueSet { - val = f.defaultValue + if f.defaultValue == "" { + return f.defaultValue } - - if val == "" { - return val - } - return fmt.Sprintf("%q", val) + return fmt.Sprintf("%q", f.defaultValue) } // GetEnvVars returns the env vars for this flag @@ -51,7 +46,6 @@ func (f *StringFlag) GetEnvVars() []string { func (f *StringFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { f.Value = val diff --git a/vendor/github.com/urfave/cli/v2/flag_timestamp.go b/vendor/github.com/urfave/cli/v2/flag_timestamp.go index b9012308..83f750a3 100644 --- a/vendor/github.com/urfave/cli/v2/flag_timestamp.go +++ b/vendor/github.com/urfave/cli/v2/flag_timestamp.go @@ -120,13 +120,8 @@ func (f *TimestampFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - val := f.Value - if f.defaultValueSet { - val = f.defaultValue - } - - if val != nil && val.timestamp != nil { - return val.timestamp.String() + if f.defaultValue != nil && f.defaultValue.timestamp != nil { + return f.defaultValue.timestamp.String() } return "" @@ -149,7 +144,6 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error { f.Value.SetLocation(f.Timezone) f.defaultValue = f.Value.clone() - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if err := f.Value.Set(val); err != nil { diff --git a/vendor/github.com/urfave/cli/v2/flag_uint.go b/vendor/github.com/urfave/cli/v2/flag_uint.go index 8d5b8545..d11aa0a8 100644 --- a/vendor/github.com/urfave/cli/v2/flag_uint.go +++ b/vendor/github.com/urfave/cli/v2/flag_uint.go @@ -25,7 +25,6 @@ func (f *UintFlag) GetCategory() string { func (f *UintFlag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { @@ -70,10 +69,7 @@ func (f *UintFlag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return fmt.Sprintf("%d", f.defaultValue) - } - return fmt.Sprintf("%d", f.Value) + return fmt.Sprintf("%d", f.defaultValue) } // GetEnvVars returns the env vars for this flag diff --git a/vendor/github.com/urfave/cli/v2/flag_uint64.go b/vendor/github.com/urfave/cli/v2/flag_uint64.go index c356e533..ea73100a 100644 --- a/vendor/github.com/urfave/cli/v2/flag_uint64.go +++ b/vendor/github.com/urfave/cli/v2/flag_uint64.go @@ -25,7 +25,6 @@ func (f *Uint64Flag) GetCategory() string { func (f *Uint64Flag) Apply(set *flag.FlagSet) error { // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value - f.defaultValueSet = true if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val != "" { @@ -70,10 +69,7 @@ func (f *Uint64Flag) GetDefaultText() string { if f.DefaultText != "" { return f.DefaultText } - if f.defaultValueSet { - return fmt.Sprintf("%d", f.defaultValue) - } - return fmt.Sprintf("%d", f.Value) + return fmt.Sprintf("%d", f.defaultValue) } // GetEnvVars returns the env vars for this flag diff --git a/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go b/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go index d3420186..e845dd52 100644 --- a/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go +++ b/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go @@ -190,15 +190,6 @@ func (f *Uint64SliceFlag) Get(ctx *Context) []uint64 { return ctx.Uint64Slice(f.Name) } -// RunAction executes flag action if set -func (f *Uint64SliceFlag) RunAction(c *Context) error { - if f.Action != nil { - return f.Action(c, c.Uint64Slice(f.Name)) - } - - return nil -} - // Uint64Slice looks up the value of a local Uint64SliceFlag, returns // nil if not found func (cCtx *Context) Uint64Slice(name string) []uint64 { diff --git a/vendor/github.com/urfave/cli/v2/flag_uint_slice.go b/vendor/github.com/urfave/cli/v2/flag_uint_slice.go index 4dc13e12..d2aed480 100644 --- a/vendor/github.com/urfave/cli/v2/flag_uint_slice.go +++ b/vendor/github.com/urfave/cli/v2/flag_uint_slice.go @@ -201,15 +201,6 @@ func (f *UintSliceFlag) Get(ctx *Context) []uint { return ctx.UintSlice(f.Name) } -// RunAction executes flag action if set -func (f *UintSliceFlag) RunAction(c *Context) error { - if f.Action != nil { - return f.Action(c, c.UintSlice(f.Name)) - } - - return nil -} - // UintSlice looks up the value of a local UintSliceFlag, returns // nil if not found func (cCtx *Context) UintSlice(name string) []uint { diff --git a/vendor/github.com/urfave/cli/v2/godoc-current.txt b/vendor/github.com/urfave/cli/v2/godoc-current.txt index 4b620fee..6016bd82 100644 --- a/vendor/github.com/urfave/cli/v2/godoc-current.txt +++ b/vendor/github.com/urfave/cli/v2/godoc-current.txt @@ -27,15 +27,15 @@ application: VARIABLES var ( - SuggestFlag SuggestFlagFunc = nil // initialized in suggestions.go unless built with urfave_cli_no_suggest - SuggestCommand SuggestCommandFunc = nil // initialized in suggestions.go unless built with urfave_cli_no_suggest + SuggestFlag SuggestFlagFunc = suggestFlag + SuggestCommand SuggestCommandFunc = suggestCommand SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate ) var AppHelpTemplate = `NAME: {{template "helpNameTemplate" .}} USAGE: - {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}}[arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} VERSION: {{.Version}}{{end}}{{end}}{{if .Description}} @@ -136,7 +136,7 @@ var SubcommandHelpTemplate = `NAME: {{template "helpNameTemplate" .}} USAGE: - {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}}[arguments...]{{end}}{{end}}{{end}}{{if .Description}} + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}} DESCRIPTION: {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} @@ -253,8 +253,6 @@ type App struct { Usage string // Text to override the USAGE section of help UsageText string - // Whether this command supports arguments - Args bool // Description of the program argument format. ArgsUsage string // Version of the program @@ -525,8 +523,6 @@ type Command struct { UsageText string // A longer explanation of how the command works Description string - // Whether this command supports arguments - Args bool // A short description of the arguments of this command ArgsUsage string // The category the command is part of @@ -653,7 +649,7 @@ func (cCtx *Context) Bool(name string) bool Bool looks up the value of a local BoolFlag, returns false if not found func (cCtx *Context) Count(name string) int - Count returns the num of occurrences of this flag + Count returns the num of occurences of this flag func (cCtx *Context) Duration(name string) time.Duration Duration looks up the value of a local DurationFlag, returns 0 if not found @@ -2146,9 +2142,6 @@ func (f *Uint64SliceFlag) IsVisible() bool func (f *Uint64SliceFlag) Names() []string Names returns the names of the flag -func (f *Uint64SliceFlag) RunAction(c *Context) error - RunAction executes flag action if set - func (f *Uint64SliceFlag) String() string String returns a readable representation of this value (for usage defaults) @@ -2314,9 +2307,6 @@ func (f *UintSliceFlag) IsVisible() bool func (f *UintSliceFlag) Names() []string Names returns the names of the flag -func (f *UintSliceFlag) RunAction(c *Context) error - RunAction executes flag action if set - func (f *UintSliceFlag) String() string String returns a readable representation of this value (for usage defaults) diff --git a/vendor/github.com/urfave/cli/v2/help.go b/vendor/github.com/urfave/cli/v2/help.go index 640e2904..885d7843 100644 --- a/vendor/github.com/urfave/cli/v2/help.go +++ b/vendor/github.com/urfave/cli/v2/help.go @@ -69,7 +69,7 @@ var helpCommand = &Command{ } // Case 3, 5 - if (len(cCtx.Command.Subcommands) == 1 && !cCtx.Command.HideHelp && !cCtx.Command.HideHelpCommand) || + if (len(cCtx.Command.Subcommands) == 1 && !cCtx.Command.HideHelp) || (len(cCtx.Command.Subcommands) == 0 && cCtx.Command.HideHelp) { templ := cCtx.Command.CustomHelpTemplate if templ == "" { @@ -278,7 +278,7 @@ func ShowCommandHelp(ctx *Context, command string) error { if ctx.App.CommandNotFound == nil { errMsg := fmt.Sprintf("No help topic for '%v'", command) - if ctx.App.Suggest && SuggestCommand != nil { + if ctx.App.Suggest { if suggestion := SuggestCommand(ctx.Command.Subcommands, command); suggestion != "" { errMsg += ". " + suggestion } @@ -376,26 +376,17 @@ func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) - templates := map[string]string{ - "helpNameTemplate": helpNameTemplate, - "usageTemplate": usageTemplate, - "descriptionTemplate": descriptionTemplate, - "visibleCommandTemplate": visibleCommandTemplate, - "copyrightTemplate": copyrightTemplate, - "versionTemplate": versionTemplate, - "visibleFlagCategoryTemplate": visibleFlagCategoryTemplate, - "visibleFlagTemplate": visibleFlagTemplate, - "visibleGlobalFlagCategoryTemplate": strings.Replace(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS", -1), - "authorsTemplate": authorsTemplate, - "visibleCommandCategoryTemplate": visibleCommandCategoryTemplate, - } - for name, value := range templates { - if _, err := t.New(name).Parse(value); err != nil { - if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { - _, _ = fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) - } - } - } + t.New("helpNameTemplate").Parse(helpNameTemplate) + t.New("usageTemplate").Parse(usageTemplate) + t.New("descriptionTemplate").Parse(descriptionTemplate) + t.New("visibleCommandTemplate").Parse(visibleCommandTemplate) + t.New("copyrightTemplate").Parse(copyrightTemplate) + t.New("versionTemplate").Parse(versionTemplate) + t.New("visibleFlagCategoryTemplate").Parse(visibleFlagCategoryTemplate) + t.New("visibleFlagTemplate").Parse(visibleFlagTemplate) + t.New("visibleGlobalFlagCategoryTemplate").Parse(strings.Replace(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS", -1)) + t.New("authorsTemplate").Parse(authorsTemplate) + t.New("visibleCommandCategoryTemplate").Parse(visibleCommandCategoryTemplate) err := t.Execute(w, data) if err != nil { @@ -424,9 +415,6 @@ func checkVersion(cCtx *Context) bool { } func checkHelp(cCtx *Context) bool { - if HelpFlag == nil { - return false - } found := false for _, name := range HelpFlag.Names() { if cCtx.Bool(name) { @@ -438,6 +426,24 @@ func checkHelp(cCtx *Context) bool { return found } +func checkCommandHelp(c *Context, name string) bool { + if c.Bool("h") || c.Bool("help") { + _ = ShowCommandHelp(c, name) + return true + } + + return false +} + +func checkSubcommandHelp(cCtx *Context) bool { + if cCtx.Bool("h") || cCtx.Bool("help") { + _ = ShowSubcommandHelp(cCtx) + return true + } + + return false +} + func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { if !a.EnableBashCompletion { return false, arguments diff --git a/vendor/github.com/urfave/cli/v2/mkdocs-reqs.txt b/vendor/github.com/urfave/cli/v2/mkdocs-requirements.txt similarity index 100% rename from vendor/github.com/urfave/cli/v2/mkdocs-reqs.txt rename to vendor/github.com/urfave/cli/v2/mkdocs-requirements.txt diff --git a/vendor/github.com/urfave/cli/v2/mkdocs.yml b/vendor/github.com/urfave/cli/v2/mkdocs.yml index f7bfd419..02657b9e 100644 --- a/vendor/github.com/urfave/cli/v2/mkdocs.yml +++ b/vendor/github.com/urfave/cli/v2/mkdocs.yml @@ -1,7 +1,7 @@ # NOTE: the mkdocs dependencies will need to be installed out of # band until this whole thing gets more automated: # -# pip install -r mkdocs-reqs.txt +# pip install -r mkdocs-requirements.txt # site_name: urfave/cli diff --git a/vendor/github.com/urfave/cli/v2/suggestions.go b/vendor/github.com/urfave/cli/v2/suggestions.go index 9d2b7a81..87fa905d 100644 --- a/vendor/github.com/urfave/cli/v2/suggestions.go +++ b/vendor/github.com/urfave/cli/v2/suggestions.go @@ -1,6 +1,3 @@ -//go:build !urfave_cli_no_suggest -// +build !urfave_cli_no_suggest - package cli import ( @@ -9,11 +6,6 @@ import ( "github.com/xrash/smetrics" ) -func init() { - SuggestFlag = suggestFlag - SuggestCommand = suggestCommand -} - func jaroWinkler(a, b string) float64 { // magic values are from https://github.com/xrash/smetrics/blob/039620a656736e6ad994090895784a7af15e0b80/jaro-winkler.go#L8 const ( @@ -29,7 +21,7 @@ func suggestFlag(flags []Flag, provided string, hideHelp bool) string { for _, flag := range flags { flagNames := flag.Names() - if !hideHelp && HelpFlag != nil { + if !hideHelp { flagNames = append(flagNames, HelpFlag.Names()...) } for _, name := range flagNames { diff --git a/vendor/github.com/urfave/cli/v2/template.go b/vendor/github.com/urfave/cli/v2/template.go index 5748f4c2..da98890e 100644 --- a/vendor/github.com/urfave/cli/v2/template.go +++ b/vendor/github.com/urfave/cli/v2/template.go @@ -1,7 +1,7 @@ package cli var helpNameTemplate = `{{$v := offset .HelpName 6}}{{wrap .HelpName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}` -var usageTemplate = `{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}}{{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}} [arguments...]{{end}}{{end}}{{end}}` +var usageTemplate = `{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}` var descriptionTemplate = `{{wrap .Description 3}}` var authorsTemplate = `{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: {{range $index, $author := .Authors}}{{if $index}} @@ -35,7 +35,7 @@ var AppHelpTemplate = `NAME: {{template "helpNameTemplate" .}} USAGE: - {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}}[arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} VERSION: {{.Version}}{{end}}{{end}}{{if .Description}} @@ -83,7 +83,7 @@ var SubcommandHelpTemplate = `NAME: {{template "helpNameTemplate" .}} USAGE: - {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}}[arguments...]{{end}}{{end}}{{end}}{{if .Description}} + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}} DESCRIPTION: {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} diff --git a/vendor/github.com/urfave/cli/v2/zz_generated.flags.go b/vendor/github.com/urfave/cli/v2/zz_generated.flags.go index f2fc8c88..73e77145 100644 --- a/vendor/github.com/urfave/cli/v2/zz_generated.flags.go +++ b/vendor/github.com/urfave/cli/v2/zz_generated.flags.go @@ -23,8 +23,7 @@ type Float64SliceFlag struct { Aliases []string EnvVars []string - defaultValue *Float64Slice - defaultValueSet bool + defaultValue *Float64Slice separator separatorSpec @@ -70,8 +69,7 @@ type GenericFlag struct { Aliases []string EnvVars []string - defaultValue Generic - defaultValueSet bool + defaultValue Generic TakesFile bool @@ -122,8 +120,7 @@ type Int64SliceFlag struct { Aliases []string EnvVars []string - defaultValue *Int64Slice - defaultValueSet bool + defaultValue *Int64Slice separator separatorSpec @@ -169,8 +166,7 @@ type IntSliceFlag struct { Aliases []string EnvVars []string - defaultValue *IntSlice - defaultValueSet bool + defaultValue *IntSlice separator separatorSpec @@ -216,8 +212,7 @@ type PathFlag struct { Aliases []string EnvVars []string - defaultValue Path - defaultValueSet bool + defaultValue Path TakesFile bool @@ -268,8 +263,7 @@ type StringSliceFlag struct { Aliases []string EnvVars []string - defaultValue *StringSlice - defaultValueSet bool + defaultValue *StringSlice separator separatorSpec @@ -319,8 +313,7 @@ type TimestampFlag struct { Aliases []string EnvVars []string - defaultValue *Timestamp - defaultValueSet bool + defaultValue *Timestamp Layout string @@ -373,8 +366,7 @@ type Uint64SliceFlag struct { Aliases []string EnvVars []string - defaultValue *Uint64Slice - defaultValueSet bool + defaultValue *Uint64Slice separator separatorSpec @@ -420,8 +412,7 @@ type UintSliceFlag struct { Aliases []string EnvVars []string - defaultValue *UintSlice - defaultValueSet bool + defaultValue *UintSlice separator separatorSpec @@ -467,8 +458,7 @@ type BoolFlag struct { Aliases []string EnvVars []string - defaultValue bool - defaultValueSet bool + defaultValue bool Count *int @@ -521,8 +511,7 @@ type Float64Flag struct { Aliases []string EnvVars []string - defaultValue float64 - defaultValueSet bool + defaultValue float64 Action func(*Context, float64) error } @@ -571,8 +560,7 @@ type IntFlag struct { Aliases []string EnvVars []string - defaultValue int - defaultValueSet bool + defaultValue int Base int @@ -623,8 +611,7 @@ type Int64Flag struct { Aliases []string EnvVars []string - defaultValue int64 - defaultValueSet bool + defaultValue int64 Base int @@ -675,8 +662,7 @@ type StringFlag struct { Aliases []string EnvVars []string - defaultValue string - defaultValueSet bool + defaultValue string TakesFile bool @@ -727,8 +713,7 @@ type DurationFlag struct { Aliases []string EnvVars []string - defaultValue time.Duration - defaultValueSet bool + defaultValue time.Duration Action func(*Context, time.Duration) error } @@ -777,8 +762,7 @@ type UintFlag struct { Aliases []string EnvVars []string - defaultValue uint - defaultValueSet bool + defaultValue uint Base int @@ -829,8 +813,7 @@ type Uint64Flag struct { Aliases []string EnvVars []string - defaultValue uint64 - defaultValueSet bool + defaultValue uint64 Base int diff --git a/vendor/github.com/xrash/smetrics/soundex.go b/vendor/github.com/xrash/smetrics/soundex.go index 18c3aef7..a2ad034d 100644 --- a/vendor/github.com/xrash/smetrics/soundex.go +++ b/vendor/github.com/xrash/smetrics/soundex.go @@ -6,58 +6,36 @@ import ( // The Soundex encoding. It is a phonetic algorithm that considers how the words sound in English. Soundex maps a string to a 4-byte code consisting of the first letter of the original string and three numbers. Strings that sound similar should map to the same code. func Soundex(s string) string { - b := strings.Builder{} - b.Grow(4) - - p := s[0] - if p <= 'z' && p >= 'a' { - p -= 32 // convert to uppercase + m := map[byte]string{ + 'B': "1", 'P': "1", 'F': "1", 'V': "1", + 'C': "2", 'S': "2", 'K': "2", 'G': "2", 'J': "2", 'Q': "2", 'X': "2", 'Z': "2", + 'D': "3", 'T': "3", + 'L': "4", + 'M': "5", 'N': "5", + 'R': "6", } - b.WriteByte(p) - n := 0 - for i := 1; i < len(s); i++ { - c := s[i] + s = strings.ToUpper(s) - if c <= 'z' && c >= 'a' { - c -= 32 // convert to uppercase - } else if c < 'A' || c > 'Z' { - continue - } + r := string(s[0]) + p := s[0] + for i := 1; i < len(s) && len(r) < 4; i++ { + c := s[i] - if c == p { + if (c < 'A' || c > 'Z') || (c == p) { continue } p = c - switch c { - case 'B', 'P', 'F', 'V': - c = '1' - case 'C', 'S', 'K', 'G', 'J', 'Q', 'X', 'Z': - c = '2' - case 'D', 'T': - c = '3' - case 'L': - c = '4' - case 'M', 'N': - c = '5' - case 'R': - c = '6' - default: - continue - } - - b.WriteByte(c) - n++ - if n == 3 { - break + if n, ok := m[c]; ok { + r += n } } - for i := n; i < 3; i++ { - b.WriteByte('0') + for i := len(r); i < 4; i++ { + r += "0" } - return b.String() + return r } diff --git a/vendor/github.com/yusufpapurcu/wmi/README.md b/vendor/github.com/yusufpapurcu/wmi/README.md deleted file mode 100644 index 426d1a46..00000000 --- a/vendor/github.com/yusufpapurcu/wmi/README.md +++ /dev/null @@ -1,6 +0,0 @@ -wmi -=== - -Package wmi provides a WQL interface to Windows WMI. - -Note: It interfaces with WMI on the local machine, therefore it only runs on Windows. diff --git a/vendor/go.opentelemetry.io/otel/.codespellignore b/vendor/go.opentelemetry.io/otel/.codespellignore index 6bf3abc4..ae6a3bcf 100644 --- a/vendor/go.opentelemetry.io/otel/.codespellignore +++ b/vendor/go.opentelemetry.io/otel/.codespellignore @@ -3,7 +3,3 @@ fo te collison consequentially -ans -nam -valu -thirdparty diff --git a/vendor/go.opentelemetry.io/otel/.codespellrc b/vendor/go.opentelemetry.io/otel/.codespellrc index e2cb3ea9..4afbb1fb 100644 --- a/vendor/go.opentelemetry.io/otel/.codespellrc +++ b/vendor/go.opentelemetry.io/otel/.codespellrc @@ -5,6 +5,6 @@ check-filenames = check-hidden = ignore-words = .codespellignore interactive = 1 -skip = .git,go.mod,go.sum,go.work,go.work.sum,semconv,venv,.tools +skip = .git,go.mod,go.sum,semconv,venv,.tools uri-ignore-words-list = * write = diff --git a/vendor/go.opentelemetry.io/otel/.gitmodules b/vendor/go.opentelemetry.io/otel/.gitmodules new file mode 100644 index 00000000..38a1f569 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/.gitmodules @@ -0,0 +1,3 @@ +[submodule "opentelemetry-proto"] + path = exporters/otlp/internal/opentelemetry-proto + url = https://github.com/open-telemetry/opentelemetry-proto diff --git a/vendor/go.opentelemetry.io/otel/.golangci.yml b/vendor/go.opentelemetry.io/otel/.golangci.yml index 6d9c8b64..a62511f3 100644 --- a/vendor/go.opentelemetry.io/otel/.golangci.yml +++ b/vendor/go.opentelemetry.io/otel/.golangci.yml @@ -11,7 +11,6 @@ linters: enable: - depguard - errcheck - - errorlint - godot - gofumpt - goimports @@ -22,11 +21,8 @@ linters: - misspell - revive - staticcheck - - tenv - typecheck - - unconvert - unused - - unparam issues: # Maximum issues count per one linter. @@ -128,8 +124,6 @@ linters-settings: - "**/example/**/*.go" - "**/trace/*.go" - "**/trace/**/*.go" - - "**/log/*.go" - - "**/log/**/*.go" deny: - pkg: "go.opentelemetry.io/otel/internal$" desc: Do not use cross-module internal packages. diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md index c01e6998..24874f85 100644 --- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md +++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md @@ -8,274 +8,6 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] -## [1.28.0/0.50.0/0.4.0] 2024-07-02 - -### Added - -- The `IsEmpty` method is added to the `Instrument` type in `go.opentelemetry.io/otel/sdk/metric`. - This method is used to check if an `Instrument` instance is a zero-value. (#5431) -- Store and provide the emitted `context.Context` in `ScopeRecords` of `go.opentelemetry.io/otel/sdk/log/logtest`. (#5468) -- The `go.opentelemetry.io/otel/semconv/v1.26.0` package. - The package contains semantic conventions from the `v1.26.0` version of the OpenTelemetry Semantic Conventions. (#5476) -- The `AssertRecordEqual` method to `go.opentelemetry.io/otel/log/logtest` to allow comparison of two log records in tests. (#5499) -- The `WithHeaders` option to `go.opentelemetry.io/otel/exporters/zipkin` to allow configuring custom http headers while exporting spans. (#5530) - -### Changed - -- `Tracer.Start` in `go.opentelemetry.io/otel/trace/noop` no longer allocates a span for empty span context. (#5457) -- Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/example/otel-collector`. (#5490) -- Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/example/zipkin`. (#5490) -- Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/exporters/zipkin`. (#5490) - - The exporter no longer exports the deprecated "otel.library.name" or "otel.library.version" attributes. -- Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/sdk/resource`. (#5490) -- Upgrade `go.opentelemetry.io/otel/semconv/v1.25.0` to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/otel/sdk/trace`. (#5490) -- `SimpleProcessor.OnEmit` in `go.opentelemetry.io/otel/sdk/log` no longer allocates a slice which makes it possible to have a zero-allocation log processing using `SimpleProcessor`. (#5493) -- Use non-generic functions in the `Start` method of `"go.opentelemetry.io/otel/sdk/trace".Trace` to reduce memory allocation. (#5497) -- `service.instance.id` is populated for a `Resource` created with `"go.opentelemetry.io/otel/sdk/resource".Default` with a default value when `OTEL_GO_X_RESOURCE` is set. (#5520) -- Improve performance of metric instruments in `go.opentelemetry.io/otel/sdk/metric` by removing unnecessary calls to `time.Now`. (#5545) - -### Fixed - -- Log a warning to the OpenTelemetry internal logger when a `Record` in `go.opentelemetry.io/otel/sdk/log` drops an attribute due to a limit being reached. (#5376) -- Identify the `Tracer` returned from the global `TracerProvider` in `go.opentelemetry.io/otel/global` with its schema URL. (#5426) -- Identify the `Meter` returned from the global `MeterProvider` in `go.opentelemetry.io/otel/global` with its schema URL. (#5426) -- Log a warning to the OpenTelemetry internal logger when a `Span` in `go.opentelemetry.io/otel/sdk/trace` drops an attribute, event, or link due to a limit being reached. (#5434) -- Document instrument name requirements in `go.opentelemetry.io/otel/metric`. (#5435) -- Prevent random number generation data-race for experimental rand exemplars in `go.opentelemetry.io/otel/sdk/metric`. (#5456) -- Fix counting number of dropped attributes of `Record` in `go.opentelemetry.io/otel/sdk/log`. (#5464) -- Fix panic in baggage creation when a member contains `0x80` char in key or value. (#5494) -- Correct comments for the priority of the `WithEndpoint` and `WithEndpointURL` options and their corresponding environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#5508) -- Retry trace and span ID generation if it generated an invalid one in `go.opentelemetry.io/otel/sdk/trace`. (#5514) -- Fix stale timestamps reported by the last-value aggregation. (#5517) -- Indicate the `Exporter` in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` must be created by the `New` method. (#5521) -- Improved performance in all `{Bool,Int64,Float64,String}SliceValue` functions of `go.opentelemetry.io/attributes` by reducing the number of allocations. (#5549) - -## [1.27.0/0.49.0/0.3.0] 2024-05-21 - -### Added - -- Add example for `go.opentelemetry.io/otel/exporters/stdout/stdoutlog`. (#5242) -- Add `RecordFactory` in `go.opentelemetry.io/otel/sdk/log/logtest` to facilitate testing exporter and processor implementations. (#5258) -- Add `RecordFactory` in `go.opentelemetry.io/otel/log/logtest` to facilitate testing bridge implementations. (#5263) -- The count of dropped records from the `BatchProcessor` in `go.opentelemetry.io/otel/sdk/log` is logged. (#5276) -- Add metrics in the `otel-collector` example. (#5283) -- Add the synchronous gauge instrument to `go.opentelemetry.io/otel/metric`. (#5304) - - An `int64` or `float64` synchronous gauge instrument can now be created from a `Meter`. - - All implementations of the API (`go.opentelemetry.io/otel/metric/noop`, `go.opentelemetry.io/otel/sdk/metric`) are updated to support this instrument. -- Add logs to `go.opentelemetry.io/otel/example/dice`. (#5349) - -### Changed - -- The `Shutdown` method of `Exporter` in `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` ignores the context cancellation and always returns `nil`. (#5189) -- The `ForceFlush` and `Shutdown` methods of the exporter returned by `New` in `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` ignore the context cancellation and always return `nil`. (#5189) -- Apply the value length limits to `Record` attributes in `go.opentelemetry.io/otel/sdk/log`. (#5230) -- De-duplicate map attributes added to a `Record` in `go.opentelemetry.io/otel/sdk/log`. (#5230) -- `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` won't print timestamps when `WithoutTimestamps` option is set. (#5241) -- The `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` exporter won't print `AttributeValueLengthLimit` and `AttributeCountLimit` fields now, instead it prints the `DroppedAttributes` field. (#5272) -- Improved performance in the `Stringer` implementation of `go.opentelemetry.io/otel/baggage.Member` by reducing the number of allocations. (#5286) -- Set the start time for last-value aggregates in `go.opentelemetry.io/otel/sdk/metric`. (#5305) -- The `Span` in `go.opentelemetry.io/otel/sdk/trace` will record links without span context if either non-empty `TraceState` or attributes are provided. (#5315) -- Upgrade all dependencies of `go.opentelemetry.io/otel/semconv/v1.24.0` to `go.opentelemetry.io/otel/semconv/v1.25.0`. (#5374) - -### Fixed - -- Comparison of unordered maps for `go.opentelemetry.io/otel/log.KeyValue` and `go.opentelemetry.io/otel/log.Value`. (#5306) -- Fix the empty output of `go.opentelemetry.io/otel/log.Value` in `go.opentelemetry.io/otel/exporters/stdout/stdoutlog`. (#5311) -- Split the behavior of `Recorder` in `go.opentelemetry.io/otel/log/logtest` so it behaves as a `LoggerProvider` only. (#5365) -- Fix wrong package name of the error message when parsing endpoint URL in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#5371) -- Identify the `Logger` returned from the global `LoggerProvider` in `go.opentelemetry.io/otel/log/global` with its schema URL. (#5375) - -## [1.26.0/0.48.0/0.2.0-alpha] 2024-04-24 - -### Added - -- Add `Recorder` in `go.opentelemetry.io/otel/log/logtest` to facilitate testing the log bridge implementations. (#5134) -- Add span flags to OTLP spans and links exported by `go.opentelemetry.io/otel/exporters/otlp/otlptrace`. (#5194) -- Make the initial alpha release of `go.opentelemetry.io/otel/sdk/log`. - This new module contains the Go implementation of the OpenTelemetry Logs SDK. - This module is unstable and breaking changes may be introduced. - See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. (#5240) -- Make the initial alpha release of `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. - This new module contains an OTLP exporter that transmits log telemetry using HTTP. - This module is unstable and breaking changes may be introduced. - See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. (#5240) -- Make the initial alpha release of `go.opentelemetry.io/otel/exporters/stdout/stdoutlog`. - This new module contains an exporter prints log records to STDOUT. - This module is unstable and breaking changes may be introduced. - See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. (#5240) -- The `go.opentelemetry.io/otel/semconv/v1.25.0` package. - The package contains semantic conventions from the `v1.25.0` version of the OpenTelemetry Semantic Conventions. (#5254) - -### Changed - -- Update `go.opentelemetry.io/proto/otlp` from v1.1.0 to v1.2.0. (#5177) -- Improve performance of baggage member character validation in `go.opentelemetry.io/otel/baggage`. (#5214) -- The `otel-collector` example now uses docker compose to bring up services instead of kubernetes. (#5244) - -### Fixed - -- Slice attribute values in `go.opentelemetry.io/otel/attribute` are now emitted as their JSON representation. (#5159) - -## [1.25.0/0.47.0/0.0.8/0.1.0-alpha] 2024-04-05 - -### Added - -- Add `WithProxy` option in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4906) -- Add `WithProxy` option in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlptracehttp`. (#4906) -- Add `AddLink` method to the `Span` interface in `go.opentelemetry.io/otel/trace`. (#5032) -- The `Enabled` method is added to the `Logger` interface in `go.opentelemetry.io/otel/log`. - This method is used to notify users if a log record will be emitted or not. (#5071) -- Add `SeverityUndefined` `const` to `go.opentelemetry.io/otel/log`. - This value represents an unset severity level. (#5072) -- Add `Empty` function in `go.opentelemetry.io/otel/log` to return a `KeyValue` for an empty value. (#5076) -- Add `go.opentelemetry.io/otel/log/global` to manage the global `LoggerProvider`. - This package is provided with the anticipation that all functionality will be migrate to `go.opentelemetry.io/otel` when `go.opentelemetry.io/otel/log` stabilizes. - At which point, users will be required to migrage their code, and this package will be deprecated then removed. (#5085) -- Add support for `Summary` metrics in the `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` exporters. (#5100) -- Add `otel.scope.name` and `otel.scope.version` tags to spans exported by `go.opentelemetry.io/otel/exporters/zipkin`. (#5108) -- Add support for `AddLink` to `go.opentelemetry.io/otel/bridge/opencensus`. (#5116) -- Add `String` method to `Value` and `KeyValue` in `go.opentelemetry.io/otel/log`. (#5117) -- Add Exemplar support to `go.opentelemetry.io/otel/exporters/prometheus`. (#5111) -- Add metric semantic conventions to `go.opentelemetry.io/otel/semconv/v1.24.0`. Future `semconv` packages will include metric semantic conventions as well. (#4528) - -### Changed - -- `SpanFromContext` and `SpanContextFromContext` in `go.opentelemetry.io/otel/trace` no longer make a heap allocation when the passed context has no span. (#5049) -- `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` now create a gRPC client in idle mode and with "dns" as the default resolver using [`grpc.NewClient`](https://pkg.go.dev/google.golang.org/grpc#NewClient). (#5151) - Because of that `WithDialOption` ignores [`grpc.WithBlock`](https://pkg.go.dev/google.golang.org/grpc#WithBlock), [`grpc.WithTimeout`](https://pkg.go.dev/google.golang.org/grpc#WithTimeout), and [`grpc.WithReturnConnectionError`](https://pkg.go.dev/google.golang.org/grpc#WithReturnConnectionError). - Notice that [`grpc.DialContext`](https://pkg.go.dev/google.golang.org/grpc#DialContext) which was used before is now deprecated. - -### Fixed - -- Clarify the documentation about equivalence guarantees for the `Set` and `Distinct` types in `go.opentelemetry.io/otel/attribute`. (#5027) -- Prevent default `ErrorHandler` self-delegation. (#5137) -- Update all dependencies to address [GO-2024-2687]. (#5139) - -### Removed - -- Drop support for [Go 1.20]. (#4967) - -### Deprecated - -- Deprecate `go.opentelemetry.io/otel/attribute.Sortable` type. (#4734) -- Deprecate `go.opentelemetry.io/otel/attribute.NewSetWithSortable` function. (#4734) -- Deprecate `go.opentelemetry.io/otel/attribute.NewSetWithSortableFiltered` function. (#4734) - -## [1.24.0/0.46.0/0.0.1-alpha] 2024-02-23 - -This release is the last to support [Go 1.20]. -The next release will require at least [Go 1.21]. - -### Added - -- Support [Go 1.22]. (#4890) -- Add exemplar support to `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4900) -- Add exemplar support to `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4900) -- The `go.opentelemetry.io/otel/log` module is added. - This module includes OpenTelemetry Go's implementation of the Logs Bridge API. - This module is in an alpha state, it is subject to breaking changes. - See our [versioning policy](./VERSIONING.md) for more info. (#4961) -- ARM64 platform to the compatibility testing suite. (#4994) - -### Fixed - -- Fix registration of multiple callbacks when using the global meter provider from `go.opentelemetry.io/otel`. (#4945) -- Fix negative buckets in output of exponential histograms. (#4956) - -## [1.23.1] 2024-02-07 - -### Fixed - -- Register all callbacks passed during observable instrument creation instead of just the last one multiple times in `go.opentelemetry.io/otel/sdk/metric`. (#4888) - -## [1.23.0] 2024-02-06 - -This release contains the first stable, `v1`, release of the following modules: - -- `go.opentelemetry.io/otel/bridge/opencensus` -- `go.opentelemetry.io/otel/bridge/opencensus/test` -- `go.opentelemetry.io/otel/example/opencensus` -- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` -- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` -- `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` - -See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. - -### Added - -- Add `WithEndpointURL` option to the `exporters/otlp/otlpmetric/otlpmetricgrpc`, `exporters/otlp/otlpmetric/otlpmetrichttp`, `exporters/otlp/otlptrace/otlptracegrpc` and `exporters/otlp/otlptrace/otlptracehttp` packages. (#4808) -- Experimental exemplar exporting is added to the metric SDK. - See [metric documentation](./sdk/metric/internal/x/README.md#exemplars) for more information about this feature and how to enable it. (#4871) -- `ErrSchemaURLConflict` is added to `go.opentelemetry.io/otel/sdk/resource`. - This error is returned when a merge of two `Resource`s with different (non-empty) schema URL is attempted. (#4876) - -### Changed - -- The `Merge` and `New` functions in `go.opentelemetry.io/otel/sdk/resource` now returns a partial result if there is a schema URL merge conflict. - Instead of returning `nil` when two `Resource`s with different (non-empty) schema URLs are merged the merged `Resource`, along with the new `ErrSchemaURLConflict` error, is returned. - It is up to the user to decide if they want to use the returned `Resource` or not. - It may have desired attributes overwritten or include stale semantic conventions. (#4876) - -### Fixed - -- Fix `ContainerID` resource detection on systemd when cgroup path has a colon. (#4449) -- Fix `go.opentelemetry.io/otel/sdk/metric` to cache instruments to avoid leaking memory when the same instrument is created multiple times. (#4820) -- Fix missing `Mix` and `Max` values for `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` by introducing `MarshalText` and `MarshalJSON` for the `Extrema` type in `go.opentelemetry.io/sdk/metric/metricdata`. (#4827) - -## [1.23.0-rc.1] 2024-01-18 - -This is a release candidate for the v1.23.0 release. -That release is expected to include the `v1` release of the following modules: - -- `go.opentelemetry.io/otel/bridge/opencensus` -- `go.opentelemetry.io/otel/bridge/opencensus/test` -- `go.opentelemetry.io/otel/example/opencensus` -- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` -- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` -- `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` - -See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. - -## [1.22.0/0.45.0] 2024-01-17 - -### Added - -- The `go.opentelemetry.io/otel/semconv/v1.22.0` package. - The package contains semantic conventions from the `v1.22.0` version of the OpenTelemetry Semantic Conventions. (#4735) -- The `go.opentelemetry.io/otel/semconv/v1.23.0` package. - The package contains semantic conventions from the `v1.23.0` version of the OpenTelemetry Semantic Conventions. (#4746) -- The `go.opentelemetry.io/otel/semconv/v1.23.1` package. - The package contains semantic conventions from the `v1.23.1` version of the OpenTelemetry Semantic Conventions. (#4749) -- The `go.opentelemetry.io/otel/semconv/v1.24.0` package. - The package contains semantic conventions from the `v1.24.0` version of the OpenTelemetry Semantic Conventions. (#4770) -- Add `WithResourceAsConstantLabels` option to apply resource attributes for every metric emitted by the Prometheus exporter. (#4733) -- Experimental cardinality limiting is added to the metric SDK. - See [metric documentation](./sdk/metric/internal/x/README.md#cardinality-limit) for more information about this feature and how to enable it. (#4457) -- Add `NewMemberRaw` and `NewKeyValuePropertyRaw` in `go.opentelemetry.io/otel/baggage`. (#4804) - -### Changed - -- Upgrade all use of `go.opentelemetry.io/otel/semconv` to use `v1.24.0`. (#4754) -- Update transformations in `go.opentelemetry.io/otel/exporters/zipkin` to follow `v1.24.0` version of the OpenTelemetry specification. (#4754) -- Record synchronous measurements when the passed context is canceled instead of dropping in `go.opentelemetry.io/otel/sdk/metric`. - If you do not want to make a measurement when the context is cancelled, you need to handle it yourself (e.g `if ctx.Err() != nil`). (#4671) -- Improve `go.opentelemetry.io/otel/trace.TraceState`'s performance. (#4722) -- Improve `go.opentelemetry.io/otel/propagation.TraceContext`'s performance. (#4721) -- Improve `go.opentelemetry.io/otel/baggage` performance. (#4743) -- Improve performance of the `(*Set).Filter` method in `go.opentelemetry.io/otel/attribute` when the passed filter does not filter out any attributes from the set. (#4774) -- `Member.String` in `go.opentelemetry.io/otel/baggage` percent-encodes only when necessary. (#4775) -- Improve `go.opentelemetry.io/otel/trace.Span`'s performance when adding multiple attributes. (#4818) -- `Property.Value` in `go.opentelemetry.io/otel/baggage` now returns a raw string instead of a percent-encoded value. (#4804) - -### Fixed - -- Fix `Parse` in `go.opentelemetry.io/otel/baggage` to validate member value before percent-decoding. (#4755) -- Fix whitespace encoding of `Member.String` in `go.opentelemetry.io/otel/baggage`. (#4756) -- Fix observable not registered error when the asynchronous instrument has a drop aggregation in `go.opentelemetry.io/otel/sdk/metric`. (#4772) -- Fix baggage item key so that it is not canonicalized in `go.opentelemetry.io/otel/bridge/opentracing`. (#4776) -- Fix `go.opentelemetry.io/otel/bridge/opentracing` to properly handle baggage values that requires escaping during propagation. (#4804) -- Fix a bug where using multiple readers resulted in incorrect asynchronous counter values in `go.opentelemetry.io/otel/sdk/metric`. (#4742) - ## [1.21.0/0.44.0] 2023-11-16 ### Removed @@ -292,7 +24,7 @@ See our [versioning policy](VERSIONING.md) for more information about these stab ## [1.20.0/0.43.0] 2023-11-10 -This release brings a breaking change for custom trace API implementations. Some interfaces (`TracerProvider`, `Tracer`, `Span`) now embed the `go.opentelemetry.io/otel/trace/embedded` types. Implementers need to update their implementations based on what they want the default behavior to be. See the "API Implementations" section of the [trace API] package documentation for more information about how to accomplish this. +This release brings a breaking change for custom trace API implementations. Some interfaces (`TracerProvider`, `Tracer`, `Span`) now embed the `go.opentelemetry.io/otel/trace/embedded` types. Implementors need to update their implementations based on what they want the default behavior to be. See the "API Implementations" section of the [trace API] package documentation for more information about how to accomplish this. ### Added @@ -324,15 +56,15 @@ This release brings a breaking change for custom trace API implementations. Some - `go.opentelemetry.io/otel/bridge/opencensus.NewMetricProducer` returns a `*MetricProducer` struct instead of the metric.Producer interface. (#4583) - The `TracerProvider` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.TracerProvider` type. This extends the `TracerProvider` interface and is is a breaking change for any existing implementation. - Implementers need to update their implementations based on what they want the default behavior of the interface to be. + Implementors need to update their implementations based on what they want the default behavior of the interface to be. See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more information about how to accomplish this. (#4620) - The `Tracer` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.Tracer` type. This extends the `Tracer` interface and is is a breaking change for any existing implementation. - Implementers need to update their implementations based on what they want the default behavior of the interface to be. + Implementors need to update their implementations based on what they want the default behavior of the interface to be. See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more information about how to accomplish this. (#4620) - The `Span` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.Span` type. This extends the `Span` interface and is is a breaking change for any existing implementation. - Implementers need to update their implementations based on what they want the default behavior of the interface to be. + Implementors need to update their implementations based on what they want the default behavior of the interface to be. See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more information about how to accomplish this. (#4620) - `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` does no longer depend on `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4660) - `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` does no longer depend on `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4660) @@ -968,7 +700,7 @@ The next release will require at least [Go 1.19]. - Exported `Status` codes in the `go.opentelemetry.io/otel/exporters/zipkin` exporter are now exported as all upper case values. (#3340) - `Aggregation`s from `go.opentelemetry.io/otel/sdk/metric` with no data are not exported. (#3394, #3436) - Re-enabled Attribute Filters in the Metric SDK. (#3396) -- Asynchronous callbacks are only called if they are registered with at least one instrument that does not use drop aggregation. (#3408) +- Asynchronous callbacks are only called if they are registered with at least one instrument that does not use drop aggragation. (#3408) - Do not report empty partial-success responses in the `go.opentelemetry.io/otel/exporters/otlp` exporters. (#3438, #3432) - Handle partial success responses in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` exporters. (#3162, #3440) - Prevent duplicate Prometheus description, unit, and type. (#3469) @@ -2013,7 +1745,7 @@ with major version 0. - `NewExporter` from `exporters/otlp` now takes a `ProtocolDriver` as a parameter. (#1369) - Many OTLP Exporter options became gRPC ProtocolDriver options. (#1369) - Unify endpoint API that related to OTel exporter. (#1401) -- Optimize metric histogram aggregator to reuse its slice of buckets. (#1435) +- Optimize metric histogram aggregator to re-use its slice of buckets. (#1435) - Metric aggregator Count() and histogram Bucket.Counts are consistently `uint64`. (1430) - Histogram aggregator accepts functional options, uses default boundaries if none given. (#1434) - `SamplingResult` now passed a `Tracestate` from the parent `SpanContext` (#1432) @@ -3003,16 +2735,7 @@ It contains api and sdk for trace and meter. - CircleCI build CI manifest files. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.28.0...HEAD -[1.28.0/0.50.0/0.4.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.28.0 -[1.27.0/0.49.0/0.3.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.27.0 -[1.26.0/0.48.0/0.2.0-alpha]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.26.0 -[1.25.0/0.47.0/0.0.8/0.1.0-alpha]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.25.0 -[1.24.0/0.46.0/0.0.1-alpha]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.24.0 -[1.23.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.23.1 -[1.23.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.23.0 -[1.23.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.23.0-rc.1 -[1.22.0/0.45.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.22.0 +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.21.0...HEAD [1.21.0/0.44.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.21.0 [1.20.0/0.43.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.20.0 [1.19.0/0.42.0/0.0.7]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0 @@ -3086,8 +2809,6 @@ It contains api and sdk for trace and meter. [0.1.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.1 [0.1.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.0 -[Go 1.22]: https://go.dev/doc/go1.22 -[Go 1.21]: https://go.dev/doc/go1.21 [Go 1.20]: https://go.dev/doc/go1.20 [Go 1.19]: https://go.dev/doc/go1.19 [Go 1.18]: https://go.dev/doc/go1.18 @@ -3095,5 +2816,3 @@ It contains api and sdk for trace and meter. [metric API]:https://pkg.go.dev/go.opentelemetry.io/otel/metric [metric SDK]:https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric [trace API]:https://pkg.go.dev/go.opentelemetry.io/otel/trace - -[GO-2024-2687]: https://pkg.go.dev/vuln/GO-2024-2687 diff --git a/vendor/go.opentelemetry.io/otel/CODEOWNERS b/vendor/go.opentelemetry.io/otel/CODEOWNERS index 20255493..62374000 100644 --- a/vendor/go.opentelemetry.io/otel/CODEOWNERS +++ b/vendor/go.opentelemetry.io/otel/CODEOWNERS @@ -12,6 +12,6 @@ # https://help.github.com/en/articles/about-code-owners # -* @MrAlias @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu +* @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu -CODEOWNERS @MrAlias @MadVikingGod @pellared @dashpole @XSAM @dmathieu +CODEOWNERS @MrAlias @MadVikingGod @pellared \ No newline at end of file diff --git a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md index b86572f5..850606ae 100644 --- a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md +++ b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md @@ -201,16 +201,6 @@ You can install and run a "local Go Doc site" in the following way: [`go.opentelemetry.io/otel/metric`](https://pkg.go.dev/go.opentelemetry.io/otel/metric) is an example of a very well-documented package. -### README files - -Each (non-internal, non-test, non-documentation) package must contain a -`README.md` file containing at least a title, and a `pkg.go.dev` badge. - -The README should not be a repetition of Go doc comments. - -You can verify the presence of all README files with the `make verify-readmes` -command. - ## Style Guide One of the primary goals of this project is that it is actually used by @@ -570,9 +560,6 @@ functionality should be added, each one will need their own super-set interfaces and will duplicate the pattern. For this reason, the simple targeted interface that defines the specific functionality should be preferred. -See also: -[Keeping Your Modules Compatible: Working with interfaces](https://go.dev/blog/module-compatibility#working-with-interfaces). - ### Testing The tests should never leak goroutines. @@ -604,48 +591,27 @@ this. [^3]: https://github.com/open-telemetry/opentelemetry-go/issues/3548 -### Ignoring context cancellation - -OpenTelemetry API implementations need to ignore the cancellation of the context that are -passed when recording a value (e.g. starting a span, recording a measurement, emitting a log). -Recording methods should not return an error describing the cancellation state of the context -when they complete, nor should they abort any work. - -This rule may not apply if the OpenTelemetry specification defines a timeout mechanism for -the method. In that case the context cancellation can be used for the timeout with the -restriction that this behavior is documented for the method. Otherwise, timeouts -are expected to be handled by the user calling the API, not the implementation. - -Stoppage of the telemetry pipeline is handled by calling the appropriate `Shutdown` method -of a provider. It is assumed the context passed from a user is not used for this purpose. - -Outside of the direct recording of telemetry from the API (e.g. exporting telemetry, -force flushing telemetry, shutting down a signal provider) the context cancellation -should be honored. This means all work done on behalf of the user provided context -should be canceled. - ## Approvers and Maintainers ### Approvers +- [Evan Torrie](https://github.com/evantorrie), Verizon Media +- [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics +- [David Ashpole](https://github.com/dashpole), Google - [Chester Cheung](https://github.com/hanyuancheung), Tencent +- [Damien Mathieu](https://github.com/dmathieu), Elastic +- [Anthony Mirabella](https://github.com/Aneurysm9), AWS ### Maintainers - [Aaron Clawson](https://github.com/MadVikingGod), LightStep -- [Damien Mathieu](https://github.com/dmathieu), Elastic -- [David Ashpole](https://github.com/dashpole), Google - [Robert Pająk](https://github.com/pellared), Splunk -- [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics - [Tyler Yahn](https://github.com/MrAlias), Splunk ### Emeritus -- [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb - [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep - [Josh MacDonald](https://github.com/jmacd), LightStep -- [Anthony Mirabella](https://github.com/Aneurysm9), AWS -- [Evan Torrie](https://github.com/evantorrie), Yahoo ### Become an Approver or a Maintainer diff --git a/vendor/go.opentelemetry.io/otel/Makefile b/vendor/go.opentelemetry.io/otel/Makefile index f33619f7..35fc1899 100644 --- a/vendor/go.opentelemetry.io/otel/Makefile +++ b/vendor/go.opentelemetry.io/otel/Makefile @@ -1,5 +1,16 @@ # Copyright The OpenTelemetry Authors -# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. TOOLS_MOD_DIR := ./internal/tools @@ -14,8 +25,8 @@ TIMEOUT = 60 .DEFAULT_GOAL := precommit .PHONY: precommit ci -precommit: generate license-check misspell go-mod-tidy golangci-lint-fix verify-readmes verify-mods test-default -ci: generate license-check lint vanity-import-check verify-readmes verify-mods build test-default check-clean-work-tree test-coverage +precommit: generate dependabot-generate license-check misspell go-mod-tidy golangci-lint-fix test-default +ci: generate dependabot-check license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage # Tools @@ -23,7 +34,7 @@ TOOLS = $(CURDIR)/.tools $(TOOLS): @mkdir -p $@ -$(TOOLS)/%: $(TOOLS_MOD_DIR)/go.mod | $(TOOLS) +$(TOOLS)/%: | $(TOOLS) cd $(TOOLS_MOD_DIR) && \ $(GO) build -o $@ $(PACKAGE) @@ -39,6 +50,9 @@ $(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink SEMCONVKIT = $(TOOLS)/semconvkit $(TOOLS)/semconvkit: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/semconvkit +DBOTCONF = $(TOOLS)/dbotconf +$(TOOLS)/dbotconf: PACKAGE=go.opentelemetry.io/build-tools/dbotconf + GOLANGCI_LINT = $(TOOLS)/golangci-lint $(TOOLS)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint @@ -67,7 +81,7 @@ GOVULNCHECK = $(TOOLS)/govulncheck $(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck .PHONY: tools -tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) +tools: $(CROSSLINK) $(DBOTCONF) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) # Virtualized python tools via docker @@ -96,7 +110,7 @@ $(PYTOOLS): @$(DOCKERPY) bash -c "python3 -m venv $(VENVDIR) && $(PIP) install --upgrade pip" # Install python packages into the virtual environment. -$(PYTOOLS)/%: $(PYTOOLS) +$(PYTOOLS)/%: | $(PYTOOLS) @$(DOCKERPY) $(PIP) install -r requirements.txt CODESPELL = $(PYTOOLS)/codespell @@ -110,18 +124,18 @@ generate: go-generate vanity-import-fix .PHONY: go-generate go-generate: $(OTEL_GO_MOD_DIRS:%=go-generate/%) go-generate/%: DIR=$* -go-generate/%: $(STRINGER) $(GOTMPL) +go-generate/%: | $(STRINGER) $(GOTMPL) @echo "$(GO) generate $(DIR)/..." \ && cd $(DIR) \ && PATH="$(TOOLS):$${PATH}" $(GO) generate ./... .PHONY: vanity-import-fix -vanity-import-fix: $(PORTO) +vanity-import-fix: | $(PORTO) @$(PORTO) --include-internal -w . # Generate go.work file for local development. .PHONY: go-work -go-work: $(CROSSLINK) +go-work: | $(CROSSLINK) $(CROSSLINK) work --root=$(shell pwd) # Build @@ -164,7 +178,7 @@ test/%: COVERAGE_MODE = atomic COVERAGE_PROFILE = coverage.out .PHONY: test-coverage -test-coverage: $(GOCOVMERGE) +test-coverage: | $(GOCOVMERGE) @set -e; \ printf "" > coverage.txt; \ for dir in $(ALL_COVERAGE_MOD_DIRS); do \ @@ -178,7 +192,7 @@ test-coverage: $(GOCOVMERGE) done; \ $(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt -# Adding a directory will include all benchmarks in that directory if a filter is not specified. +# Adding a directory will include all benchmarks in that direcotry if a filter is not specified. BENCHMARK_TARGETS := sdk/trace .PHONY: benchmark benchmark: $(BENCHMARK_TARGETS:%=benchmark/%) @@ -195,23 +209,23 @@ golangci-lint-fix: ARGS=--fix golangci-lint-fix: golangci-lint golangci-lint: $(OTEL_GO_MOD_DIRS:%=golangci-lint/%) golangci-lint/%: DIR=$* -golangci-lint/%: $(GOLANGCI_LINT) +golangci-lint/%: | $(GOLANGCI_LINT) @echo 'golangci-lint $(if $(ARGS),$(ARGS) ,)$(DIR)' \ && cd $(DIR) \ && $(GOLANGCI_LINT) run --allow-serial-runners $(ARGS) .PHONY: crosslink -crosslink: $(CROSSLINK) +crosslink: | $(CROSSLINK) @echo "Updating intra-repository dependencies in all go modules" \ && $(CROSSLINK) --root=$(shell pwd) --prune .PHONY: go-mod-tidy go-mod-tidy: $(ALL_GO_MOD_DIRS:%=go-mod-tidy/%) go-mod-tidy/%: DIR=$* -go-mod-tidy/%: crosslink +go-mod-tidy/%: | crosslink @echo "$(GO) mod tidy in $(DIR)" \ && cd $(DIR) \ - && $(GO) mod tidy -compat=1.21 + && $(GO) mod tidy -compat=1.20 .PHONY: lint-modules lint-modules: go-mod-tidy @@ -220,23 +234,23 @@ lint-modules: go-mod-tidy lint: misspell lint-modules golangci-lint govulncheck .PHONY: vanity-import-check -vanity-import-check: $(PORTO) +vanity-import-check: | $(PORTO) @$(PORTO) --include-internal -l . || ( echo "(run: make vanity-import-fix)"; exit 1 ) .PHONY: misspell -misspell: $(MISSPELL) +misspell: | $(MISSPELL) @$(MISSPELL) -w $(ALL_DOCS) .PHONY: govulncheck govulncheck: $(OTEL_GO_MOD_DIRS:%=govulncheck/%) govulncheck/%: DIR=$* -govulncheck/%: $(GOVULNCHECK) +govulncheck/%: | $(GOVULNCHECK) @echo "govulncheck ./... in $(DIR)" \ && cd $(DIR) \ && $(GOVULNCHECK) ./... .PHONY: codespell -codespell: $(CODESPELL) +codespell: | $(CODESPELL) @$(DOCKERPY) $(CODESPELL) .PHONY: license-check @@ -249,6 +263,15 @@ license-check: exit 1; \ fi +DEPENDABOT_CONFIG = .github/dependabot.yml +.PHONY: dependabot-check +dependabot-check: | $(DBOTCONF) + @$(DBOTCONF) verify $(DEPENDABOT_CONFIG) || ( echo "(run: make dependabot-generate)"; exit 1 ) + +.PHONY: dependabot-generate +dependabot-generate: | $(DBOTCONF) + @$(DBOTCONF) generate > $(DEPENDABOT_CONFIG) + .PHONY: check-clean-work-tree check-clean-work-tree: @if ! git diff --quiet; then \ @@ -261,11 +284,13 @@ check-clean-work-tree: SEMCONVPKG ?= "semconv/" .PHONY: semconv-generate -semconv-generate: $(SEMCONVGEN) $(SEMCONVKIT) +semconv-generate: | $(SEMCONVGEN) $(SEMCONVKIT) [ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 ) [ "$(OTEL_SEMCONV_REPO)" ] || ( echo "OTEL_SEMCONV_REPO unset: missing path to opentelemetry semantic-conventions repo"; exit 1 ) + $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=span -p conventionType=trace -f trace.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" - $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=metric -f metric.go -t "$(SEMCONVPKG)/metric_template.j2" -s "$(TAG)" + $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=event -p conventionType=event -f event.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" + $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=resource -p conventionType=resource -f resource.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" $(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)" .PHONY: gorelease @@ -277,25 +302,17 @@ gorelease/%:| $(GORELEASE) && $(GORELEASE) \ || echo "" -.PHONY: verify-mods -verify-mods: $(MULTIMOD) - $(MULTIMOD) verify - .PHONY: prerelease -prerelease: verify-mods +prerelease: | $(MULTIMOD) @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) - $(MULTIMOD) prerelease -m ${MODSET} + $(MULTIMOD) verify && $(MULTIMOD) prerelease -m ${MODSET} COMMIT ?= "HEAD" .PHONY: add-tags -add-tags: verify-mods +add-tags: | $(MULTIMOD) @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) - $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT} + $(MULTIMOD) verify && $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT} .PHONY: lint-markdown -lint-markdown: - docker run -v "$(CURDIR):$(WORKDIR)" avtodev/markdown-lint:v1 -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md - -.PHONY: verify-readmes -verify-readmes: - ./verify_readmes.sh +lint-markdown: + docker run -v "$(CURDIR):$(WORKDIR)" docker://avtodev/markdown-lint:v1 -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md diff --git a/vendor/go.opentelemetry.io/otel/README.md b/vendor/go.opentelemetry.io/otel/README.md index 5a890931..2c5b0cc2 100644 --- a/vendor/go.opentelemetry.io/otel/README.md +++ b/vendor/go.opentelemetry.io/otel/README.md @@ -11,11 +11,14 @@ It provides a set of APIs to directly measure performance and behavior of your s ## Project Status -| Signal | Status | -|---------|--------------------| -| Traces | Stable | -| Metrics | Stable | -| Logs | Beta[^1] | +| Signal | Status | +|---------|------------| +| Traces | Stable | +| Metrics | Stable | +| Logs | Design [1] | + +- [1]: Currently the logs signal development is in a design phase ([#4696](https://github.com/open-telemetry/opentelemetry-go/issues/4696)). + No Logs Pull Requests are currently being accepted. Progress and status specific to this repository is tracked in our [project boards](https://github.com/open-telemetry/opentelemetry-go/projects) @@ -25,8 +28,6 @@ and Project versioning information and stability guarantees can be found in the [versioning documentation](VERSIONING.md). -[^1]: https://github.com/orgs/open-telemetry/projects/43 - ### Compatibility OpenTelemetry-Go ensures compatibility with the current supported versions of @@ -49,25 +50,23 @@ Currently, this project supports the following environments. | OS | Go Version | Architecture | |---------|------------|--------------| -| Ubuntu | 1.22 | amd64 | | Ubuntu | 1.21 | amd64 | -| Ubuntu | 1.22 | 386 | +| Ubuntu | 1.20 | amd64 | | Ubuntu | 1.21 | 386 | -| Linux | 1.22 | arm64 | -| Linux | 1.21 | arm64 | -| MacOS | 1.22 | amd64 | +| Ubuntu | 1.20 | 386 | | MacOS | 1.21 | amd64 | -| Windows | 1.22 | amd64 | +| MacOS | 1.20 | amd64 | | Windows | 1.21 | amd64 | -| Windows | 1.22 | 386 | +| Windows | 1.20 | amd64 | | Windows | 1.21 | 386 | +| Windows | 1.20 | 386 | While this project should work for other systems, no compatibility guarantees are made for those systems currently. ## Getting Started -You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/languages/go/getting-started/). +You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/go/getting-started/). OpenTelemetry's goal is to provide a single set of APIs to capture distributed traces and metrics from your application and send them to an observability @@ -97,12 +96,12 @@ export pipeline to send that telemetry to an observability platform. All officially supported exporters for the OpenTelemetry project are contained in the [exporters directory](./exporters). -| Exporter | Logs | Metrics | Traces | -|---------------------------------------|:----:|:-------:|:------:| -| [OTLP](./exporters/otlp/) | ✓ | ✓ | ✓ | -| [Prometheus](./exporters/prometheus/) | | ✓ | | -| [stdout](./exporters/stdout/) | ✓ | ✓ | ✓ | -| [Zipkin](./exporters/zipkin/) | | | ✓ | +| Exporter | Metrics | Traces | +|---------------------------------------|:-------:|:------:| +| [OTLP](./exporters/otlp/) | ✓ | ✓ | +| [Prometheus](./exporters/prometheus/) | ✓ | | +| [stdout](./exporters/stdout/) | ✓ | ✓ | +| [Zipkin](./exporters/zipkin/) | | ✓ | ## Contributing diff --git a/vendor/go.opentelemetry.io/otel/RELEASING.md b/vendor/go.opentelemetry.io/otel/RELEASING.md index 940f57f3..82ce3ee4 100644 --- a/vendor/go.opentelemetry.io/otel/RELEASING.md +++ b/vendor/go.opentelemetry.io/otel/RELEASING.md @@ -27,12 +27,6 @@ You can run `make gorelease` that runs [gorelease](https://pkg.go.dev/golang.org You can check/report problems with `gorelease` [here](https://golang.org/issues/26420). -## Verify changes for contrib repository - -If the changes in the main repository are going to affect the contrib repository, it is important to verify that the changes are compatible with the contrib repository. - -Follow [the steps](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md#verify-otel-changes) in the contrib repository to verify OTel changes. - ## Pre-Release First, decide which module sets will be released and update their versions @@ -129,12 +123,12 @@ Once verified be sure to [make a release for the `contrib` repository](https://g ### Website Documentation -Update the [Go instrumentation documentation] in the OpenTelemetry website under [content/en/docs/languages/go]. +Update the [Go instrumentation documentation] in the OpenTelemetry website under [content/en/docs/instrumentation/go]. Importantly, bump any package versions referenced to be the latest one you just released and ensure all code examples still compile and are accurate. [OpenTelemetry Semantic Conventions]: https://github.com/open-telemetry/semantic-conventions -[Go instrumentation documentation]: https://opentelemetry.io/docs/languages/go/ -[content/en/docs/languages/go]: https://github.com/open-telemetry/opentelemetry.io/tree/main/content/en/docs/languages/go +[Go instrumentation documentation]: https://opentelemetry.io/docs/instrumentation/go/ +[content/en/docs/instrumentation/go]: https://github.com/open-telemetry/opentelemetry.io/tree/main/content/en/docs/instrumentation/go ### Demo Repository diff --git a/vendor/go.opentelemetry.io/otel/attribute/README.md b/vendor/go.opentelemetry.io/otel/attribute/README.md deleted file mode 100644 index 5b3da8f1..00000000 --- a/vendor/go.opentelemetry.io/otel/attribute/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Attribute - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/attribute)](https://pkg.go.dev/go.opentelemetry.io/otel/attribute) diff --git a/vendor/go.opentelemetry.io/otel/attribute/doc.go b/vendor/go.opentelemetry.io/otel/attribute/doc.go index eef51ebc..dafe7424 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/doc.go +++ b/vendor/go.opentelemetry.io/otel/attribute/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package attribute provides key and value attributes. package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/attribute/encoder.go b/vendor/go.opentelemetry.io/otel/attribute/encoder.go index 318e42fc..fe2bc576 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/encoder.go +++ b/vendor/go.opentelemetry.io/otel/attribute/encoder.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/attribute/filter.go b/vendor/go.opentelemetry.io/otel/attribute/filter.go index be9cd922..638c213d 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/filter.go +++ b/vendor/go.opentelemetry.io/otel/attribute/filter.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/attribute/iterator.go b/vendor/go.opentelemetry.io/otel/attribute/iterator.go index f2ba89ce..841b271f 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/iterator.go +++ b/vendor/go.opentelemetry.io/otel/attribute/iterator.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/attribute/key.go b/vendor/go.opentelemetry.io/otel/attribute/key.go index d9a22c65..0656a04e 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/key.go +++ b/vendor/go.opentelemetry.io/otel/attribute/key.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/attribute/kv.go b/vendor/go.opentelemetry.io/otel/attribute/kv.go index 3028f9a4..1ddf3ce0 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/kv.go +++ b/vendor/go.opentelemetry.io/otel/attribute/kv.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/attribute/set.go b/vendor/go.opentelemetry.io/otel/attribute/set.go index bff9c7fd..9f9303d4 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/set.go +++ b/vendor/go.opentelemetry.io/otel/attribute/set.go @@ -1,14 +1,24 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" import ( - "cmp" "encoding/json" "reflect" - "slices" "sort" + "sync" ) type ( @@ -16,33 +26,23 @@ type ( // immutable set of attributes, with an internal cache for storing // attribute encodings. // - // This type will remain comparable for backwards compatibility. The - // equivalence of Sets across versions is not guaranteed to be stable. - // Prior versions may find two Sets to be equal or not when compared - // directly (i.e. ==), but subsequent versions may not. Users should use - // the Equals method to ensure stable equivalence checking. - // - // Users should also use the Distinct returned from Equivalent as a map key - // instead of a Set directly. In addition to that type providing guarantees - // on stable equivalence, it may also provide performance improvements. + // This type supports the Equivalent method of comparison using values of + // type Distinct. Set struct { equivalent Distinct } - // Distinct is a unique identifier of a Set. - // - // Distinct is designed to be ensures equivalence stability: comparisons - // will return the save value across versions. For this reason, Distinct - // should always be used as a map key instead of a Set. + // Distinct wraps a variable-size array of KeyValue, constructed with keys + // in sorted order. This can be used as a map key or for equality checking + // between Sets. Distinct struct { iface interface{} } - // Sortable implements sort.Interface, used for sorting KeyValue. - // - // Deprecated: This type is no longer used. It was added as a performance - // optimization for Go < 1.21 that is no longer needed (Go < 1.21 is no - // longer supported by the module). + // Sortable implements sort.Interface, used for sorting KeyValue. This is + // an exported type to support a memory optimization. A pointer to one of + // these is needed for the call to sort.Stable(), which the caller may + // provide in order to avoid an allocation. See NewSetWithSortable(). Sortable []KeyValue ) @@ -56,6 +56,12 @@ var ( iface: [0]KeyValue{}, }, } + + // sortables is a pool of Sortables used to create Sets with a user does + // not provide one. + sortables = sync.Pool{ + New: func() interface{} { return new(Sortable) }, + } ) // EmptySet returns a reference to a Set with no elements. @@ -181,7 +187,13 @@ func empty() Set { // Except for empty sets, this method adds an additional allocation compared // with calls that include a Sortable. func NewSet(kvs ...KeyValue) Set { - s, _ := NewSetWithFiltered(kvs, nil) + // Check for empty set. + if len(kvs) == 0 { + return empty() + } + srt := sortables.Get().(*Sortable) + s, _ := NewSetWithSortableFiltered(kvs, srt, nil) + sortables.Put(srt) return s } @@ -189,10 +201,12 @@ func NewSet(kvs ...KeyValue) Set { // NewSetWithSortableFiltered for more details. // // This call includes a Sortable option as a memory optimization. -// -// Deprecated: Use [NewSet] instead. -func NewSetWithSortable(kvs []KeyValue, _ *Sortable) Set { - s, _ := NewSetWithFiltered(kvs, nil) +func NewSetWithSortable(kvs []KeyValue, tmp *Sortable) Set { + // Check for empty set. + if len(kvs) == 0 { + return empty() + } + s, _ := NewSetWithSortableFiltered(kvs, tmp, nil) return s } @@ -206,37 +220,10 @@ func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) { if len(kvs) == 0 { return empty(), nil } - - // Stable sort so the following de-duplication can implement - // last-value-wins semantics. - slices.SortStableFunc(kvs, func(a, b KeyValue) int { - return cmp.Compare(a.Key, b.Key) - }) - - position := len(kvs) - 1 - offset := position - 1 - - // The requirements stated above require that the stable - // result be placed in the end of the input slice, while - // overwritten values are swapped to the beginning. - // - // De-duplicate with last-value-wins semantics. Preserve - // duplicate values at the beginning of the input slice. - for ; offset >= 0; offset-- { - if kvs[offset].Key == kvs[position].Key { - continue - } - position-- - kvs[offset], kvs[position] = kvs[position], kvs[offset] - } - kvs = kvs[position:] - - if filter != nil { - if div := filteredToFront(kvs, filter); div != 0 { - return Set{equivalent: computeDistinct(kvs[div:])}, kvs[:div] - } - } - return Set{equivalent: computeDistinct(kvs)}, nil + srt := sortables.Get().(*Sortable) + s, filtered := NewSetWithSortableFiltered(kvs, srt, filter) + sortables.Put(srt) + return s, filtered } // NewSetWithSortableFiltered returns a new Set. @@ -262,71 +249,82 @@ func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) { // // The second []KeyValue return value is a list of attributes that were // excluded by the Filter (if non-nil). -// -// Deprecated: Use [NewSetWithFiltered] instead. -func NewSetWithSortableFiltered(kvs []KeyValue, _ *Sortable, filter Filter) (Set, []KeyValue) { - return NewSetWithFiltered(kvs, filter) -} +func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (Set, []KeyValue) { + // Check for empty set. + if len(kvs) == 0 { + return empty(), nil + } + + *tmp = kvs + + // Stable sort so the following de-duplication can implement + // last-value-wins semantics. + sort.Stable(tmp) + + *tmp = nil + + position := len(kvs) - 1 + offset := position - 1 -// filteredToFront filters slice in-place using keep function. All KeyValues that need to -// be removed are moved to the front. All KeyValues that need to be kept are -// moved (in-order) to the back. The index for the first KeyValue to be kept is -// returned. -func filteredToFront(slice []KeyValue, keep Filter) int { - n := len(slice) - j := n - for i := n - 1; i >= 0; i-- { - if keep(slice[i]) { - j-- - slice[i], slice[j] = slice[j], slice[i] + // The requirements stated above require that the stable + // result be placed in the end of the input slice, while + // overwritten values are swapped to the beginning. + // + // De-duplicate with last-value-wins semantics. Preserve + // duplicate values at the beginning of the input slice. + for ; offset >= 0; offset-- { + if kvs[offset].Key == kvs[position].Key { + continue } + position-- + kvs[offset], kvs[position] = kvs[position], kvs[offset] + } + if filter != nil { + return filterSet(kvs[position:], filter) } - return j + return Set{ + equivalent: computeDistinct(kvs[position:]), + }, nil } -// Filter returns a filtered copy of this Set. See the documentation for -// NewSetWithSortableFiltered for more details. -func (l *Set) Filter(re Filter) (Set, []KeyValue) { - if re == nil { - return *l, nil - } +// filterSet reorders kvs so that included keys are contiguous at the end of +// the slice, while excluded keys precede the included keys. +func filterSet(kvs []KeyValue, filter Filter) (Set, []KeyValue) { + var excluded []KeyValue - // Iterate in reverse to the first attribute that will be filtered out. - n := l.Len() - first := n - 1 - for ; first >= 0; first-- { - kv, _ := l.Get(first) - if !re(kv) { - break + // Move attributes that do not match the filter so they're adjacent before + // calling computeDistinct(). + distinctPosition := len(kvs) + + // Swap indistinct keys forward and distinct keys toward the + // end of the slice. + offset := len(kvs) - 1 + for ; offset >= 0; offset-- { + if filter(kvs[offset]) { + distinctPosition-- + kvs[offset], kvs[distinctPosition] = kvs[distinctPosition], kvs[offset] + continue } } + excluded = kvs[:distinctPosition] - // No attributes will be dropped, return the immutable Set l and nil. - if first < 0 { - return *l, nil - } + return Set{ + equivalent: computeDistinct(kvs[distinctPosition:]), + }, excluded +} - // Copy now that we know we need to return a modified set. - // - // Do not do this in-place on the underlying storage of *Set l. Sets are - // immutable and filtering should not change this. - slice := l.ToSlice() - - // Don't re-iterate the slice if only slice[0] is filtered. - if first == 0 { - // It is safe to assume len(slice) >= 1 given we found at least one - // attribute above that needs to be filtered out. - return Set{equivalent: computeDistinct(slice[1:])}, slice[:1] +// Filter returns a filtered copy of this Set. See the documentation for +// NewSetWithSortableFiltered for more details. +func (l *Set) Filter(re Filter) (Set, []KeyValue) { + if re == nil { + return Set{ + equivalent: l.equivalent, + }, nil } - // Move the filtered slice[first] to the front (preserving order). - kv := slice[first] - copy(slice[1:first+1], slice[:first]) - slice[0] = kv - - // Do not re-evaluate re(slice[first+1:]). - div := filteredToFront(slice[1:first+1], re) + 1 - return Set{equivalent: computeDistinct(slice[div:])}, slice[:div] + // Note: This could be refactored to avoid the temporary slice + // allocation, if it proves to be expensive. + return filterSet(l.ToSlice(), re) } // computeDistinct returns a Distinct using either the fixed- or @@ -406,7 +404,7 @@ func (l *Set) MarshalJSON() ([]byte, error) { return json.Marshal(l.equivalent.iface) } -// MarshalLog is the marshaling function used by the logging system to represent this Set. +// MarshalLog is the marshaling function used by the logging system to represent this exporter. func (l Set) MarshalLog() interface{} { kvs := make(map[string]string) for _, kv := range l.ToSlice() { diff --git a/vendor/go.opentelemetry.io/otel/attribute/value.go b/vendor/go.opentelemetry.io/otel/attribute/value.go index 9ea0ecbb..cb21dd5c 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/value.go +++ b/vendor/go.opentelemetry.io/otel/attribute/value.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package attribute // import "go.opentelemetry.io/otel/attribute" @@ -231,27 +242,15 @@ func (v Value) Emit() string { case BOOL: return strconv.FormatBool(v.AsBool()) case INT64SLICE: - j, err := json.Marshal(v.asInt64Slice()) - if err != nil { - return fmt.Sprintf("invalid: %v", v.asInt64Slice()) - } - return string(j) + return fmt.Sprint(v.asInt64Slice()) case INT64: return strconv.FormatInt(v.AsInt64(), 10) case FLOAT64SLICE: - j, err := json.Marshal(v.asFloat64Slice()) - if err != nil { - return fmt.Sprintf("invalid: %v", v.asFloat64Slice()) - } - return string(j) + return fmt.Sprint(v.asFloat64Slice()) case FLOAT64: return fmt.Sprint(v.AsFloat64()) case STRINGSLICE: - j, err := json.Marshal(v.asStringSlice()) - if err != nil { - return fmt.Sprintf("invalid: %v", v.asStringSlice()) - } - return string(j) + return fmt.Sprint(v.asStringSlice()) case STRING: return v.stringly default: diff --git a/vendor/go.opentelemetry.io/otel/baggage/README.md b/vendor/go.opentelemetry.io/otel/baggage/README.md deleted file mode 100644 index 7d798435..00000000 --- a/vendor/go.opentelemetry.io/otel/baggage/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Baggage - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/baggage)](https://pkg.go.dev/go.opentelemetry.io/otel/baggage) diff --git a/vendor/go.opentelemetry.io/otel/baggage/baggage.go b/vendor/go.opentelemetry.io/otel/baggage/baggage.go index c40c896c..84532cb1 100644 --- a/vendor/go.opentelemetry.io/otel/baggage/baggage.go +++ b/vendor/go.opentelemetry.io/otel/baggage/baggage.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package baggage // import "go.opentelemetry.io/otel/baggage" @@ -7,8 +18,8 @@ import ( "errors" "fmt" "net/url" + "regexp" "strings" - "unicode/utf8" "go.opentelemetry.io/otel/internal/baggage" ) @@ -21,6 +32,16 @@ const ( listDelimiter = "," keyValueDelimiter = "=" propertyDelimiter = ";" + + keyDef = `([\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5a\x5e-\x7a\x7c\x7e]+)` + valueDef = `([\x21\x23-\x2b\x2d-\x3a\x3c-\x5B\x5D-\x7e]*)` + keyValueDef = `\s*` + keyDef + `\s*` + keyValueDelimiter + `\s*` + valueDef + `\s*` +) + +var ( + keyRe = regexp.MustCompile(`^` + keyDef + `$`) + valueRe = regexp.MustCompile(`^` + valueDef + `$`) + propertyRe = regexp.MustCompile(`^(?:\s*` + keyDef + `\s*|` + keyValueDef + `)$`) ) var ( @@ -46,7 +67,7 @@ type Property struct { // // If key is invalid, an error will be returned. func NewKeyProperty(key string) (Property, error) { - if !validateKey(key) { + if !keyRe.MatchString(key) { return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) } @@ -56,29 +77,14 @@ func NewKeyProperty(key string) (Property, error) { // NewKeyValueProperty returns a new Property for key with value. // -// The passed key must be compliant with W3C Baggage specification. -// The passed value must be percent-encoded as defined in W3C Baggage specification. -// -// Notice: Consider using [NewKeyValuePropertyRaw] instead -// that does not require percent-encoding of the value. +// If key or value are invalid, an error will be returned. func NewKeyValueProperty(key, value string) (Property, error) { - if !validateValue(value) { - return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value) + if !keyRe.MatchString(key) { + return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) } - decodedValue, err := url.PathUnescape(value) - if err != nil { + if !valueRe.MatchString(value) { return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value) } - return NewKeyValuePropertyRaw(key, decodedValue) -} - -// NewKeyValuePropertyRaw returns a new Property for key with value. -// -// The passed key must be compliant with W3C Baggage specification. -func NewKeyValuePropertyRaw(key, value string) (Property, error) { - if !validateKey(key) { - return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) - } p := Property{ key: key, @@ -100,11 +106,20 @@ func parseProperty(property string) (Property, error) { return newInvalidProperty(), nil } - p, ok := parsePropertyInternal(property) - if !ok { + match := propertyRe.FindStringSubmatch(property) + if len(match) != 4 { return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidProperty, property) } + var p Property + if match[1] != "" { + p.key = match[1] + } else { + p.key = match[2] + p.value = match[3] + p.hasValue = true + } + return p, nil } @@ -115,9 +130,12 @@ func (p Property) validate() error { return fmt.Errorf("invalid property: %w", err) } - if !validateKey(p.key) { + if !keyRe.MatchString(p.key) { return errFunc(fmt.Errorf("%w: %q", errInvalidKey, p.key)) } + if p.hasValue && !valueRe.MatchString(p.value) { + return errFunc(fmt.Errorf("%w: %q", errInvalidValue, p.value)) + } if !p.hasValue && p.value != "" { return errFunc(errors.New("inconsistent value")) } @@ -136,11 +154,11 @@ func (p Property) Value() (string, bool) { return p.value, p.hasValue } -// String encodes Property into a header string compliant with the W3C Baggage +// String encodes Property into a string compliant with the W3C Baggage // specification. func (p Property) String() string { if p.hasValue { - return fmt.Sprintf("%s%s%v", p.key, keyValueDelimiter, valueEscape(p.value)) + return fmt.Sprintf("%s%s%v", p.key, keyValueDelimiter, p.value) } return p.key } @@ -200,7 +218,7 @@ func (p properties) validate() error { return nil } -// String encodes properties into a header string compliant with the W3C Baggage +// String encodes properties into a string compliant with the W3C Baggage // specification. func (p properties) String() string { props := make([]string, len(p)) @@ -222,28 +240,11 @@ type Member struct { hasData bool } -// NewMember returns a new Member from the passed arguments. -// -// The passed key must be compliant with W3C Baggage specification. -// The passed value must be percent-encoded as defined in W3C Baggage specification. -// -// Notice: Consider using [NewMemberRaw] instead -// that does not require percent-encoding of the value. +// NewMember returns a new Member from the passed arguments. The key will be +// used directly while the value will be url decoded after validation. An error +// is returned if the created Member would be invalid according to the W3C +// Baggage specification. func NewMember(key, value string, props ...Property) (Member, error) { - if !validateValue(value) { - return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) - } - decodedValue, err := url.PathUnescape(value) - if err != nil { - return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) - } - return NewMemberRaw(key, decodedValue, props...) -} - -// NewMemberRaw returns a new Member from the passed arguments. -// -// The passed key must be compliant with W3C Baggage specification. -func NewMemberRaw(key, value string, props ...Property) (Member, error) { m := Member{ key: key, value: value, @@ -253,6 +254,11 @@ func NewMemberRaw(key, value string, props ...Property) (Member, error) { if err := m.validate(); err != nil { return newInvalidMember(), err } + decodedValue, err := url.PathUnescape(value) + if err != nil { + return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) + } + m.value = decodedValue return m, nil } @@ -268,7 +274,11 @@ func parseMember(member string) (Member, error) { return newInvalidMember(), fmt.Errorf("%w: %d", errMemberBytes, n) } - var props properties + var ( + key, value string + props properties + ) + keyValue, properties, found := strings.Cut(member, propertyDelimiter) if found { // Parse the member properties. @@ -289,34 +299,36 @@ func parseMember(member string) (Member, error) { } // "Leading and trailing whitespaces are allowed but MUST be trimmed // when converting the header into a data structure." - key := strings.TrimSpace(k) - if !validateKey(key) { + key = strings.TrimSpace(k) + var err error + value, err = url.PathUnescape(strings.TrimSpace(v)) + if err != nil { + return newInvalidMember(), fmt.Errorf("%w: %q", err, value) + } + if !keyRe.MatchString(key) { return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key) } - - val := strings.TrimSpace(v) - if !validateValue(val) { - return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, v) + if !valueRe.MatchString(value) { + return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) } - // Decode a percent-encoded value. - value, err := url.PathUnescape(val) - if err != nil { - return newInvalidMember(), fmt.Errorf("%w: %w", errInvalidValue, err) - } return Member{key: key, value: value, properties: props, hasData: true}, nil } // validate ensures m conforms to the W3C Baggage specification. -// A key must be an ASCII string, returning an error otherwise. +// A key is just an ASCII string, but a value must be URL encoded UTF-8, +// returning an error otherwise. func (m Member) validate() error { if !m.hasData { return fmt.Errorf("%w: %q", errInvalidMember, m) } - if !validateKey(m.key) { + if !keyRe.MatchString(m.key) { return fmt.Errorf("%w: %q", errInvalidKey, m.key) } + if !valueRe.MatchString(m.value) { + return fmt.Errorf("%w: %q", errInvalidValue, m.value) + } return m.properties.validate() } @@ -329,15 +341,13 @@ func (m Member) Value() string { return m.value } // Properties returns a copy of the Member properties. func (m Member) Properties() []Property { return m.properties.Copy() } -// String encodes Member into a header string compliant with the W3C Baggage +// String encodes Member into a string compliant with the W3C Baggage // specification. func (m Member) String() string { - // A key is just an ASCII string. A value is restricted to be - // US-ASCII characters excluding CTLs, whitespace, - // DQUOTE, comma, semicolon, and backslash. - s := m.key + keyValueDelimiter + valueEscape(m.value) + // A key is just an ASCII string, but a value is URL encoded UTF-8. + s := fmt.Sprintf("%s%s%s", m.key, keyValueDelimiter, url.QueryEscape(m.value)) if len(m.properties) > 0 { - s += propertyDelimiter + m.properties.String() + s = fmt.Sprintf("%s%s%s", s, propertyDelimiter, m.properties.String()) } return s } @@ -526,8 +536,9 @@ func (b Baggage) Len() int { return len(b.list) } -// String encodes Baggage into a header string compliant with the W3C Baggage -// specification. +// String encodes Baggage into a string compliant with the W3C Baggage +// specification. The returned string will be invalid if the Baggage contains +// any invalid list-members. func (b Baggage) String() string { members := make([]string, 0, len(b.list)) for k, v := range b.list { @@ -539,372 +550,3 @@ func (b Baggage) String() string { } return strings.Join(members, listDelimiter) } - -// parsePropertyInternal attempts to decode a Property from the passed string. -// It follows the spec at https://www.w3.org/TR/baggage/#definition. -func parsePropertyInternal(s string) (p Property, ok bool) { - // For the entire function we will use " key = value " as an example. - // Attempting to parse the key. - // First skip spaces at the beginning "< >key = value " (they could be empty). - index := skipSpace(s, 0) - - // Parse the key: " = value ". - keyStart := index - keyEnd := index - for _, c := range s[keyStart:] { - if !validateKeyChar(c) { - break - } - keyEnd++ - } - - // If we couldn't find any valid key character, - // it means the key is either empty or invalid. - if keyStart == keyEnd { - return - } - - // Skip spaces after the key: " key< >= value ". - index = skipSpace(s, keyEnd) - - if index == len(s) { - // A key can have no value, like: " key ". - ok = true - p.key = s[keyStart:keyEnd] - return - } - - // If we have not reached the end and we can't find the '=' delimiter, - // it means the property is invalid. - if s[index] != keyValueDelimiter[0] { - return - } - - // Attempting to parse the value. - // Match: " key =< >value ". - index = skipSpace(s, index+1) - - // Match the value string: " key = ". - // A valid property can be: " key =". - // Therefore, we don't have to check if the value is empty. - valueStart := index - valueEnd := index - for _, c := range s[valueStart:] { - if !validateValueChar(c) { - break - } - valueEnd++ - } - - // Skip all trailing whitespaces: " key = value< >". - index = skipSpace(s, valueEnd) - - // If after looking for the value and skipping whitespaces - // we have not reached the end, it means the property is - // invalid, something like: " key = value value1". - if index != len(s) { - return - } - - // Decode a percent-encoded value. - value, err := url.PathUnescape(s[valueStart:valueEnd]) - if err != nil { - return - } - - ok = true - p.key = s[keyStart:keyEnd] - p.hasValue = true - - p.value = value - return -} - -func skipSpace(s string, offset int) int { - i := offset - for ; i < len(s); i++ { - c := s[i] - if c != ' ' && c != '\t' { - break - } - } - return i -} - -var safeKeyCharset = [utf8.RuneSelf]bool{ - // 0x23 to 0x27 - '#': true, - '$': true, - '%': true, - '&': true, - '\'': true, - - // 0x30 to 0x39 - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - - // 0x41 to 0x5a - 'A': true, - 'B': true, - 'C': true, - 'D': true, - 'E': true, - 'F': true, - 'G': true, - 'H': true, - 'I': true, - 'J': true, - 'K': true, - 'L': true, - 'M': true, - 'N': true, - 'O': true, - 'P': true, - 'Q': true, - 'R': true, - 'S': true, - 'T': true, - 'U': true, - 'V': true, - 'W': true, - 'X': true, - 'Y': true, - 'Z': true, - - // 0x5e to 0x7a - '^': true, - '_': true, - '`': true, - 'a': true, - 'b': true, - 'c': true, - 'd': true, - 'e': true, - 'f': true, - 'g': true, - 'h': true, - 'i': true, - 'j': true, - 'k': true, - 'l': true, - 'm': true, - 'n': true, - 'o': true, - 'p': true, - 'q': true, - 'r': true, - 's': true, - 't': true, - 'u': true, - 'v': true, - 'w': true, - 'x': true, - 'y': true, - 'z': true, - - // remainder - '!': true, - '*': true, - '+': true, - '-': true, - '.': true, - '|': true, - '~': true, -} - -func validateKey(s string) bool { - if len(s) == 0 { - return false - } - - for _, c := range s { - if !validateKeyChar(c) { - return false - } - } - - return true -} - -func validateKeyChar(c int32) bool { - return c >= 0 && c < int32(utf8.RuneSelf) && safeKeyCharset[c] -} - -func validateValue(s string) bool { - for _, c := range s { - if !validateValueChar(c) { - return false - } - } - - return true -} - -var safeValueCharset = [utf8.RuneSelf]bool{ - '!': true, // 0x21 - - // 0x23 to 0x2b - '#': true, - '$': true, - '%': true, - '&': true, - '\'': true, - '(': true, - ')': true, - '*': true, - '+': true, - - // 0x2d to 0x3a - '-': true, - '.': true, - '/': true, - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - ':': true, - - // 0x3c to 0x5b - '<': true, // 0x3C - '=': true, // 0x3D - '>': true, // 0x3E - '?': true, // 0x3F - '@': true, // 0x40 - 'A': true, // 0x41 - 'B': true, // 0x42 - 'C': true, // 0x43 - 'D': true, // 0x44 - 'E': true, // 0x45 - 'F': true, // 0x46 - 'G': true, // 0x47 - 'H': true, // 0x48 - 'I': true, // 0x49 - 'J': true, // 0x4A - 'K': true, // 0x4B - 'L': true, // 0x4C - 'M': true, // 0x4D - 'N': true, // 0x4E - 'O': true, // 0x4F - 'P': true, // 0x50 - 'Q': true, // 0x51 - 'R': true, // 0x52 - 'S': true, // 0x53 - 'T': true, // 0x54 - 'U': true, // 0x55 - 'V': true, // 0x56 - 'W': true, // 0x57 - 'X': true, // 0x58 - 'Y': true, // 0x59 - 'Z': true, // 0x5A - '[': true, // 0x5B - - // 0x5d to 0x7e - ']': true, // 0x5D - '^': true, // 0x5E - '_': true, // 0x5F - '`': true, // 0x60 - 'a': true, // 0x61 - 'b': true, // 0x62 - 'c': true, // 0x63 - 'd': true, // 0x64 - 'e': true, // 0x65 - 'f': true, // 0x66 - 'g': true, // 0x67 - 'h': true, // 0x68 - 'i': true, // 0x69 - 'j': true, // 0x6A - 'k': true, // 0x6B - 'l': true, // 0x6C - 'm': true, // 0x6D - 'n': true, // 0x6E - 'o': true, // 0x6F - 'p': true, // 0x70 - 'q': true, // 0x71 - 'r': true, // 0x72 - 's': true, // 0x73 - 't': true, // 0x74 - 'u': true, // 0x75 - 'v': true, // 0x76 - 'w': true, // 0x77 - 'x': true, // 0x78 - 'y': true, // 0x79 - 'z': true, // 0x7A - '{': true, // 0x7B - '|': true, // 0x7C - '}': true, // 0x7D - '~': true, // 0x7E -} - -func validateValueChar(c int32) bool { - return c >= 0 && c < int32(utf8.RuneSelf) && safeValueCharset[c] -} - -// valueEscape escapes the string so it can be safely placed inside a baggage value, -// replacing special characters with %XX sequences as needed. -// -// The implementation is based on: -// https://github.com/golang/go/blob/f6509cf5cdbb5787061b784973782933c47f1782/src/net/url/url.go#L285. -func valueEscape(s string) string { - hexCount := 0 - for i := 0; i < len(s); i++ { - c := s[i] - if shouldEscape(c) { - hexCount++ - } - } - - if hexCount == 0 { - return s - } - - var buf [64]byte - var t []byte - - required := len(s) + 2*hexCount - if required <= len(buf) { - t = buf[:required] - } else { - t = make([]byte, required) - } - - j := 0 - for i := 0; i < len(s); i++ { - c := s[i] - if shouldEscape(s[i]) { - const upperhex = "0123456789ABCDEF" - t[j] = '%' - t[j+1] = upperhex[c>>4] - t[j+2] = upperhex[c&15] - j += 3 - } else { - t[j] = c - j++ - } - } - - return string(t) -} - -// shouldEscape returns true if the specified byte should be escaped when -// appearing in a baggage value string. -func shouldEscape(c byte) bool { - if c == '%' { - // The percent character must be encoded so that percent-encoding can work. - return true - } - return !validateValueChar(int32(c)) -} diff --git a/vendor/go.opentelemetry.io/otel/baggage/context.go b/vendor/go.opentelemetry.io/otel/baggage/context.go index a572461a..24b34b75 100644 --- a/vendor/go.opentelemetry.io/otel/baggage/context.go +++ b/vendor/go.opentelemetry.io/otel/baggage/context.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package baggage // import "go.opentelemetry.io/otel/baggage" diff --git a/vendor/go.opentelemetry.io/otel/baggage/doc.go b/vendor/go.opentelemetry.io/otel/baggage/doc.go index b51d87ca..4545100d 100644 --- a/vendor/go.opentelemetry.io/otel/baggage/doc.go +++ b/vendor/go.opentelemetry.io/otel/baggage/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package baggage provides functionality for storing and retrieving diff --git a/vendor/go.opentelemetry.io/otel/codes/README.md b/vendor/go.opentelemetry.io/otel/codes/README.md deleted file mode 100644 index 24c52b38..00000000 --- a/vendor/go.opentelemetry.io/otel/codes/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Codes - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/codes)](https://pkg.go.dev/go.opentelemetry.io/otel/codes) diff --git a/vendor/go.opentelemetry.io/otel/codes/codes.go b/vendor/go.opentelemetry.io/otel/codes/codes.go index df29d96a..587ebae4 100644 --- a/vendor/go.opentelemetry.io/otel/codes/codes.go +++ b/vendor/go.opentelemetry.io/otel/codes/codes.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package codes // import "go.opentelemetry.io/otel/codes" diff --git a/vendor/go.opentelemetry.io/otel/codes/doc.go b/vendor/go.opentelemetry.io/otel/codes/doc.go index ee8db448..4e328fbb 100644 --- a/vendor/go.opentelemetry.io/otel/codes/doc.go +++ b/vendor/go.opentelemetry.io/otel/codes/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package codes defines the canonical error codes used by OpenTelemetry. diff --git a/vendor/go.opentelemetry.io/otel/doc.go b/vendor/go.opentelemetry.io/otel/doc.go index 441c5950..daa36c89 100644 --- a/vendor/go.opentelemetry.io/otel/doc.go +++ b/vendor/go.opentelemetry.io/otel/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package otel provides global access to the OpenTelemetry API. The subpackages of @@ -11,7 +22,7 @@ transmitted anywhere. An implementation of the OpenTelemetry SDK, like the default SDK implementation (go.opentelemetry.io/otel/sdk), and associated exporters are used to process and transport this data. -To read the getting started guide, see https://opentelemetry.io/docs/languages/go/getting-started/. +To read the getting started guide, see https://opentelemetry.io/docs/go/getting-started/. To read more about tracing, see go.opentelemetry.io/otel/trace. diff --git a/vendor/go.opentelemetry.io/otel/error_handler.go b/vendor/go.opentelemetry.io/otel/error_handler.go index 67414c71..72fad854 100644 --- a/vendor/go.opentelemetry.io/otel/error_handler.go +++ b/vendor/go.opentelemetry.io/otel/error_handler.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" diff --git a/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh b/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh index 93e80ea3..9a58fb1d 100644 --- a/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh +++ b/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh @@ -1,7 +1,18 @@ #!/usr/bin/env bash # Copyright The OpenTelemetry Authors -# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. set -euo pipefail diff --git a/vendor/go.opentelemetry.io/otel/handler.go b/vendor/go.opentelemetry.io/otel/handler.go index 07623b67..4115fe3b 100644 --- a/vendor/go.opentelemetry.io/otel/handler.go +++ b/vendor/go.opentelemetry.io/otel/handler.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" @@ -7,8 +18,12 @@ import ( "go.opentelemetry.io/otel/internal/global" ) -// Compile-time check global.ErrDelegator implements ErrorHandler. -var _ ErrorHandler = (*global.ErrDelegator)(nil) +var ( + // Compile-time check global.ErrDelegator implements ErrorHandler. + _ ErrorHandler = (*global.ErrDelegator)(nil) + // Compile-time check global.ErrLogger implements ErrorHandler. + _ ErrorHandler = (*global.ErrLogger)(nil) +) // GetErrorHandler returns the global ErrorHandler instance. // @@ -29,5 +44,5 @@ func GetErrorHandler() ErrorHandler { return global.GetErrorHandler() } // delegate errors to h. func SetErrorHandler(h ErrorHandler) { global.SetErrorHandler(h) } -// Handle is a convenience function for GetErrorHandler().Handle(err). -func Handle(err error) { global.GetErrorHandler().Handle(err) } +// Handle is a convenience function for ErrorHandler().Handle(err). +func Handle(err error) { global.Handle(err) } diff --git a/vendor/go.opentelemetry.io/otel/internal/attribute/attribute.go b/vendor/go.opentelemetry.io/otel/internal/attribute/attribute.go index 822d8479..622c3ee3 100644 --- a/vendor/go.opentelemetry.io/otel/internal/attribute/attribute.go +++ b/vendor/go.opentelemetry.io/otel/internal/attribute/attribute.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package attribute provide several helper functions for some commonly used @@ -14,33 +25,33 @@ import ( // BoolSliceValue converts a bool slice into an array with same elements as slice. func BoolSliceValue(v []bool) interface{} { var zero bool - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]bool), v) + return cp.Elem().Interface() } // Int64SliceValue converts an int64 slice into an array with same elements as slice. func Int64SliceValue(v []int64) interface{} { var zero int64 - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]int64), v) + return cp.Elem().Interface() } // Float64SliceValue converts a float64 slice into an array with same elements as slice. func Float64SliceValue(v []float64) interface{} { var zero float64 - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]float64), v) + return cp.Elem().Interface() } // StringSliceValue converts a string slice into an array with same elements as slice. func StringSliceValue(v []string) interface{} { var zero string - cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem() - reflect.Copy(cp, reflect.ValueOf(v)) - return cp.Interface() + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]string), v) + return cp.Elem().Interface() } // AsBoolSlice converts a bool array into a slice into with same elements as array. diff --git a/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go b/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go index b4f85f44..b96e5408 100644 --- a/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go +++ b/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package baggage provides base types and functionality to store and retrieve diff --git a/vendor/go.opentelemetry.io/otel/internal/baggage/context.go b/vendor/go.opentelemetry.io/otel/internal/baggage/context.go index 3aea9c49..4469700d 100644 --- a/vendor/go.opentelemetry.io/otel/internal/baggage/context.go +++ b/vendor/go.opentelemetry.io/otel/internal/baggage/context.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package baggage // import "go.opentelemetry.io/otel/internal/baggage" diff --git a/vendor/go.opentelemetry.io/otel/internal/gen.go b/vendor/go.opentelemetry.io/otel/internal/gen.go index 4259f032..f532f07e 100644 --- a/vendor/go.opentelemetry.io/otel/internal/gen.go +++ b/vendor/go.opentelemetry.io/otel/internal/gen.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package internal // import "go.opentelemetry.io/otel/internal" diff --git a/vendor/go.opentelemetry.io/otel/internal/global/handler.go b/vendor/go.opentelemetry.io/otel/internal/global/handler.go index c657ff8e..5e9b8304 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/handler.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/handler.go @@ -1,13 +1,38 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" import ( "log" + "os" "sync/atomic" ) +var ( + // GlobalErrorHandler provides an ErrorHandler that can be used + // throughout an OpenTelemetry instrumented project. When a user + // specified ErrorHandler is registered (`SetErrorHandler`) all calls to + // `Handle` and will be delegated to the registered ErrorHandler. + GlobalErrorHandler = defaultErrorHandler() + + // Compile-time check that delegator implements ErrorHandler. + _ ErrorHandler = (*ErrDelegator)(nil) + // Compile-time check that errLogger implements ErrorHandler. + _ ErrorHandler = (*ErrLogger)(nil) +) + // ErrorHandler handles irremediable events. type ErrorHandler interface { // Handle handles any error deemed irremediable by an OpenTelemetry @@ -19,18 +44,59 @@ type ErrDelegator struct { delegate atomic.Pointer[ErrorHandler] } -// Compile-time check that delegator implements ErrorHandler. -var _ ErrorHandler = (*ErrDelegator)(nil) - func (d *ErrDelegator) Handle(err error) { - if eh := d.delegate.Load(); eh != nil { - (*eh).Handle(err) - return - } - log.Print(err) + d.getDelegate().Handle(err) +} + +func (d *ErrDelegator) getDelegate() ErrorHandler { + return *d.delegate.Load() } // setDelegate sets the ErrorHandler delegate. func (d *ErrDelegator) setDelegate(eh ErrorHandler) { d.delegate.Store(&eh) } + +func defaultErrorHandler() *ErrDelegator { + d := &ErrDelegator{} + d.setDelegate(&ErrLogger{l: log.New(os.Stderr, "", log.LstdFlags)}) + return d +} + +// ErrLogger logs errors if no delegate is set, otherwise they are delegated. +type ErrLogger struct { + l *log.Logger +} + +// Handle logs err if no delegate is set, otherwise it is delegated. +func (h *ErrLogger) Handle(err error) { + h.l.Print(err) +} + +// GetErrorHandler returns the global ErrorHandler instance. +// +// The default ErrorHandler instance returned will log all errors to STDERR +// until an override ErrorHandler is set with SetErrorHandler. All +// ErrorHandler returned prior to this will automatically forward errors to +// the set instance instead of logging. +// +// Subsequent calls to SetErrorHandler after the first will not forward errors +// to the new ErrorHandler for prior returned instances. +func GetErrorHandler() ErrorHandler { + return GlobalErrorHandler +} + +// SetErrorHandler sets the global ErrorHandler to h. +// +// The first time this is called all ErrorHandler previously returned from +// GetErrorHandler will send errors to h instead of the default logging +// ErrorHandler. Subsequent calls will set the global ErrorHandler, but not +// delegate errors to h. +func SetErrorHandler(h ErrorHandler) { + GlobalErrorHandler.setDelegate(h) +} + +// Handle is a convenience function for ErrorHandler().Handle(err). +func Handle(err error) { + GetErrorHandler().Handle(err) +} diff --git a/vendor/go.opentelemetry.io/otel/internal/global/instruments.go b/vendor/go.opentelemetry.io/otel/internal/global/instruments.go index 3a0cc42f..ebb13c20 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/instruments.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/instruments.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" @@ -281,32 +292,6 @@ func (i *sfHistogram) Record(ctx context.Context, x float64, opts ...metric.Reco } } -type sfGauge struct { - embedded.Float64Gauge - - name string - opts []metric.Float64GaugeOption - - delegate atomic.Value // metric.Float64Gauge -} - -var _ metric.Float64Gauge = (*sfGauge)(nil) - -func (i *sfGauge) setDelegate(m metric.Meter) { - ctr, err := m.Float64Gauge(i.name, i.opts...) - if err != nil { - GetErrorHandler().Handle(err) - return - } - i.delegate.Store(ctr) -} - -func (i *sfGauge) Record(ctx context.Context, x float64, opts ...metric.RecordOption) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(metric.Float64Gauge).Record(ctx, x, opts...) - } -} - type siCounter struct { embedded.Int64Counter @@ -384,29 +369,3 @@ func (i *siHistogram) Record(ctx context.Context, x int64, opts ...metric.Record ctr.(metric.Int64Histogram).Record(ctx, x, opts...) } } - -type siGauge struct { - embedded.Int64Gauge - - name string - opts []metric.Int64GaugeOption - - delegate atomic.Value // metric.Int64Gauge -} - -var _ metric.Int64Gauge = (*siGauge)(nil) - -func (i *siGauge) setDelegate(m metric.Meter) { - ctr, err := m.Int64Gauge(i.name, i.opts...) - if err != nil { - GetErrorHandler().Handle(err) - return - } - i.delegate.Store(ctr) -} - -func (i *siGauge) Record(ctx context.Context, x int64, opts ...metric.RecordOption) { - if ctr := i.delegate.Load(); ctr != nil { - ctr.(metric.Int64Gauge).Record(ctx, x, opts...) - } -} diff --git a/vendor/go.opentelemetry.io/otel/internal/global/internal_logging.go b/vendor/go.opentelemetry.io/otel/internal/global/internal_logging.go index adbca7d3..c6f305a2 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/internal_logging.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/internal_logging.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" @@ -12,20 +23,17 @@ import ( "github.com/go-logr/stdr" ) -// globalLogger holds a reference to the [logr.Logger] used within -// go.opentelemetry.io/otel. +// globalLogger is the logging interface used within the otel api and sdk provide details of the internals. // // The default logger uses stdr which is backed by the standard `log.Logger` // interface. This logger will only show messages at the Error Level. -var globalLogger = func() *atomic.Pointer[logr.Logger] { - l := stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)) +var globalLogger atomic.Pointer[logr.Logger] - p := new(atomic.Pointer[logr.Logger]) - p.Store(&l) - return p -}() +func init() { + SetLogger(stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile))) +} -// SetLogger sets the global Logger to l. +// SetLogger overrides the globalLogger with l. // // To see Warn messages use a logger with `l.V(1).Enabled() == true` // To see Info messages use a logger with `l.V(4).Enabled() == true` @@ -34,29 +42,28 @@ func SetLogger(l logr.Logger) { globalLogger.Store(&l) } -// GetLogger returns the global logger. -func GetLogger() logr.Logger { +func getLogger() logr.Logger { return *globalLogger.Load() } // Info prints messages about the general state of the API or SDK. // This should usually be less than 5 messages a minute. func Info(msg string, keysAndValues ...interface{}) { - GetLogger().V(4).Info(msg, keysAndValues...) + getLogger().V(4).Info(msg, keysAndValues...) } // Error prints messages about exceptional states of the API or SDK. func Error(err error, msg string, keysAndValues ...interface{}) { - GetLogger().Error(err, msg, keysAndValues...) + getLogger().Error(err, msg, keysAndValues...) } // Debug prints messages about all internal changes in the API or SDK. func Debug(msg string, keysAndValues ...interface{}) { - GetLogger().V(8).Info(msg, keysAndValues...) + getLogger().V(8).Info(msg, keysAndValues...) } // Warn prints messages about warnings in the API or SDK. // Not an error but is likely more important than an informational event. func Warn(msg string, keysAndValues ...interface{}) { - GetLogger().V(1).Info(msg, keysAndValues...) + getLogger().V(1).Info(msg, keysAndValues...) } diff --git a/vendor/go.opentelemetry.io/otel/internal/global/meter.go b/vendor/go.opentelemetry.io/otel/internal/global/meter.go index cfd1df9b..0097db47 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/meter.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/meter.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" @@ -65,7 +76,6 @@ func (p *meterProvider) Meter(name string, opts ...metric.MeterOption) metric.Me key := il{ name: name, version: c.InstrumentationVersion(), - schema: c.SchemaURL(), } if p.meters == nil { @@ -120,11 +130,9 @@ func (m *meter) setDelegate(provider metric.MeterProvider) { inst.setDelegate(meter) } - var n *list.Element - for e := m.registry.Front(); e != nil; e = n { + for e := m.registry.Front(); e != nil; e = e.Next() { r := e.Value.(*registration) r.setDelegate(meter) - n = e.Next() m.registry.Remove(e) } @@ -165,17 +173,6 @@ func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOpti return i, nil } -func (m *meter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (metric.Int64Gauge, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64Gauge(name, options...) - } - m.mtx.Lock() - defer m.mtx.Unlock() - i := &siGauge{name: name, opts: options} - m.instruments = append(m.instruments, i) - return i, nil -} - func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) { if del, ok := m.delegate.Load().(metric.Meter); ok { return del.Int64ObservableCounter(name, options...) @@ -242,17 +239,6 @@ func (m *meter) Float64Histogram(name string, options ...metric.Float64Histogram return i, nil } -func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption) (metric.Float64Gauge, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64Gauge(name, options...) - } - m.mtx.Lock() - defer m.mtx.Unlock() - i := &sfGauge{name: name, opts: options} - m.instruments = append(m.instruments, i) - return i, nil -} - func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) { if del, ok := m.delegate.Load().(metric.Meter); ok { return del.Float64ObservableCounter(name, options...) diff --git a/vendor/go.opentelemetry.io/otel/internal/global/propagator.go b/vendor/go.opentelemetry.io/otel/internal/global/propagator.go index 38560ff9..06bac35c 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/propagator.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/propagator.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" diff --git a/vendor/go.opentelemetry.io/otel/internal/global/state.go b/vendor/go.opentelemetry.io/otel/internal/global/state.go index 204ea142..7985005b 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/state.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/state.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" @@ -14,10 +25,6 @@ import ( ) type ( - errorHandlerHolder struct { - eh ErrorHandler - } - tracerProviderHolder struct { tp trace.TracerProvider } @@ -32,59 +39,15 @@ type ( ) var ( - globalErrorHandler = defaultErrorHandler() globalTracer = defaultTracerValue() globalPropagators = defaultPropagatorsValue() globalMeterProvider = defaultMeterProvider() - delegateErrorHandlerOnce sync.Once delegateTraceOnce sync.Once delegateTextMapPropagatorOnce sync.Once delegateMeterOnce sync.Once ) -// GetErrorHandler returns the global ErrorHandler instance. -// -// The default ErrorHandler instance returned will log all errors to STDERR -// until an override ErrorHandler is set with SetErrorHandler. All -// ErrorHandler returned prior to this will automatically forward errors to -// the set instance instead of logging. -// -// Subsequent calls to SetErrorHandler after the first will not forward errors -// to the new ErrorHandler for prior returned instances. -func GetErrorHandler() ErrorHandler { - return globalErrorHandler.Load().(errorHandlerHolder).eh -} - -// SetErrorHandler sets the global ErrorHandler to h. -// -// The first time this is called all ErrorHandler previously returned from -// GetErrorHandler will send errors to h instead of the default logging -// ErrorHandler. Subsequent calls will set the global ErrorHandler, but not -// delegate errors to h. -func SetErrorHandler(h ErrorHandler) { - current := GetErrorHandler() - - if _, cOk := current.(*ErrDelegator); cOk { - if _, ehOk := h.(*ErrDelegator); ehOk && current == h { - // Do not assign to the delegate of the default ErrDelegator to be - // itself. - Error( - errors.New("no ErrorHandler delegate configured"), - "ErrorHandler remains its current value.", - ) - return - } - } - - delegateErrorHandlerOnce.Do(func() { - if def, ok := current.(*ErrDelegator); ok { - def.setDelegate(h) - } - }) - globalErrorHandler.Store(errorHandlerHolder{eh: h}) -} - // TracerProvider is the internal implementation for global.TracerProvider. func TracerProvider() trace.TracerProvider { return globalTracer.Load().(tracerProviderHolder).tp @@ -100,7 +63,7 @@ func SetTracerProvider(tp trace.TracerProvider) { // to itself. Error( errors.New("no delegate configured in tracer provider"), - "Setting tracer provider to its current value. No delegate will be configured", + "Setting tracer provider to it's current value. No delegate will be configured", ) return } @@ -129,7 +92,7 @@ func SetTextMapPropagator(p propagation.TextMapPropagator) { // delegate to itself. Error( errors.New("no delegate configured in text map propagator"), - "Setting text map propagator to its current value. No delegate will be configured", + "Setting text map propagator to it's current value. No delegate will be configured", ) return } @@ -160,7 +123,7 @@ func SetMeterProvider(mp metric.MeterProvider) { // to itself. Error( errors.New("no delegate configured in meter provider"), - "Setting meter provider to its current value. No delegate will be configured", + "Setting meter provider to it's current value. No delegate will be configured", ) return } @@ -174,12 +137,6 @@ func SetMeterProvider(mp metric.MeterProvider) { globalMeterProvider.Store(meterProviderHolder{mp: mp}) } -func defaultErrorHandler() *atomic.Value { - v := &atomic.Value{} - v.Store(errorHandlerHolder{eh: &ErrDelegator{}}) - return v -} - func defaultTracerValue() *atomic.Value { v := &atomic.Value{} v.Store(tracerProviderHolder{tp: &tracerProvider{}}) diff --git a/vendor/go.opentelemetry.io/otel/internal/global/trace.go b/vendor/go.opentelemetry.io/otel/internal/global/trace.go index e31f442b..3f61ec12 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/trace.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/trace.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package global // import "go.opentelemetry.io/otel/internal/global" @@ -86,7 +97,6 @@ func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T key := il{ name: name, version: c.InstrumentationVersion(), - schema: c.SchemaURL(), } if p.tracers == nil { @@ -102,7 +112,10 @@ func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T return t } -type il struct{ name, version, schema string } +type il struct { + name string + version string +} // tracer is a placeholder for a trace.Tracer. // @@ -180,9 +193,6 @@ func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {} // AddEvent does nothing. func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {} -// AddLink does nothing. -func (nonRecordingSpan) AddLink(trace.Link) {} - // SetName does nothing. func (nonRecordingSpan) SetName(string) {} diff --git a/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go b/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go index 3e7bb3b3..e07e7940 100644 --- a/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go +++ b/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package internal // import "go.opentelemetry.io/otel/internal" diff --git a/vendor/go.opentelemetry.io/otel/internal_logging.go b/vendor/go.opentelemetry.io/otel/internal_logging.go index 6de7f2e4..c4f8acd5 100644 --- a/vendor/go.opentelemetry.io/otel/internal_logging.go +++ b/vendor/go.opentelemetry.io/otel/internal_logging.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" diff --git a/vendor/go.opentelemetry.io/otel/metric.go b/vendor/go.opentelemetry.io/otel/metric.go index 1e6473b3..f9551719 100644 --- a/vendor/go.opentelemetry.io/otel/metric.go +++ b/vendor/go.opentelemetry.io/otel/metric.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" diff --git a/vendor/go.opentelemetry.io/otel/metric/README.md b/vendor/go.opentelemetry.io/otel/metric/README.md deleted file mode 100644 index 0cf902e0..00000000 --- a/vendor/go.opentelemetry.io/otel/metric/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Metric API - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/metric)](https://pkg.go.dev/go.opentelemetry.io/otel/metric) diff --git a/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go b/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go index cf23db77..072baa8e 100644 --- a/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go +++ b/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" @@ -39,7 +50,7 @@ type Float64ObservableCounter interface { } // Float64ObservableCounterConfig contains options for asynchronous counter -// instruments that record float64 values. +// instruments that record int64 values. type Float64ObservableCounterConfig struct { description string unit string @@ -97,7 +108,7 @@ type Float64ObservableUpDownCounter interface { } // Float64ObservableUpDownCounterConfig contains options for asynchronous -// counter instruments that record float64 values. +// counter instruments that record int64 values. type Float64ObservableUpDownCounterConfig struct { description string unit string @@ -154,7 +165,7 @@ type Float64ObservableGauge interface { } // Float64ObservableGaugeConfig contains options for asynchronous counter -// instruments that record float64 values. +// instruments that record int64 values. type Float64ObservableGaugeConfig struct { description string unit string diff --git a/vendor/go.opentelemetry.io/otel/metric/asyncint64.go b/vendor/go.opentelemetry.io/otel/metric/asyncint64.go index c82ba532..9bd6ebf0 100644 --- a/vendor/go.opentelemetry.io/otel/metric/asyncint64.go +++ b/vendor/go.opentelemetry.io/otel/metric/asyncint64.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" diff --git a/vendor/go.opentelemetry.io/otel/metric/config.go b/vendor/go.opentelemetry.io/otel/metric/config.go index d9e3b13e..778ad2d7 100644 --- a/vendor/go.opentelemetry.io/otel/metric/config.go +++ b/vendor/go.opentelemetry.io/otel/metric/config.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" diff --git a/vendor/go.opentelemetry.io/otel/metric/doc.go b/vendor/go.opentelemetry.io/otel/metric/doc.go index f153745b..54716e13 100644 --- a/vendor/go.opentelemetry.io/otel/metric/doc.go +++ b/vendor/go.opentelemetry.io/otel/metric/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package metric provides the OpenTelemetry API used to measure metrics about @@ -57,23 +68,6 @@ asynchronous measurement, a Gauge ([Int64ObservableGauge] and See the [OpenTelemetry documentation] for more information about instruments and their intended use. -# Instrument Name - -OpenTelemetry defines an [instrument name syntax] that restricts what -instrument names are allowed. - -Instrument names should ... - - - Not be empty. - - Have an alphabetic character as their first letter. - - Have any letter after the first be an alphanumeric character, ‘_’, ‘.’, - ‘-’, or ‘/’. - - Have a maximum length of 255 letters. - -To ensure compatibility with observability platforms, all instruments created -need to conform to this syntax. Not all implementations of the API will validate -these names, it is the callers responsibility to ensure compliance. - # Measurements Measurements are made by recording values and information about the values with @@ -170,7 +164,6 @@ It is strongly recommended that authors only embed That implementation is the only one OpenTelemetry authors can guarantee will fully implement all the API interfaces when a user updates their API. -[instrument name syntax]: https://opentelemetry.io/docs/specs/otel/metrics/api/#instrument-name-syntax [OpenTelemetry documentation]: https://opentelemetry.io/docs/concepts/signals/metrics/ [GetMeterProvider]: https://pkg.go.dev/go.opentelemetry.io/otel#GetMeterProvider */ diff --git a/vendor/go.opentelemetry.io/otel/metric/embedded/README.md b/vendor/go.opentelemetry.io/otel/metric/embedded/README.md deleted file mode 100644 index 1f6e0efa..00000000 --- a/vendor/go.opentelemetry.io/otel/metric/embedded/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Metric Embedded - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/metric/embedded)](https://pkg.go.dev/go.opentelemetry.io/otel/metric/embedded) diff --git a/vendor/go.opentelemetry.io/otel/metric/embedded/embedded.go b/vendor/go.opentelemetry.io/otel/metric/embedded/embedded.go index 1a9dc680..ae0bdbd2 100644 --- a/vendor/go.opentelemetry.io/otel/metric/embedded/embedded.go +++ b/vendor/go.opentelemetry.io/otel/metric/embedded/embedded.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package embedded provides interfaces embedded within the [OpenTelemetry // metric API]. @@ -102,16 +113,6 @@ type Float64Counter interface{ float64Counter() } // the API package). type Float64Histogram interface{ float64Histogram() } -// Float64Gauge is embedded in [go.opentelemetry.io/otel/metric.Float64Gauge]. -// -// Embed this interface in your implementation of the -// [go.opentelemetry.io/otel/metric.Float64Gauge] if you want users to -// experience a compilation error, signaling they need to update to your latest -// implementation, when the [go.opentelemetry.io/otel/metric.Float64Gauge] -// interface is extended (which is something that can happen without a major -// version bump of the API package). -type Float64Gauge interface{ float64Gauge() } - // Float64ObservableCounter is embedded in // [go.opentelemetry.io/otel/metric.Float64ObservableCounter]. // @@ -184,16 +185,6 @@ type Int64Counter interface{ int64Counter() } // the API package). type Int64Histogram interface{ int64Histogram() } -// Int64Gauge is embedded in [go.opentelemetry.io/otel/metric.Int64Gauge]. -// -// Embed this interface in your implementation of the -// [go.opentelemetry.io/otel/metric.Int64Gauge] if you want users to experience -// a compilation error, signaling they need to update to your latest -// implementation, when the [go.opentelemetry.io/otel/metric.Int64Gauge] -// interface is extended (which is something that can happen without a major -// version bump of the API package). -type Int64Gauge interface{ int64Gauge() } - // Int64ObservableCounter is embedded in // [go.opentelemetry.io/otel/metric.Int64ObservableCounter]. // diff --git a/vendor/go.opentelemetry.io/otel/metric/instrument.go b/vendor/go.opentelemetry.io/otel/metric/instrument.go index ea52e402..be89cd53 100644 --- a/vendor/go.opentelemetry.io/otel/metric/instrument.go +++ b/vendor/go.opentelemetry.io/otel/metric/instrument.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" @@ -16,7 +27,6 @@ type InstrumentOption interface { Int64CounterOption Int64UpDownCounterOption Int64HistogramOption - Int64GaugeOption Int64ObservableCounterOption Int64ObservableUpDownCounterOption Int64ObservableGaugeOption @@ -24,7 +34,6 @@ type InstrumentOption interface { Float64CounterOption Float64UpDownCounterOption Float64HistogramOption - Float64GaugeOption Float64ObservableCounterOption Float64ObservableUpDownCounterOption Float64ObservableGaugeOption @@ -53,11 +62,6 @@ func (o descOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64Histogra return c } -func (o descOpt) applyFloat64Gauge(c Float64GaugeConfig) Float64GaugeConfig { - c.description = string(o) - return c -} - func (o descOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig) Float64ObservableCounterConfig { c.description = string(o) return c @@ -88,11 +92,6 @@ func (o descOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfi return c } -func (o descOpt) applyInt64Gauge(c Int64GaugeConfig) Int64GaugeConfig { - c.description = string(o) - return c -} - func (o descOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int64ObservableCounterConfig { c.description = string(o) return c @@ -128,11 +127,6 @@ func (o unitOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64Histogra return c } -func (o unitOpt) applyFloat64Gauge(c Float64GaugeConfig) Float64GaugeConfig { - c.unit = string(o) - return c -} - func (o unitOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig) Float64ObservableCounterConfig { c.unit = string(o) return c @@ -163,11 +157,6 @@ func (o unitOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfi return c } -func (o unitOpt) applyInt64Gauge(c Int64GaugeConfig) Int64GaugeConfig { - c.unit = string(o) - return c -} - func (o unitOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int64ObservableCounterConfig { c.unit = string(o) return c diff --git a/vendor/go.opentelemetry.io/otel/metric/meter.go b/vendor/go.opentelemetry.io/otel/metric/meter.go index 6a7991e0..2520bc74 100644 --- a/vendor/go.opentelemetry.io/otel/metric/meter.go +++ b/vendor/go.opentelemetry.io/otel/metric/meter.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" @@ -47,37 +58,17 @@ type Meter interface { // Int64Counter returns a new Int64Counter instrument identified by name // and configured with options. The instrument is used to synchronously // record increasing int64 measurements during a computational operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Int64Counter(name string, options ...Int64CounterOption) (Int64Counter, error) // Int64UpDownCounter returns a new Int64UpDownCounter instrument // identified by name and configured with options. The instrument is used // to synchronously record int64 measurements during a computational // operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Int64UpDownCounter(name string, options ...Int64UpDownCounterOption) (Int64UpDownCounter, error) // Int64Histogram returns a new Int64Histogram instrument identified by // name and configured with options. The instrument is used to // synchronously record the distribution of int64 measurements during a // computational operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Int64Histogram(name string, options ...Int64HistogramOption) (Int64Histogram, error) - // Int64Gauge returns a new Int64Gauge instrument identified by name and - // configured with options. The instrument is used to synchronously record - // instantaneous int64 measurements during a computational operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. - Int64Gauge(name string, options ...Int64GaugeOption) (Int64Gauge, error) // Int64ObservableCounter returns a new Int64ObservableCounter identified // by name and configured with options. The instrument is used to // asynchronously record increasing int64 measurements once per a @@ -87,10 +78,6 @@ type Meter interface { // the WithInt64Callback option to register the callback here, or use the // RegisterCallback method of this Meter to register one later. See the // Measurements section of the package documentation for more information. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Int64ObservableCounter(name string, options ...Int64ObservableCounterOption) (Int64ObservableCounter, error) // Int64ObservableUpDownCounter returns a new Int64ObservableUpDownCounter // instrument identified by name and configured with options. The @@ -101,10 +88,6 @@ type Meter interface { // the WithInt64Callback option to register the callback here, or use the // RegisterCallback method of this Meter to register one later. See the // Measurements section of the package documentation for more information. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Int64ObservableUpDownCounter(name string, options ...Int64ObservableUpDownCounterOption) (Int64ObservableUpDownCounter, error) // Int64ObservableGauge returns a new Int64ObservableGauge instrument // identified by name and configured with options. The instrument is used @@ -115,47 +98,23 @@ type Meter interface { // the WithInt64Callback option to register the callback here, or use the // RegisterCallback method of this Meter to register one later. See the // Measurements section of the package documentation for more information. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Int64ObservableGauge(name string, options ...Int64ObservableGaugeOption) (Int64ObservableGauge, error) // Float64Counter returns a new Float64Counter instrument identified by // name and configured with options. The instrument is used to // synchronously record increasing float64 measurements during a // computational operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Float64Counter(name string, options ...Float64CounterOption) (Float64Counter, error) // Float64UpDownCounter returns a new Float64UpDownCounter instrument // identified by name and configured with options. The instrument is used // to synchronously record float64 measurements during a computational // operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Float64UpDownCounter(name string, options ...Float64UpDownCounterOption) (Float64UpDownCounter, error) // Float64Histogram returns a new Float64Histogram instrument identified by // name and configured with options. The instrument is used to // synchronously record the distribution of float64 measurements during a // computational operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Float64Histogram(name string, options ...Float64HistogramOption) (Float64Histogram, error) - // Float64Gauge returns a new Float64Gauge instrument identified by name and - // configured with options. The instrument is used to synchronously record - // instantaneous float64 measurements during a computational operation. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. - Float64Gauge(name string, options ...Float64GaugeOption) (Float64Gauge, error) // Float64ObservableCounter returns a new Float64ObservableCounter // instrument identified by name and configured with options. The // instrument is used to asynchronously record increasing float64 @@ -165,10 +124,6 @@ type Meter interface { // the WithFloat64Callback option to register the callback here, or use the // RegisterCallback method of this Meter to register one later. See the // Measurements section of the package documentation for more information. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Float64ObservableCounter(name string, options ...Float64ObservableCounterOption) (Float64ObservableCounter, error) // Float64ObservableUpDownCounter returns a new // Float64ObservableUpDownCounter instrument identified by name and @@ -179,10 +134,6 @@ type Meter interface { // the WithFloat64Callback option to register the callback here, or use the // RegisterCallback method of this Meter to register one later. See the // Measurements section of the package documentation for more information. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Float64ObservableUpDownCounter(name string, options ...Float64ObservableUpDownCounterOption) (Float64ObservableUpDownCounter, error) // Float64ObservableGauge returns a new Float64ObservableGauge instrument // identified by name and configured with options. The instrument is used @@ -193,10 +144,6 @@ type Meter interface { // the WithFloat64Callback option to register the callback here, or use the // RegisterCallback method of this Meter to register one later. See the // Measurements section of the package documentation for more information. - // - // The name needs to conform to the OpenTelemetry instrument name syntax. - // See the Instrument Name section of the package documentation for more - // information. Float64ObservableGauge(name string, options ...Float64ObservableGaugeOption) (Float64ObservableGauge, error) // RegisterCallback registers f to be called during the collection of a diff --git a/vendor/go.opentelemetry.io/otel/metric/syncfloat64.go b/vendor/go.opentelemetry.io/otel/metric/syncfloat64.go index 8403a4ba..0a4825ae 100644 --- a/vendor/go.opentelemetry.io/otel/metric/syncfloat64.go +++ b/vendor/go.opentelemetry.io/otel/metric/syncfloat64.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" @@ -28,7 +39,7 @@ type Float64Counter interface { } // Float64CounterConfig contains options for synchronous counter instruments that -// record float64 values. +// record int64 values. type Float64CounterConfig struct { description string unit string @@ -81,7 +92,7 @@ type Float64UpDownCounter interface { } // Float64UpDownCounterConfig contains options for synchronous counter -// instruments that record float64 values. +// instruments that record int64 values. type Float64UpDownCounterConfig struct { description string unit string @@ -133,8 +144,8 @@ type Float64Histogram interface { Record(ctx context.Context, incr float64, options ...RecordOption) } -// Float64HistogramConfig contains options for synchronous histogram -// instruments that record float64 values. +// Float64HistogramConfig contains options for synchronous counter instruments +// that record int64 values. type Float64HistogramConfig struct { description string unit string @@ -172,55 +183,3 @@ func (c Float64HistogramConfig) ExplicitBucketBoundaries() []float64 { type Float64HistogramOption interface { applyFloat64Histogram(Float64HistogramConfig) Float64HistogramConfig } - -// Float64Gauge is an instrument that records instantaneous float64 values. -// -// Warning: Methods may be added to this interface in minor releases. See -// package documentation on API implementation for information on how to set -// default behavior for unimplemented methods. -type Float64Gauge interface { - // Users of the interface can ignore this. This embedded type is only used - // by implementations of this interface. See the "API Implementations" - // section of the package documentation for more information. - embedded.Float64Gauge - - // Record records the instantaneous value. - // - // Use the WithAttributeSet (or, if performance is not a concern, - // the WithAttributes) option to include measurement attributes. - Record(ctx context.Context, value float64, options ...RecordOption) -} - -// Float64GaugeConfig contains options for synchronous gauge instruments that -// record float64 values. -type Float64GaugeConfig struct { - description string - unit string -} - -// NewFloat64GaugeConfig returns a new [Float64GaugeConfig] with all opts -// applied. -func NewFloat64GaugeConfig(opts ...Float64GaugeOption) Float64GaugeConfig { - var config Float64GaugeConfig - for _, o := range opts { - config = o.applyFloat64Gauge(config) - } - return config -} - -// Description returns the configured description. -func (c Float64GaugeConfig) Description() string { - return c.description -} - -// Unit returns the configured unit. -func (c Float64GaugeConfig) Unit() string { - return c.unit -} - -// Float64GaugeOption applies options to a [Float64GaugeConfig]. See -// [InstrumentOption] for other options that can be used as a -// Float64GaugeOption. -type Float64GaugeOption interface { - applyFloat64Gauge(Float64GaugeConfig) Float64GaugeConfig -} diff --git a/vendor/go.opentelemetry.io/otel/metric/syncint64.go b/vendor/go.opentelemetry.io/otel/metric/syncint64.go index 783fdfba..56667d32 100644 --- a/vendor/go.opentelemetry.io/otel/metric/syncint64.go +++ b/vendor/go.opentelemetry.io/otel/metric/syncint64.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package metric // import "go.opentelemetry.io/otel/metric" @@ -133,7 +144,7 @@ type Int64Histogram interface { Record(ctx context.Context, incr int64, options ...RecordOption) } -// Int64HistogramConfig contains options for synchronous histogram instruments +// Int64HistogramConfig contains options for synchronous counter instruments // that record int64 values. type Int64HistogramConfig struct { description string @@ -172,55 +183,3 @@ func (c Int64HistogramConfig) ExplicitBucketBoundaries() []float64 { type Int64HistogramOption interface { applyInt64Histogram(Int64HistogramConfig) Int64HistogramConfig } - -// Int64Gauge is an instrument that records instantaneous int64 values. -// -// Warning: Methods may be added to this interface in minor releases. See -// package documentation on API implementation for information on how to set -// default behavior for unimplemented methods. -type Int64Gauge interface { - // Users of the interface can ignore this. This embedded type is only used - // by implementations of this interface. See the "API Implementations" - // section of the package documentation for more information. - embedded.Int64Gauge - - // Record records the instantaneous value. - // - // Use the WithAttributeSet (or, if performance is not a concern, - // the WithAttributes) option to include measurement attributes. - Record(ctx context.Context, value int64, options ...RecordOption) -} - -// Int64GaugeConfig contains options for synchronous gauge instruments that -// record int64 values. -type Int64GaugeConfig struct { - description string - unit string -} - -// NewInt64GaugeConfig returns a new [Int64GaugeConfig] with all opts -// applied. -func NewInt64GaugeConfig(opts ...Int64GaugeOption) Int64GaugeConfig { - var config Int64GaugeConfig - for _, o := range opts { - config = o.applyInt64Gauge(config) - } - return config -} - -// Description returns the configured description. -func (c Int64GaugeConfig) Description() string { - return c.description -} - -// Unit returns the configured unit. -func (c Int64GaugeConfig) Unit() string { - return c.unit -} - -// Int64GaugeOption applies options to a [Int64GaugeConfig]. See -// [InstrumentOption] for other options that can be used as a -// Int64GaugeOption. -type Int64GaugeOption interface { - applyInt64Gauge(Int64GaugeConfig) Int64GaugeConfig -} diff --git a/vendor/go.opentelemetry.io/otel/propagation.go b/vendor/go.opentelemetry.io/otel/propagation.go index 2fd94973..d29aaa32 100644 --- a/vendor/go.opentelemetry.io/otel/propagation.go +++ b/vendor/go.opentelemetry.io/otel/propagation.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" diff --git a/vendor/go.opentelemetry.io/otel/propagation/README.md b/vendor/go.opentelemetry.io/otel/propagation/README.md deleted file mode 100644 index e2959ac7..00000000 --- a/vendor/go.opentelemetry.io/otel/propagation/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Propagation - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/propagation)](https://pkg.go.dev/go.opentelemetry.io/otel/propagation) diff --git a/vendor/go.opentelemetry.io/otel/propagation/baggage.go b/vendor/go.opentelemetry.io/otel/propagation/baggage.go index 552263ba..303cdf1c 100644 --- a/vendor/go.opentelemetry.io/otel/propagation/baggage.go +++ b/vendor/go.opentelemetry.io/otel/propagation/baggage.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package propagation // import "go.opentelemetry.io/otel/propagation" diff --git a/vendor/go.opentelemetry.io/otel/propagation/doc.go b/vendor/go.opentelemetry.io/otel/propagation/doc.go index 33a3baf1..c119eb28 100644 --- a/vendor/go.opentelemetry.io/otel/propagation/doc.go +++ b/vendor/go.opentelemetry.io/otel/propagation/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package propagation contains OpenTelemetry context propagators. diff --git a/vendor/go.opentelemetry.io/otel/propagation/propagation.go b/vendor/go.opentelemetry.io/otel/propagation/propagation.go index 8c8286aa..c94438f7 100644 --- a/vendor/go.opentelemetry.io/otel/propagation/propagation.go +++ b/vendor/go.opentelemetry.io/otel/propagation/propagation.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package propagation // import "go.opentelemetry.io/otel/propagation" diff --git a/vendor/go.opentelemetry.io/otel/propagation/trace_context.go b/vendor/go.opentelemetry.io/otel/propagation/trace_context.go index 6870e316..75a8f343 100644 --- a/vendor/go.opentelemetry.io/otel/propagation/trace_context.go +++ b/vendor/go.opentelemetry.io/otel/propagation/trace_context.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package propagation // import "go.opentelemetry.io/otel/propagation" @@ -7,7 +18,7 @@ import ( "context" "encoding/hex" "fmt" - "strings" + "regexp" "go.opentelemetry.io/otel/trace" ) @@ -17,7 +28,6 @@ const ( maxVersion = 254 traceparentHeader = "traceparent" tracestateHeader = "tracestate" - delimiter = "-" ) // TraceContext is a propagator that supports the W3C Trace Context format @@ -31,11 +41,11 @@ const ( type TraceContext struct{} var ( - _ TextMapPropagator = TraceContext{} - versionPart = fmt.Sprintf("%.2X", supportedVersion) + _ TextMapPropagator = TraceContext{} + traceCtxRegExp = regexp.MustCompile("^(?P[0-9a-f]{2})-(?P[a-f0-9]{32})-(?P[a-f0-9]{16})-(?P[a-f0-9]{2})(?:-.*)?$") ) -// Inject injects the trace context from ctx into carrier. +// Inject set tracecontext from the Context into the carrier. func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) { sc := trace.SpanContextFromContext(ctx) if !sc.IsValid() { @@ -49,19 +59,12 @@ func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) { // Clear all flags other than the trace-context supported sampling bit. flags := sc.TraceFlags() & trace.FlagsSampled - var sb strings.Builder - sb.Grow(2 + 32 + 16 + 2 + 3) - _, _ = sb.WriteString(versionPart) - traceID := sc.TraceID() - spanID := sc.SpanID() - flagByte := [1]byte{byte(flags)} - var buf [32]byte - for _, src := range [][]byte{traceID[:], spanID[:], flagByte[:]} { - _ = sb.WriteByte(delimiter[0]) - n := hex.Encode(buf[:], src) - _, _ = sb.Write(buf[:n]) - } - carrier.Set(traceparentHeader, sb.String()) + h := fmt.Sprintf("%.2x-%s-%s-%s", + supportedVersion, + sc.TraceID(), + sc.SpanID(), + flags) + carrier.Set(traceparentHeader, h) } // Extract reads tracecontext from the carrier into a returned Context. @@ -83,8 +86,21 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext { return trace.SpanContext{} } - var ver [1]byte - if !extractPart(ver[:], &h, 2) { + matches := traceCtxRegExp.FindStringSubmatch(h) + + if len(matches) == 0 { + return trace.SpanContext{} + } + + if len(matches) < 5 { // four subgroups plus the overall match + return trace.SpanContext{} + } + + if len(matches[1]) != 2 { + return trace.SpanContext{} + } + ver, err := hex.DecodeString(matches[1]) + if err != nil { return trace.SpanContext{} } version := int(ver[0]) @@ -92,24 +108,36 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext { return trace.SpanContext{} } - var scc trace.SpanContextConfig - if !extractPart(scc.TraceID[:], &h, 32) { + if version == 0 && len(matches) != 5 { // four subgroups plus the overall match + return trace.SpanContext{} + } + + if len(matches[2]) != 32 { return trace.SpanContext{} } - if !extractPart(scc.SpanID[:], &h, 16) { + + var scc trace.SpanContextConfig + + scc.TraceID, err = trace.TraceIDFromHex(matches[2][:32]) + if err != nil { return trace.SpanContext{} } - var opts [1]byte - if !extractPart(opts[:], &h, 2) { + if len(matches[3]) != 16 { return trace.SpanContext{} } - if version == 0 && (h != "" || opts[0] > 2) { - // version 0 not allow extra - // version 0 not allow other flag + scc.SpanID, err = trace.SpanIDFromHex(matches[3]) + if err != nil { return trace.SpanContext{} } + if len(matches[4]) != 2 { + return trace.SpanContext{} + } + opts, err := hex.DecodeString(matches[4]) + if err != nil || len(opts) < 1 || (version == 0 && opts[0] > 2) { + return trace.SpanContext{} + } // Clear all flags other than the trace-context supported sampling bit. scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled @@ -127,29 +155,6 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext { return sc } -// upperHex detect hex is upper case Unicode characters. -func upperHex(v string) bool { - for _, c := range v { - if c >= 'A' && c <= 'F' { - return true - } - } - return false -} - -func extractPart(dst []byte, h *string, n int) bool { - part, left, _ := strings.Cut(*h, delimiter) - *h = left - // hex.Decode decodes unsupported upper-case characters, so exclude explicitly. - if len(part) != n || upperHex(part) { - return false - } - if p, err := hex.Decode(dst, []byte(part)); err != nil || p != n/2 { - return false - } - return true -} - // Fields returns the keys who's values are set with Inject. func (tc TraceContext) Fields() []string { return []string{traceparentHeader, tracestateHeader} diff --git a/vendor/go.opentelemetry.io/otel/renovate.json b/vendor/go.opentelemetry.io/otel/renovate.json deleted file mode 100644 index 8c5ac55c..00000000 --- a/vendor/go.opentelemetry.io/otel/renovate.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ], - "ignorePaths": [], - "labels": ["Skip Changelog", "dependencies"], - "postUpdateOptions" : [ - "gomodTidy" - ], - "packageRules": [ - { - "matchManagers": ["gomod"], - "matchDepTypes": ["indirect"], - "enabled": true - }, - { - "matchFileNames": ["internal/tools/**"], - "matchManagers": ["gomod"], - "matchDepTypes": ["indirect"], - "enabled": false - } - ] -} diff --git a/vendor/go.opentelemetry.io/otel/requirements.txt b/vendor/go.opentelemetry.io/otel/requirements.txt index ab09daf9..e0a43e13 100644 --- a/vendor/go.opentelemetry.io/otel/requirements.txt +++ b/vendor/go.opentelemetry.io/otel/requirements.txt @@ -1 +1 @@ -codespell==2.3.0 +codespell==2.2.6 diff --git a/vendor/go.opentelemetry.io/otel/sdk/README.md b/vendor/go.opentelemetry.io/otel/sdk/README.md deleted file mode 100644 index f81b1576..00000000 --- a/vendor/go.opentelemetry.io/otel/sdk/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SDK - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/sdk)](https://pkg.go.dev/go.opentelemetry.io/otel/sdk) diff --git a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md deleted file mode 100644 index 06e6d868..00000000 --- a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SDK Instrumentation - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/sdk/instrumentation)](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/instrumentation) diff --git a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/doc.go b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/doc.go index a4faa6a0..6e923aca 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/doc.go +++ b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package instrumentation provides types to represent the code libraries that // provide OpenTelemetry instrumentation. These types are used in the diff --git a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/library.go b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/library.go index f4d1857c..39f025a1 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/library.go +++ b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/library.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation" diff --git a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/scope.go b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/scope.go index 72811504..09c6d93f 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/instrumentation/scope.go +++ b/vendor/go.opentelemetry.io/otel/sdk/instrumentation/scope.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation" diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/env/env.go b/vendor/go.opentelemetry.io/otel/sdk/internal/env/env.go index 07923ed8..59dcfab2 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/internal/env/env.go +++ b/vendor/go.opentelemetry.io/otel/sdk/internal/env/env.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package env // import "go.opentelemetry.io/otel/sdk/internal/env" @@ -22,7 +33,7 @@ const ( BatchSpanProcessorMaxQueueSizeKey = "OTEL_BSP_MAX_QUEUE_SIZE" // BatchSpanProcessorMaxExportBatchSizeKey is the maximum batch size (i.e. // 512). Note: it must be less than or equal to - // BatchSpanProcessorMaxQueueSize. + // EnvBatchSpanProcessorMaxQueueSize. BatchSpanProcessorMaxExportBatchSizeKey = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE" // AttributeValueLengthKey is the maximum allowed attribute value size. diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/gen.go b/vendor/go.opentelemetry.io/otel/sdk/internal/gen.go new file mode 100644 index 00000000..bd84f624 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/internal/gen.go @@ -0,0 +1,29 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/sdk/internal" + +//go:generate gotmpl --body=../../internal/shared/matchers/expectation.go.tmpl "--data={}" --out=matchers/expectation.go +//go:generate gotmpl --body=../../internal/shared/matchers/expecter.go.tmpl "--data={}" --out=matchers/expecter.go +//go:generate gotmpl --body=../../internal/shared/matchers/temporal_matcher.go.tmpl "--data={}" --out=matchers/temporal_matcher.go + +//go:generate gotmpl --body=../../internal/shared/internaltest/alignment.go.tmpl "--data={}" --out=internaltest/alignment.go +//go:generate gotmpl --body=../../internal/shared/internaltest/env.go.tmpl "--data={}" --out=internaltest/env.go +//go:generate gotmpl --body=../../internal/shared/internaltest/env_test.go.tmpl "--data={}" --out=internaltest/env_test.go +//go:generate gotmpl --body=../../internal/shared/internaltest/errors.go.tmpl "--data={}" --out=internaltest/errors.go +//go:generate gotmpl --body=../../internal/shared/internaltest/harness.go.tmpl "--data={\"matchersImportPath\": \"go.opentelemetry.io/otel/sdk/internal/matchers\"}" --out=internaltest/harness.go +//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_carrier.go.tmpl "--data={}" --out=internaltest/text_map_carrier.go +//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_carrier_test.go.tmpl "--data={}" --out=internaltest/text_map_carrier_test.go +//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_propagator.go.tmpl "--data={}" --out=internaltest/text_map_propagator.go +//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_propagator_test.go.tmpl "--data={}" --out=internaltest/text_map_propagator_test.go diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/internal.go b/vendor/go.opentelemetry.io/otel/sdk/internal/internal.go new file mode 100644 index 00000000..dfeaaa8c --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/internal/internal.go @@ -0,0 +1,28 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/sdk/internal" + +import "time" + +// MonotonicEndTime returns the end time at present +// but offset from start, monotonically. +// +// The monotonic clock is used in subtractions hence +// the duration since start added back to start gives +// end as a monotonic time. +// See https://golang.org/pkg/time/#hdr-Monotonic_Clocks +func MonotonicEndTime(start time.Time) time.Time { + return start.Add(time.Since(start)) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md b/vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md deleted file mode 100644 index fab61647..00000000 --- a/vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Experimental Features - -The SDK contains features that have not yet stabilized in the OpenTelemetry specification. -These features are added to the OpenTelemetry Go SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback. - -These feature may change in backwards incompatible ways as feedback is applied. -See the [Compatibility and Stability](#compatibility-and-stability) section for more information. - -## Features - -- [Resource](#resource) - -### Resource - -[OpenTelemetry resource semantic conventions] include many attribute definitions that are defined as experimental. -To have experimental semantic conventions be added by [resource detectors] set the `OTEL_GO_X_RESOURCE` environment variable. -The value set must be the case-insensitive string of `"true"` to enable the feature. -All other values are ignored. - - - -[OpenTelemetry resource semantic conventions]: https://opentelemetry.io/docs/specs/semconv/resource/ -[resource detectors]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource#Detector - -#### Examples - -Enable experimental resource semantic conventions. - -```console -export OTEL_GO_X_RESOURCE=true -``` - -Disable experimental resource semantic conventions. - -```console -unset OTEL_GO_X_RESOURCE -``` - -## Compatibility and Stability - -Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../VERSIONING.md). -These features may be removed or modified in successive version releases, including patch versions. - -When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release. -There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version. -If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support. diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go b/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go deleted file mode 100644 index 68d296cb..00000000 --- a/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Package x contains support for OTel SDK experimental features. -// -// This package should only be used for features defined in the specification. -// It should not be used for experiments or new project ideas. -package x // import "go.opentelemetry.io/otel/sdk/internal/x" - -import ( - "os" - "strings" -) - -// Resource is an experimental feature flag that defines if resource detectors -// should be included experimental semantic conventions. -// -// To enable this feature set the OTEL_GO_X_RESOURCE environment variable -// to the case-insensitive string value of "true" (i.e. "True" and "TRUE" -// will also enable this). -var Resource = newFeature("RESOURCE", func(v string) (string, bool) { - if strings.ToLower(v) == "true" { - return v, true - } - return "", false -}) - -// Feature is an experimental feature control flag. It provides a uniform way -// to interact with these feature flags and parse their values. -type Feature[T any] struct { - key string - parse func(v string) (T, bool) -} - -func newFeature[T any](suffix string, parse func(string) (T, bool)) Feature[T] { - const envKeyRoot = "OTEL_GO_X_" - return Feature[T]{ - key: envKeyRoot + suffix, - parse: parse, - } -} - -// Key returns the environment variable key that needs to be set to enable the -// feature. -func (f Feature[T]) Key() string { return f.key } - -// Lookup returns the user configured value for the feature and true if the -// user has enabled the feature. Otherwise, if the feature is not enabled, a -// zero-value and false are returned. -func (f Feature[T]) Lookup() (v T, ok bool) { - // https://github.com/open-telemetry/opentelemetry-specification/blob/62effed618589a0bec416a87e559c0a9d96289bb/specification/configuration/sdk-environment-variables.md#parsing-empty-value - // - // > The SDK MUST interpret an empty value of an environment variable the - // > same way as when the variable is unset. - vRaw := os.Getenv(f.key) - if vRaw == "" { - return v, ok - } - return f.parse(vRaw) -} - -// Enabled returns if the feature is enabled. -func (f Feature[T]) Enabled() bool { - _, ok := f.Lookup() - return ok -} diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/README.md b/vendor/go.opentelemetry.io/otel/sdk/resource/README.md deleted file mode 100644 index 4ad864d7..00000000 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SDK Resource - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/sdk/resource)](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource) diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/auto.go b/vendor/go.opentelemetry.io/otel/sdk/resource/auto.go index 95a61d61..4279013b 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/auto.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/auto.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -30,20 +41,8 @@ type Detector interface { // must never be done outside of a new major release. } -// Detect returns a new [Resource] merged from all the Resources each of the -// detectors produces. Each of the detectors are called sequentially, in the -// order they are passed, merging the produced resource into the previous. -// -// This may return a partial Resource along with an error containing -// [ErrPartialResource] if that error is returned from a detector. It may also -// return a merge-conflicting Resource along with an error containing -// [ErrSchemaURLConflict] if merging Resources from different detectors results -// in a schema URL conflict. It is up to the caller to determine if this -// returned Resource should be used or not. -// -// If one of the detectors returns an error that is not [ErrPartialResource], -// the resource produced by the detector will not be merged and the returned -// error will wrap that detector's error. +// Detect calls all input detectors sequentially and merges each result with the previous one. +// It returns the merged error too. func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) { r := new(Resource) return r, detect(ctx, r, detectors) @@ -51,10 +50,6 @@ func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) { // detect runs all detectors using ctx and merges the result into res. This // assumes res is allocated and not nil, it will panic otherwise. -// -// If the detectors or merging resources produces any errors (i.e. -// [ErrPartialResource] [ErrSchemaURLConflict]), a single error wrapping all of -// these errors will be returned. Otherwise, nil is returned. func detect(ctx context.Context, res *Resource, detectors []Detector) error { var ( r *Resource @@ -83,11 +78,6 @@ func detect(ctx context.Context, res *Resource, detectors []Detector) error { if len(errs) == 0 { return nil } - if errors.Is(errs, ErrSchemaURLConflict) { - // If there has been a merge conflict, ensure the resource has no - // schema URL. - res.schemaURL = "" - } return errs } diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go b/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go index 6ac1cdbf..c63a0dd1 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -9,11 +20,9 @@ import ( "os" "path/filepath" - "github.com/google/uuid" - "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) type ( @@ -38,8 +47,6 @@ type ( } defaultServiceNameDetector struct{} - - defaultServiceInstanceIDDetector struct{} ) var ( @@ -47,7 +54,6 @@ var ( _ Detector = host{} _ Detector = stringDetector{} _ Detector = defaultServiceNameDetector{} - _ Detector = defaultServiceInstanceIDDetector{} ) // Detect returns a *Resource that describes the OpenTelemetry SDK used. @@ -100,19 +106,3 @@ func (defaultServiceNameDetector) Detect(ctx context.Context) (*Resource, error) }, ).Detect(ctx) } - -// Detect implements Detector. -func (defaultServiceInstanceIDDetector) Detect(ctx context.Context) (*Resource, error) { - return StringDetector( - semconv.SchemaURL, - semconv.ServiceInstanceIDKey, - func() (string, error) { - version4Uuid, err := uuid.NewRandom() - if err != nil { - return "", err - } - - return version4Uuid.String(), nil - }, - ).Detect(ctx) -} diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/config.go b/vendor/go.opentelemetry.io/otel/sdk/resource/config.go index 0d6e213d..f263919f 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/config.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/config.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/container.go b/vendor/go.opentelemetry.io/otel/sdk/resource/container.go index 5ecd859a..3d536228 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/container.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/container.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -11,14 +22,14 @@ import ( "os" "regexp" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) type containerIDProvider func() (string, error) var ( containerID containerIDProvider = getContainerIDFromCGroup - cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*[-:])?([0-9a-f]+)(?:\.|\s*$)`) + cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([0-9a-f]+)(?:\.|\s*$)`) ) type cgroupContainerIDDetector struct{} diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/doc.go b/vendor/go.opentelemetry.io/otel/sdk/resource/doc.go index 64939a27..d55a50b0 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/doc.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package resource provides detecting and representing resources. // diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/env.go b/vendor/go.opentelemetry.io/otel/sdk/resource/env.go index 813f0562..e29ae563 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/env.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/env.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -12,7 +23,7 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) const ( diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go index 2d0f6549..fb1ebf2c 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -8,7 +19,7 @@ import ( "errors" "strings" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) type hostIDProvider func() (string, error) diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go index cc8b8938..1778bbac 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build dragonfly || freebsd || netbsd || openbsd || solaris // +build dragonfly freebsd netbsd openbsd solaris diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go index b09fde3b..ba41409b 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go index d9e5d1a8..207acb0e 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build darwin || dragonfly || freebsd || netbsd || openbsd || solaris diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go index f84f1732..410579b8 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build linux // +build linux diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go index 6354b356..721e3ca6 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build linux || dragonfly || freebsd || netbsd || openbsd || solaris diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go index df12c44c..89df9d68 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go @@ -1,8 +1,25 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows -// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows +// +build !darwin +// +build !dragonfly +// +build !freebsd +// +build !linux +// +build !netbsd +// +build !openbsd +// +build !solaris +// +build !windows package resource // import "go.opentelemetry.io/otel/sdk/resource" diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go index 71386e2d..5b431c6e 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build windows // +build windows diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os.go index 8a48ab4f..0cbd5597 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/os.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -8,7 +19,7 @@ import ( "strings" "go.opentelemetry.io/otel/attribute" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) type osDescriptionProvider func() (string, error) diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go index ce455dc5..24ec8579 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go index f537e5ca..c771942d 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build aix || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos // +build aix dragonfly freebsd linux netbsd openbsd solaris zos diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go index a6ff26a4..1c84afc1 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go index a77742b0..3ebcb534 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go @@ -1,8 +1,27 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos -// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows,!zos +// +build !aix +// +build !darwin +// +build !dragonfly +// +build !freebsd +// +build !linux +// +build !netbsd +// +build !openbsd +// +build !solaris +// +build !windows +// +build !zos package resource // import "go.opentelemetry.io/otel/sdk/resource" diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go index 5e3d199d..faad64d8 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/process.go b/vendor/go.opentelemetry.io/otel/sdk/resource/process.go index 085fe68f..ecdd11dd 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/process.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/process.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" @@ -11,7 +22,7 @@ import ( "path/filepath" "runtime" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) type ( diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go b/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go index ad4b50df..176ff106 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go @@ -1,17 +1,26 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package resource // import "go.opentelemetry.io/otel/sdk/resource" import ( "context" "errors" - "fmt" "sync" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/sdk/internal/x" ) // Resource describes an entity about which identifying information @@ -31,20 +40,9 @@ var ( defaultResourceOnce sync.Once ) -// ErrSchemaURLConflict is an error returned when two Resources are merged -// together that contain different, non-empty, schema URLs. -var ErrSchemaURLConflict = errors.New("conflicting Schema URL") +var errMergeConflictSchemaURL = errors.New("cannot merge resource due to conflicting Schema URL") -// New returns a [Resource] built using opts. -// -// This may return a partial Resource along with an error containing -// [ErrPartialResource] if options that provide a [Detector] are used and that -// error is returned from one or more of the Detectors. It may also return a -// merge-conflict Resource along with an error containing -// [ErrSchemaURLConflict] if merging Resources from the opts results in a -// schema URL conflict (see [Resource.Merge] for more information). It is up to -// the caller to determine if this returned Resource should be used or not -// based on these errors. +// New returns a Resource combined from the user-provided detectors. func New(ctx context.Context, opts ...Option) (*Resource, error) { cfg := config{} for _, opt := range opts { @@ -100,7 +98,7 @@ func (r *Resource) String() string { return r.attrs.Encoded(attribute.DefaultEncoder()) } -// MarshalLog is the marshaling function used by the logging system to represent this Resource. +// MarshalLog is the marshaling function used by the logging system to represent this exporter. func (r *Resource) MarshalLog() interface{} { return struct { Attributes attribute.Set @@ -148,29 +146,16 @@ func (r *Resource) Equal(eq *Resource) bool { return r.Equivalent() == eq.Equivalent() } -// Merge creates a new [Resource] by merging a and b. -// -// If there are common keys between a and b, then the value from b will -// overwrite the value from a, even if b's value is empty. -// -// The SchemaURL of the resources will be merged according to the -// [OpenTelemetry specification rules]: +// Merge creates a new resource by combining resource a and b. // -// - If a's schema URL is empty then the returned Resource's schema URL will -// be set to the schema URL of b, -// - Else if b's schema URL is empty then the returned Resource's schema URL -// will be set to the schema URL of a, -// - Else if the schema URLs of a and b are the same then that will be the -// schema URL of the returned Resource, -// - Else this is a merging error. If the resources have different, -// non-empty, schema URLs an error containing [ErrSchemaURLConflict] will -// be returned with the merged Resource. The merged Resource will have an -// empty schema URL. It may be the case that some unintended attributes -// have been overwritten or old semantic conventions persisted in the -// returned Resource. It is up to the caller to determine if this returned -// Resource should be used or not. +// If there are common keys between resource a and b, then the value +// from resource b will overwrite the value from resource a, even +// if resource b's value is empty. // -// [OpenTelemetry specification rules]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge +// The SchemaURL of the resources will be merged according to the spec rules: +// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge +// If the resources have different non-empty schemaURL an empty resource and an error +// will be returned. func Merge(a, b *Resource) (*Resource, error) { if a == nil && b == nil { return Empty(), nil @@ -182,6 +167,19 @@ func Merge(a, b *Resource) (*Resource, error) { return a, nil } + // Merge the schema URL. + var schemaURL string + switch true { + case a.schemaURL == "": + schemaURL = b.schemaURL + case b.schemaURL == "": + schemaURL = a.schemaURL + case a.schemaURL == b.schemaURL: + schemaURL = a.schemaURL + default: + return Empty(), errMergeConflictSchemaURL + } + // Note: 'b' attributes will overwrite 'a' with last-value-wins in attribute.Key() // Meaning this is equivalent to: append(a.Attributes(), b.Attributes()...) mi := attribute.NewMergeIterator(b.Set(), a.Set()) @@ -189,23 +187,8 @@ func Merge(a, b *Resource) (*Resource, error) { for mi.Next() { combine = append(combine, mi.Attribute()) } - - switch { - case a.schemaURL == "": - return NewWithAttributes(b.schemaURL, combine...), nil - case b.schemaURL == "": - return NewWithAttributes(a.schemaURL, combine...), nil - case a.schemaURL == b.schemaURL: - return NewWithAttributes(a.schemaURL, combine...), nil - } - // Return the merged resource with an appropriate error. It is up to - // the user to decide if the returned resource can be used or not. - return NewSchemaless(combine...), fmt.Errorf( - "%w: %s and %s", - ErrSchemaURLConflict, - a.schemaURL, - b.schemaURL, - ) + merged := NewWithAttributes(schemaURL, combine...) + return merged, nil } // Empty returns an instance of Resource with no attributes. It is @@ -219,17 +202,11 @@ func Empty() *Resource { func Default() *Resource { defaultResourceOnce.Do(func() { var err error - defaultDetectors := []Detector{ + defaultResource, err = Detect( + context.Background(), defaultServiceNameDetector{}, fromEnv{}, telemetrySDK{}, - } - if x.Resource.Enabled() { - defaultDetectors = append([]Detector{defaultServiceInstanceIDDetector{}}, defaultDetectors...) - } - defaultResource, err = Detect( - context.Background(), - defaultDetectors..., ) if err != nil { otel.Handle(err) diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/README.md b/vendor/go.opentelemetry.io/otel/sdk/trace/README.md deleted file mode 100644 index f2936e14..00000000 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SDK Trace - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/sdk/trace)](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace) diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go index 1d399a75..c9c7effb 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" @@ -381,7 +392,7 @@ func (bsp *batchSpanProcessor) enqueueBlockOnQueueFull(ctx context.Context, sd R } } -func (bsp *batchSpanProcessor) enqueueDrop(_ context.Context, sd ReadOnlySpan) bool { +func (bsp *batchSpanProcessor) enqueueDrop(ctx context.Context, sd ReadOnlySpan) bool { if !sd.SpanContext().IsSampled() { return false } @@ -395,7 +406,7 @@ func (bsp *batchSpanProcessor) enqueueDrop(_ context.Context, sd ReadOnlySpan) b return false } -// MarshalLog is the marshaling function used by the logging system to represent this Span Processor. +// MarshalLog is the marshaling function used by the logging system to represent this exporter. func (bsp *batchSpanProcessor) MarshalLog() interface{} { return struct { Type string diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go b/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go index 1f60524e..0285e99b 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package trace contains support for OpenTelemetry distributed tracing. diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/event.go b/vendor/go.opentelemetry.io/otel/sdk/trace/event.go index 60a7ed13..1e3b4267 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/event.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/event.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go b/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go index 821c83fa..d1c86e59 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go @@ -1,45 +1,36 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" -import ( - "slices" - "sync" - - "go.opentelemetry.io/otel/internal/global" -) - // evictedQueue is a FIFO queue with a configurable capacity. -type evictedQueue[T any] struct { - queue []T +type evictedQueue struct { + queue []interface{} capacity int droppedCount int - logDropped func() } -func newEvictedQueueEvent(capacity int) evictedQueue[Event] { +func newEvictedQueue(capacity int) evictedQueue { // Do not pre-allocate queue, do this lazily. - return evictedQueue[Event]{ - capacity: capacity, - logDropped: sync.OnceFunc(func() { global.Warn("limit reached: dropping trace trace.Event") }), - } -} - -func newEvictedQueueLink(capacity int) evictedQueue[Link] { - // Do not pre-allocate queue, do this lazily. - return evictedQueue[Link]{ - capacity: capacity, - logDropped: sync.OnceFunc(func() { global.Warn("limit reached: dropping trace trace.Link") }), - } + return evictedQueue{capacity: capacity} } // add adds value to the evictedQueue eq. If eq is at capacity, the oldest // queued value will be discarded and the drop count incremented. -func (eq *evictedQueue[T]) add(value T) { +func (eq *evictedQueue) add(value interface{}) { if eq.capacity == 0 { eq.droppedCount++ - eq.logDropped() return } @@ -48,12 +39,6 @@ func (eq *evictedQueue[T]) add(value T) { copy(eq.queue[:eq.capacity-1], eq.queue[1:]) eq.queue = eq.queue[:eq.capacity-1] eq.droppedCount++ - eq.logDropped() } eq.queue = append(eq.queue, value) } - -// copy returns a copy of the evictedQueue. -func (eq *evictedQueue[T]) copy() []T { - return slices.Clone(eq.queue) -} diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go b/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go index 925bcf99..bba24604 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" @@ -41,12 +52,7 @@ func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.Trace gen.Lock() defer gen.Unlock() sid := trace.SpanID{} - for { - _, _ = gen.randSource.Read(sid[:]) - if sid.IsValid() { - break - } - } + _, _ = gen.randSource.Read(sid[:]) return sid } @@ -56,19 +62,9 @@ func (gen *randomIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace. gen.Lock() defer gen.Unlock() tid := trace.TraceID{} + _, _ = gen.randSource.Read(tid[:]) sid := trace.SpanID{} - for { - _, _ = gen.randSource.Read(tid[:]) - if tid.IsValid() { - break - } - } - for { - _, _ = gen.randSource.Read(sid[:]) - if sid.IsValid() { - break - } - } + _, _ = gen.randSource.Read(sid[:]) return tid, sid } diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/link.go b/vendor/go.opentelemetry.io/otel/sdk/trace/link.go index c03bdc90..19cfea4b 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/link.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/link.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go index 14c2e5be..7d46c4b4 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" @@ -44,7 +55,7 @@ type tracerProviderConfig struct { resource *resource.Resource } -// MarshalLog is the marshaling function used by the logging system to represent this Provider. +// MarshalLog is the marshaling function used by the logging system to represent this exporter. func (cfg tracerProviderConfig) MarshalLog() interface{} { return struct { SpanProcessors []SpanProcessor @@ -291,7 +302,7 @@ func (p *TracerProvider) Shutdown(ctx context.Context) error { retErr = err } else { // Poor man's list of errors - retErr = fmt.Errorf("%w; %w", retErr, err) + retErr = fmt.Errorf("%v; %v", retErr, err) } } } diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go b/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go index d2d1f724..02053b31 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go b/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go index ebb6df6c..a7bc125b 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go index 554111bb..f8770fff 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" @@ -25,10 +36,10 @@ var _ SpanProcessor = (*simpleSpanProcessor)(nil) // send completed spans to the exporter immediately. // // This SpanProcessor is not recommended for production use. The synchronous -// nature of this SpanProcessor makes it good for testing, debugging, or showing -// examples of other features, but it will be slow and have a high computation -// resource usage overhead. The BatchSpanProcessor is recommended for production -// use instead. +// nature of this SpanProcessor make it good for testing, debugging, or +// showing examples of other feature, but it will be slow and have a high +// computation resource usage overhead. The BatchSpanProcessor is recommended +// for production use instead. func NewSimpleSpanProcessor(exporter SpanExporter) SpanProcessor { ssp := &simpleSpanProcessor{ exporter: exporter, @@ -69,10 +80,10 @@ func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error { // // A closure is used to keep reference to the exporter and then the // field is zeroed. This ensures the simpleSpanProcessor is shut down - // before the exporter. This order is important as it avoids a potential - // deadlock. If the exporter shut down operation generates a span, that - // span would need to be exported. Meaning, OnEnd would be called and - // try acquiring the lock that is held here. + // before the exporter. This order is important as it avoids a + // potential deadlock. If the exporter shut down operation generates a + // span, that span would need to be exported. Meaning, OnEnd would be + // called and try acquiring the lock that is held here. ssp.exporterMu.Lock() done, shutdown := stopFunc(ssp.exporter) ssp.exporter = nil @@ -84,15 +95,15 @@ func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error { select { case err = <-done: case <-ctx.Done(): - // It is possible for the exporter to have immediately shut down and - // the context to be done simultaneously. In that case this outer - // select statement will randomly choose a case. This will result in - // a different returned error for similar scenarios. Instead, double - // check if the exporter shut down at the same time and return that - // error if so. This will ensure consistency as well as ensure - // the caller knows the exporter shut down successfully (they can - // already determine if the deadline is expired given they passed - // the context). + // It is possible for the exporter to have immediately shut down + // and the context to be done simultaneously. In that case this + // outer select statement will randomly choose a case. This will + // result in a different returned error for similar scenarios. + // Instead, double check if the exporter shut down at the same + // time and return that error if so. This will ensure consistency + // as well as ensure the caller knows the exporter shut down + // successfully (they can already determine if the deadline is + // expired given they passed the context). select { case err = <-done: default: @@ -108,8 +119,7 @@ func (ssp *simpleSpanProcessor) ForceFlush(context.Context) error { return nil } -// MarshalLog is the marshaling function used by the logging system to represent -// this Span Processor. +// MarshalLog is the marshaling function used by the logging system to represent this Span Processor. func (ssp *simpleSpanProcessor) MarshalLog() interface{} { return struct { Type string diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go b/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go index 32f86279..0349b2f1 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go index ac90f1a2..36dbf677 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" @@ -9,7 +20,6 @@ import ( "reflect" "runtime" rt "runtime/trace" - "slices" "strings" "sync" "time" @@ -17,10 +27,10 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/internal" "go.opentelemetry.io/otel/sdk/resource" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/embedded" ) @@ -137,13 +147,12 @@ type recordingSpan struct { // ReadOnlySpan exported when the span ends. attributes []attribute.KeyValue droppedAttributes int - logDropAttrsOnce sync.Once // events are stored in FIFO queue capped by configured limit. - events evictedQueue[Event] + events evictedQueue // links are stored in FIFO queue capped by configured limit. - links evictedQueue[Link] + links evictedQueue // executionTracerTaskEnd ends the execution tracer span. executionTracerTaskEnd func() @@ -220,7 +229,7 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) { limit := s.tracer.provider.spanLimits.AttributeCountLimit if limit == 0 { // No attributes allowed. - s.addDroppedAttr(len(attributes)) + s.droppedAttributes += len(attributes) return } @@ -233,11 +242,10 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) { // Otherwise, add without deduplication. When attributes are read they // will be deduplicated, optimizing the operation. - s.attributes = slices.Grow(s.attributes, len(s.attributes)+len(attributes)) for _, a := range attributes { if !a.Valid() { // Drop all invalid attributes. - s.addDroppedAttr(1) + s.droppedAttributes++ continue } a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a) @@ -245,22 +253,6 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) { } } -// Declared as a var so tests can override. -var logDropAttrs = func() { - global.Warn("limit reached: dropping trace Span attributes") -} - -// addDroppedAttr adds incr to the count of dropped attributes. -// -// The first, and only the first, time this method is called a warning will be -// logged. -// -// This method assumes s.mu.Lock is held by the caller. -func (s *recordingSpan) addDroppedAttr(incr int) { - s.droppedAttributes += incr - s.logDropAttrsOnce.Do(logDropAttrs) -} - // addOverCapAttrs adds the attributes attrs to the span s while // de-duplicating the attributes of s and attrs and dropping attributes that // exceed the limit. @@ -285,12 +277,10 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) { // Now that s.attributes is deduplicated, adding unique attributes up to // the capacity of s will not over allocate s.attributes. - sum := len(attrs) + len(s.attributes) - s.attributes = slices.Grow(s.attributes, min(sum, limit)) for _, a := range attrs { if !a.Valid() { // Drop all invalid attributes. - s.addDroppedAttr(1) + s.droppedAttributes++ continue } @@ -303,7 +293,7 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) { if len(s.attributes) >= limit { // Do not just drop all of the remaining attributes, make sure // updates are checked and performed. - s.addDroppedAttr(1) + s.droppedAttributes++ } else { a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a) s.attributes = append(s.attributes, a) @@ -384,7 +374,7 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) { // Store the end time as soon as possible to avoid artificially increasing // the span's duration in case some operation below takes a while. - et := monotonicEndTime(s.startTime) + et := internal.MonotonicEndTime(s.startTime) // Do relative expensive check now that we have an end time and see if we // need to do any more processing. @@ -435,16 +425,6 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) { } } -// monotonicEndTime returns the end time at present but offset from start, -// monotonically. -// -// The monotonic clock is used in subtractions hence the duration since start -// added back to start gives end as a monotonic time. See -// https://golang.org/pkg/time/#hdr-Monotonic_Clocks -func monotonicEndTime(start time.Time) time.Time { - return start.Add(time.Since(start)) -} - // RecordError will record err as a span event for this span. An additional call to // SetStatus is required if the Status of the Span should be set to Error, this method // does not change the Span status. If this span is not being recorded or err is nil @@ -612,7 +592,7 @@ func (s *recordingSpan) Links() []Link { if len(s.links.queue) == 0 { return []Link{} } - return s.links.copy() + return s.interfaceArrayToLinksArray() } // Events returns the events of this span. @@ -622,7 +602,7 @@ func (s *recordingSpan) Events() []Event { if len(s.events.queue) == 0 { return []Event{} } - return s.events.copy() + return s.interfaceArrayToEventArray() } // Status returns the status of this span. @@ -656,12 +636,8 @@ func (s *recordingSpan) Resource() *resource.Resource { return s.tracer.provider.resource } -func (s *recordingSpan) AddLink(link trace.Link) { - if !s.IsRecording() { - return - } - if !link.SpanContext.IsValid() && len(link.Attributes) == 0 && - link.SpanContext.TraceState().Len() == 0 { +func (s *recordingSpan) addLink(link trace.Link) { + if !s.IsRecording() || !link.SpanContext.IsValid() { return } @@ -744,16 +720,32 @@ func (s *recordingSpan) snapshot() ReadOnlySpan { } sd.droppedAttributeCount = s.droppedAttributes if len(s.events.queue) > 0 { - sd.events = s.events.copy() + sd.events = s.interfaceArrayToEventArray() sd.droppedEventCount = s.events.droppedCount } if len(s.links.queue) > 0 { - sd.links = s.links.copy() + sd.links = s.interfaceArrayToLinksArray() sd.droppedLinkCount = s.links.droppedCount } return &sd } +func (s *recordingSpan) interfaceArrayToLinksArray() []Link { + linkArr := make([]Link, 0) + for _, value := range s.links.queue { + linkArr = append(linkArr, value.(Link)) + } + return linkArr +} + +func (s *recordingSpan) interfaceArrayToEventArray() []Event { + eventArr := make([]Event, 0) + for _, value := range s.events.queue { + eventArr = append(eventArr, value.(Event)) + } + return eventArr +} + func (s *recordingSpan) addChild() { if !s.IsRecording() { return @@ -818,9 +810,6 @@ func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {} // AddEvent does nothing. func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {} -// AddLink does nothing. -func (nonRecordingSpan) AddLink(trace.Link) {} - // SetName does nothing. func (nonRecordingSpan) SetName(string) {} diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span_exporter.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span_exporter.go index 6bdda3d9..c9bd52f7 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span_exporter.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span_exporter.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go index bec5e209..aa4d4221 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span_processor.go index af7f9177..9c53657a 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span_processor.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span_processor.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go b/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go index 43419d3b..301e1a7a 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" @@ -132,13 +143,13 @@ func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr Sa spanKind: trace.ValidateSpanKind(config.SpanKind()), name: name, startTime: startTime, - events: newEvictedQueueEvent(tr.provider.spanLimits.EventCountLimit), - links: newEvictedQueueLink(tr.provider.spanLimits.LinkCountLimit), + events: newEvictedQueue(tr.provider.spanLimits.EventCountLimit), + links: newEvictedQueue(tr.provider.spanLimits.LinkCountLimit), tracer: tr, } for _, l := range config.Links() { - s.AddLink(l) + s.addLink(l) } s.SetAttributes(sr.Attributes...) diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/version.go b/vendor/go.opentelemetry.io/otel/sdk/trace/version.go index b84dd2c5..d3457ed1 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/version.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/version.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/sdk/trace" diff --git a/vendor/go.opentelemetry.io/otel/sdk/version.go b/vendor/go.opentelemetry.io/otel/sdk/version.go index 33d065a7..422d4c96 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/version.go +++ b/vendor/go.opentelemetry.io/otel/sdk/version.go @@ -1,9 +1,20 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package sdk // import "go.opentelemetry.io/otel/sdk" // Version is the current release version of the OpenTelemetry SDK in use. func Version() string { - return "1.28.0" + return "1.21.0" } diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/attribute_group.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/attribute_group.go new file mode 100644 index 00000000..e6cf8951 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/attribute_group.go @@ -0,0 +1,1877 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated from semantic convention specification. DO NOT EDIT. + +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" + +import "go.opentelemetry.io/otel/attribute" + +// These attributes may be used to describe the client in a connection-based +// network interaction where there is one side that initiates the connection +// (the client is the side that initiates the connection). This covers all TCP +// network interactions since TCP is connection-based and one side initiates +// the connection (an exception is made for peer-to-peer communication over TCP +// where the "user-facing" surface of the protocol / API does not expose a +// clear notion of client and server). This also covers UDP network +// interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) +// and DNS. +const ( + // ClientAddressKey is the attribute Key conforming to the "client.address" + // semantic conventions. It represents the client address - unix domain + // socket name, IPv4 or IPv6 address. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '/tmp/my.sock', '10.1.2.80' + // Note: When observed from the server side, and when communicating through + // an intermediary, `client.address` SHOULD represent client address behind + // any intermediaries (e.g. proxies) if it's available. + ClientAddressKey = attribute.Key("client.address") + + // ClientPortKey is the attribute Key conforming to the "client.port" + // semantic conventions. It represents the client port number + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 65123 + // Note: When observed from the server side, and when communicating through + // an intermediary, `client.port` SHOULD represent client port behind any + // intermediaries (e.g. proxies) if it's available. + ClientPortKey = attribute.Key("client.port") + + // ClientSocketAddressKey is the attribute Key conforming to the + // "client.socket.address" semantic conventions. It represents the + // immediate client peer address - unix domain socket name, IPv4 or IPv6 + // address. + // + // Type: string + // RequirementLevel: Recommended (If different than `client.address`.) + // Stability: stable + // Examples: '/tmp/my.sock', '127.0.0.1' + ClientSocketAddressKey = attribute.Key("client.socket.address") + + // ClientSocketPortKey is the attribute Key conforming to the + // "client.socket.port" semantic conventions. It represents the immediate + // client peer port number + // + // Type: int + // RequirementLevel: Recommended (If different than `client.port`.) + // Stability: stable + // Examples: 35555 + ClientSocketPortKey = attribute.Key("client.socket.port") +) + +// ClientAddress returns an attribute KeyValue conforming to the +// "client.address" semantic conventions. It represents the client address - +// unix domain socket name, IPv4 or IPv6 address. +func ClientAddress(val string) attribute.KeyValue { + return ClientAddressKey.String(val) +} + +// ClientPort returns an attribute KeyValue conforming to the "client.port" +// semantic conventions. It represents the client port number +func ClientPort(val int) attribute.KeyValue { + return ClientPortKey.Int(val) +} + +// ClientSocketAddress returns an attribute KeyValue conforming to the +// "client.socket.address" semantic conventions. It represents the immediate +// client peer address - unix domain socket name, IPv4 or IPv6 address. +func ClientSocketAddress(val string) attribute.KeyValue { + return ClientSocketAddressKey.String(val) +} + +// ClientSocketPort returns an attribute KeyValue conforming to the +// "client.socket.port" semantic conventions. It represents the immediate +// client peer port number +func ClientSocketPort(val int) attribute.KeyValue { + return ClientSocketPortKey.Int(val) +} + +// Describes deprecated HTTP attributes. +const ( + // HTTPMethodKey is the attribute Key conforming to the "http.method" + // semantic conventions. It represents the deprecated, use + // `http.request.method` instead. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'GET', 'POST', 'HEAD' + HTTPMethodKey = attribute.Key("http.method") + + // HTTPStatusCodeKey is the attribute Key conforming to the + // "http.status_code" semantic conventions. It represents the deprecated, + // use `http.response.status_code` instead. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 200 + HTTPStatusCodeKey = attribute.Key("http.status_code") + + // HTTPSchemeKey is the attribute Key conforming to the "http.scheme" + // semantic conventions. It represents the deprecated, use `url.scheme` + // instead. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'http', 'https' + HTTPSchemeKey = attribute.Key("http.scheme") + + // HTTPURLKey is the attribute Key conforming to the "http.url" semantic + // conventions. It represents the deprecated, use `url.full` instead. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'https://www.foo.bar/search?q=OpenTelemetry#SemConv' + HTTPURLKey = attribute.Key("http.url") + + // HTTPTargetKey is the attribute Key conforming to the "http.target" + // semantic conventions. It represents the deprecated, use `url.path` and + // `url.query` instead. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: '/search?q=OpenTelemetry#SemConv' + HTTPTargetKey = attribute.Key("http.target") + + // HTTPRequestContentLengthKey is the attribute Key conforming to the + // "http.request_content_length" semantic conventions. It represents the + // deprecated, use `http.request.body.size` instead. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 3495 + HTTPRequestContentLengthKey = attribute.Key("http.request_content_length") + + // HTTPResponseContentLengthKey is the attribute Key conforming to the + // "http.response_content_length" semantic conventions. It represents the + // deprecated, use `http.response.body.size` instead. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 3495 + HTTPResponseContentLengthKey = attribute.Key("http.response_content_length") +) + +// HTTPMethod returns an attribute KeyValue conforming to the "http.method" +// semantic conventions. It represents the deprecated, use +// `http.request.method` instead. +func HTTPMethod(val string) attribute.KeyValue { + return HTTPMethodKey.String(val) +} + +// HTTPStatusCode returns an attribute KeyValue conforming to the +// "http.status_code" semantic conventions. It represents the deprecated, use +// `http.response.status_code` instead. +func HTTPStatusCode(val int) attribute.KeyValue { + return HTTPStatusCodeKey.Int(val) +} + +// HTTPScheme returns an attribute KeyValue conforming to the "http.scheme" +// semantic conventions. It represents the deprecated, use `url.scheme` +// instead. +func HTTPScheme(val string) attribute.KeyValue { + return HTTPSchemeKey.String(val) +} + +// HTTPURL returns an attribute KeyValue conforming to the "http.url" +// semantic conventions. It represents the deprecated, use `url.full` instead. +func HTTPURL(val string) attribute.KeyValue { + return HTTPURLKey.String(val) +} + +// HTTPTarget returns an attribute KeyValue conforming to the "http.target" +// semantic conventions. It represents the deprecated, use `url.path` and +// `url.query` instead. +func HTTPTarget(val string) attribute.KeyValue { + return HTTPTargetKey.String(val) +} + +// HTTPRequestContentLength returns an attribute KeyValue conforming to the +// "http.request_content_length" semantic conventions. It represents the +// deprecated, use `http.request.body.size` instead. +func HTTPRequestContentLength(val int) attribute.KeyValue { + return HTTPRequestContentLengthKey.Int(val) +} + +// HTTPResponseContentLength returns an attribute KeyValue conforming to the +// "http.response_content_length" semantic conventions. It represents the +// deprecated, use `http.response.body.size` instead. +func HTTPResponseContentLength(val int) attribute.KeyValue { + return HTTPResponseContentLengthKey.Int(val) +} + +// These attributes may be used for any network related operation. +const ( + // NetSockPeerNameKey is the attribute Key conforming to the + // "net.sock.peer.name" semantic conventions. It represents the deprecated, + // use `server.socket.domain` on client spans. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: '/var/my.sock' + NetSockPeerNameKey = attribute.Key("net.sock.peer.name") + + // NetSockPeerAddrKey is the attribute Key conforming to the + // "net.sock.peer.addr" semantic conventions. It represents the deprecated, + // use `server.socket.address` on client spans and `client.socket.address` + // on server spans. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: '192.168.0.1' + NetSockPeerAddrKey = attribute.Key("net.sock.peer.addr") + + // NetSockPeerPortKey is the attribute Key conforming to the + // "net.sock.peer.port" semantic conventions. It represents the deprecated, + // use `server.socket.port` on client spans and `client.socket.port` on + // server spans. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 65531 + NetSockPeerPortKey = attribute.Key("net.sock.peer.port") + + // NetPeerNameKey is the attribute Key conforming to the "net.peer.name" + // semantic conventions. It represents the deprecated, use `server.address` + // on client spans and `client.address` on server spans. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'example.com' + NetPeerNameKey = attribute.Key("net.peer.name") + + // NetPeerPortKey is the attribute Key conforming to the "net.peer.port" + // semantic conventions. It represents the deprecated, use `server.port` on + // client spans and `client.port` on server spans. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 8080 + NetPeerPortKey = attribute.Key("net.peer.port") + + // NetHostNameKey is the attribute Key conforming to the "net.host.name" + // semantic conventions. It represents the deprecated, use + // `server.address`. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'example.com' + NetHostNameKey = attribute.Key("net.host.name") + + // NetHostPortKey is the attribute Key conforming to the "net.host.port" + // semantic conventions. It represents the deprecated, use `server.port`. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 8080 + NetHostPortKey = attribute.Key("net.host.port") + + // NetSockHostAddrKey is the attribute Key conforming to the + // "net.sock.host.addr" semantic conventions. It represents the deprecated, + // use `server.socket.address`. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: '/var/my.sock' + NetSockHostAddrKey = attribute.Key("net.sock.host.addr") + + // NetSockHostPortKey is the attribute Key conforming to the + // "net.sock.host.port" semantic conventions. It represents the deprecated, + // use `server.socket.port`. + // + // Type: int + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 8080 + NetSockHostPortKey = attribute.Key("net.sock.host.port") + + // NetTransportKey is the attribute Key conforming to the "net.transport" + // semantic conventions. It represents the deprecated, use + // `network.transport`. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: deprecated + NetTransportKey = attribute.Key("net.transport") + + // NetProtocolNameKey is the attribute Key conforming to the + // "net.protocol.name" semantic conventions. It represents the deprecated, + // use `network.protocol.name`. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'amqp', 'http', 'mqtt' + NetProtocolNameKey = attribute.Key("net.protocol.name") + + // NetProtocolVersionKey is the attribute Key conforming to the + // "net.protocol.version" semantic conventions. It represents the + // deprecated, use `network.protocol.version`. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: '3.1.1' + NetProtocolVersionKey = attribute.Key("net.protocol.version") + + // NetSockFamilyKey is the attribute Key conforming to the + // "net.sock.family" semantic conventions. It represents the deprecated, + // use `network.transport` and `network.type`. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: deprecated + NetSockFamilyKey = attribute.Key("net.sock.family") +) + +var ( + // ip_tcp + NetTransportTCP = NetTransportKey.String("ip_tcp") + // ip_udp + NetTransportUDP = NetTransportKey.String("ip_udp") + // Named or anonymous pipe + NetTransportPipe = NetTransportKey.String("pipe") + // In-process communication + NetTransportInProc = NetTransportKey.String("inproc") + // Something else (non IP-based) + NetTransportOther = NetTransportKey.String("other") +) + +var ( + // IPv4 address + NetSockFamilyInet = NetSockFamilyKey.String("inet") + // IPv6 address + NetSockFamilyInet6 = NetSockFamilyKey.String("inet6") + // Unix domain socket path + NetSockFamilyUnix = NetSockFamilyKey.String("unix") +) + +// NetSockPeerName returns an attribute KeyValue conforming to the +// "net.sock.peer.name" semantic conventions. It represents the deprecated, use +// `server.socket.domain` on client spans. +func NetSockPeerName(val string) attribute.KeyValue { + return NetSockPeerNameKey.String(val) +} + +// NetSockPeerAddr returns an attribute KeyValue conforming to the +// "net.sock.peer.addr" semantic conventions. It represents the deprecated, use +// `server.socket.address` on client spans and `client.socket.address` on +// server spans. +func NetSockPeerAddr(val string) attribute.KeyValue { + return NetSockPeerAddrKey.String(val) +} + +// NetSockPeerPort returns an attribute KeyValue conforming to the +// "net.sock.peer.port" semantic conventions. It represents the deprecated, use +// `server.socket.port` on client spans and `client.socket.port` on server +// spans. +func NetSockPeerPort(val int) attribute.KeyValue { + return NetSockPeerPortKey.Int(val) +} + +// NetPeerName returns an attribute KeyValue conforming to the +// "net.peer.name" semantic conventions. It represents the deprecated, use +// `server.address` on client spans and `client.address` on server spans. +func NetPeerName(val string) attribute.KeyValue { + return NetPeerNameKey.String(val) +} + +// NetPeerPort returns an attribute KeyValue conforming to the +// "net.peer.port" semantic conventions. It represents the deprecated, use +// `server.port` on client spans and `client.port` on server spans. +func NetPeerPort(val int) attribute.KeyValue { + return NetPeerPortKey.Int(val) +} + +// NetHostName returns an attribute KeyValue conforming to the +// "net.host.name" semantic conventions. It represents the deprecated, use +// `server.address`. +func NetHostName(val string) attribute.KeyValue { + return NetHostNameKey.String(val) +} + +// NetHostPort returns an attribute KeyValue conforming to the +// "net.host.port" semantic conventions. It represents the deprecated, use +// `server.port`. +func NetHostPort(val int) attribute.KeyValue { + return NetHostPortKey.Int(val) +} + +// NetSockHostAddr returns an attribute KeyValue conforming to the +// "net.sock.host.addr" semantic conventions. It represents the deprecated, use +// `server.socket.address`. +func NetSockHostAddr(val string) attribute.KeyValue { + return NetSockHostAddrKey.String(val) +} + +// NetSockHostPort returns an attribute KeyValue conforming to the +// "net.sock.host.port" semantic conventions. It represents the deprecated, use +// `server.socket.port`. +func NetSockHostPort(val int) attribute.KeyValue { + return NetSockHostPortKey.Int(val) +} + +// NetProtocolName returns an attribute KeyValue conforming to the +// "net.protocol.name" semantic conventions. It represents the deprecated, use +// `network.protocol.name`. +func NetProtocolName(val string) attribute.KeyValue { + return NetProtocolNameKey.String(val) +} + +// NetProtocolVersion returns an attribute KeyValue conforming to the +// "net.protocol.version" semantic conventions. It represents the deprecated, +// use `network.protocol.version`. +func NetProtocolVersion(val string) attribute.KeyValue { + return NetProtocolVersionKey.String(val) +} + +// These attributes may be used to describe the receiver of a network +// exchange/packet. These should be used when there is no client/server +// relationship between the two sides, or when that relationship is unknown. +// This covers low-level network interactions (e.g. packet tracing) where you +// don't know if there was a connection or which side initiated it. This also +// covers unidirectional UDP flows and peer-to-peer communication where the +// "user-facing" surface of the protocol / API does not expose a clear notion +// of client and server. +const ( + // DestinationDomainKey is the attribute Key conforming to the + // "destination.domain" semantic conventions. It represents the domain name + // of the destination system. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'foo.example.com' + // Note: This value may be a host name, a fully qualified domain name, or + // another host naming format. + DestinationDomainKey = attribute.Key("destination.domain") + + // DestinationAddressKey is the attribute Key conforming to the + // "destination.address" semantic conventions. It represents the peer + // address, for example IP address or UNIX socket name. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '10.5.3.2' + DestinationAddressKey = attribute.Key("destination.address") + + // DestinationPortKey is the attribute Key conforming to the + // "destination.port" semantic conventions. It represents the peer port + // number + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 3389, 2888 + DestinationPortKey = attribute.Key("destination.port") +) + +// DestinationDomain returns an attribute KeyValue conforming to the +// "destination.domain" semantic conventions. It represents the domain name of +// the destination system. +func DestinationDomain(val string) attribute.KeyValue { + return DestinationDomainKey.String(val) +} + +// DestinationAddress returns an attribute KeyValue conforming to the +// "destination.address" semantic conventions. It represents the peer address, +// for example IP address or UNIX socket name. +func DestinationAddress(val string) attribute.KeyValue { + return DestinationAddressKey.String(val) +} + +// DestinationPort returns an attribute KeyValue conforming to the +// "destination.port" semantic conventions. It represents the peer port number +func DestinationPort(val int) attribute.KeyValue { + return DestinationPortKey.Int(val) +} + +// Describes HTTP attributes. +const ( + // HTTPRequestMethodKey is the attribute Key conforming to the + // "http.request.method" semantic conventions. It represents the hTTP + // request method. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + // Examples: 'GET', 'POST', 'HEAD' + // Note: HTTP request method value SHOULD be "known" to the + // instrumentation. + // By default, this convention defines "known" methods as the ones listed + // in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + // and the PATCH method defined in + // [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + // + // If the HTTP request method is not known to instrumentation, it MUST set + // the `http.request.method` attribute to `_OTHER` and, except if reporting + // a metric, MUST + // set the exact method received in the request line as value of the + // `http.request.method_original` attribute. + // + // If the HTTP instrumentation could end up converting valid HTTP request + // methods to `_OTHER`, then it MUST provide a way to override + // the list of known HTTP methods. If this override is done via environment + // variable, then the environment variable MUST be named + // OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated + // list of case-sensitive known HTTP methods + // (this list MUST be a full override of the default known method, it is + // not a list of known methods in addition to the defaults). + // + // HTTP method names are case-sensitive and `http.request.method` attribute + // value MUST match a known HTTP method name exactly. + // Instrumentations for specific web frameworks that consider HTTP methods + // to be case insensitive, SHOULD populate a canonical equivalent. + // Tracing instrumentations that do so, MUST also set + // `http.request.method_original` to the original value. + HTTPRequestMethodKey = attribute.Key("http.request.method") + + // HTTPResponseStatusCodeKey is the attribute Key conforming to the + // "http.response.status_code" semantic conventions. It represents the + // [HTTP response status + // code](https://tools.ietf.org/html/rfc7231#section-6). + // + // Type: int + // RequirementLevel: ConditionallyRequired (If and only if one was + // received/sent.) + // Stability: stable + // Examples: 200 + HTTPResponseStatusCodeKey = attribute.Key("http.response.status_code") +) + +var ( + // CONNECT method + HTTPRequestMethodConnect = HTTPRequestMethodKey.String("CONNECT") + // DELETE method + HTTPRequestMethodDelete = HTTPRequestMethodKey.String("DELETE") + // GET method + HTTPRequestMethodGet = HTTPRequestMethodKey.String("GET") + // HEAD method + HTTPRequestMethodHead = HTTPRequestMethodKey.String("HEAD") + // OPTIONS method + HTTPRequestMethodOptions = HTTPRequestMethodKey.String("OPTIONS") + // PATCH method + HTTPRequestMethodPatch = HTTPRequestMethodKey.String("PATCH") + // POST method + HTTPRequestMethodPost = HTTPRequestMethodKey.String("POST") + // PUT method + HTTPRequestMethodPut = HTTPRequestMethodKey.String("PUT") + // TRACE method + HTTPRequestMethodTrace = HTTPRequestMethodKey.String("TRACE") + // Any HTTP method that the instrumentation has no prior knowledge of + HTTPRequestMethodOther = HTTPRequestMethodKey.String("_OTHER") +) + +// HTTPResponseStatusCode returns an attribute KeyValue conforming to the +// "http.response.status_code" semantic conventions. It represents the [HTTP +// response status code](https://tools.ietf.org/html/rfc7231#section-6). +func HTTPResponseStatusCode(val int) attribute.KeyValue { + return HTTPResponseStatusCodeKey.Int(val) +} + +// HTTP Server attributes +const ( + // HTTPRouteKey is the attribute Key conforming to the "http.route" + // semantic conventions. It represents the matched route (path template in + // the format used by the respective server framework). See note below + // + // Type: string + // RequirementLevel: ConditionallyRequired (If and only if it's available) + // Stability: stable + // Examples: '/users/:userID?', '{controller}/{action}/{id?}' + // Note: MUST NOT be populated when this is not supported by the HTTP + // server framework as the route attribute should have low-cardinality and + // the URI path can NOT substitute it. + // SHOULD include the [application + // root](/docs/http/http-spans.md#http-server-definitions) if there is one. + HTTPRouteKey = attribute.Key("http.route") +) + +// HTTPRoute returns an attribute KeyValue conforming to the "http.route" +// semantic conventions. It represents the matched route (path template in the +// format used by the respective server framework). See note below +func HTTPRoute(val string) attribute.KeyValue { + return HTTPRouteKey.String(val) +} + +// Attributes for Events represented using Log Records. +const ( + // EventNameKey is the attribute Key conforming to the "event.name" + // semantic conventions. It represents the name identifies the event. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'click', 'exception' + EventNameKey = attribute.Key("event.name") + + // EventDomainKey is the attribute Key conforming to the "event.domain" + // semantic conventions. It represents the domain identifies the business + // context for the events. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + // Note: Events across different domains may have same `event.name`, yet be + // unrelated events. + EventDomainKey = attribute.Key("event.domain") +) + +var ( + // Events from browser apps + EventDomainBrowser = EventDomainKey.String("browser") + // Events from mobile apps + EventDomainDevice = EventDomainKey.String("device") + // Events from Kubernetes + EventDomainK8S = EventDomainKey.String("k8s") +) + +// EventName returns an attribute KeyValue conforming to the "event.name" +// semantic conventions. It represents the name identifies the event. +func EventName(val string) attribute.KeyValue { + return EventNameKey.String(val) +} + +// The attributes described in this section are rather generic. They may be +// used in any Log Record they apply to. +const ( + // LogRecordUIDKey is the attribute Key conforming to the "log.record.uid" + // semantic conventions. It represents a unique identifier for the Log + // Record. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '01ARZ3NDEKTSV4RRFFQ69G5FAV' + // Note: If an id is provided, other log records with the same id will be + // considered duplicates and can be removed safely. This means, that two + // distinguishable log records MUST have different values. + // The id MAY be an [Universally Unique Lexicographically Sortable + // Identifier (ULID)](https://github.com/ulid/spec), but other identifiers + // (e.g. UUID) may be used as needed. + LogRecordUIDKey = attribute.Key("log.record.uid") +) + +// LogRecordUID returns an attribute KeyValue conforming to the +// "log.record.uid" semantic conventions. It represents a unique identifier for +// the Log Record. +func LogRecordUID(val string) attribute.KeyValue { + return LogRecordUIDKey.String(val) +} + +// Describes Log attributes +const ( + // LogIostreamKey is the attribute Key conforming to the "log.iostream" + // semantic conventions. It represents the stream associated with the log. + // See below for a list of well-known values. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + LogIostreamKey = attribute.Key("log.iostream") +) + +var ( + // Logs from stdout stream + LogIostreamStdout = LogIostreamKey.String("stdout") + // Events from stderr stream + LogIostreamStderr = LogIostreamKey.String("stderr") +) + +// A file to which log was emitted. +const ( + // LogFileNameKey is the attribute Key conforming to the "log.file.name" + // semantic conventions. It represents the basename of the file. + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'audit.log' + LogFileNameKey = attribute.Key("log.file.name") + + // LogFilePathKey is the attribute Key conforming to the "log.file.path" + // semantic conventions. It represents the full path to the file. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '/var/log/mysql/audit.log' + LogFilePathKey = attribute.Key("log.file.path") + + // LogFileNameResolvedKey is the attribute Key conforming to the + // "log.file.name_resolved" semantic conventions. It represents the + // basename of the file, with symlinks resolved. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'uuid.log' + LogFileNameResolvedKey = attribute.Key("log.file.name_resolved") + + // LogFilePathResolvedKey is the attribute Key conforming to the + // "log.file.path_resolved" semantic conventions. It represents the full + // path to the file, with symlinks resolved. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '/var/lib/docker/uuid.log' + LogFilePathResolvedKey = attribute.Key("log.file.path_resolved") +) + +// LogFileName returns an attribute KeyValue conforming to the +// "log.file.name" semantic conventions. It represents the basename of the +// file. +func LogFileName(val string) attribute.KeyValue { + return LogFileNameKey.String(val) +} + +// LogFilePath returns an attribute KeyValue conforming to the +// "log.file.path" semantic conventions. It represents the full path to the +// file. +func LogFilePath(val string) attribute.KeyValue { + return LogFilePathKey.String(val) +} + +// LogFileNameResolved returns an attribute KeyValue conforming to the +// "log.file.name_resolved" semantic conventions. It represents the basename of +// the file, with symlinks resolved. +func LogFileNameResolved(val string) attribute.KeyValue { + return LogFileNameResolvedKey.String(val) +} + +// LogFilePathResolved returns an attribute KeyValue conforming to the +// "log.file.path_resolved" semantic conventions. It represents the full path +// to the file, with symlinks resolved. +func LogFilePathResolved(val string) attribute.KeyValue { + return LogFilePathResolvedKey.String(val) +} + +// Describes JVM memory metric attributes. +const ( + // TypeKey is the attribute Key conforming to the "type" semantic + // conventions. It represents the type of memory. + // + // Type: Enum + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'heap', 'non_heap' + TypeKey = attribute.Key("type") + + // PoolKey is the attribute Key conforming to the "pool" semantic + // conventions. It represents the name of the memory pool. + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'G1 Old Gen', 'G1 Eden space', 'G1 Survivor Space' + // Note: Pool names are generally obtained via + // [MemoryPoolMXBean#getName()](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryPoolMXBean.html#getName()). + PoolKey = attribute.Key("pool") +) + +var ( + // Heap memory + TypeHeap = TypeKey.String("heap") + // Non-heap memory + TypeNonHeap = TypeKey.String("non_heap") +) + +// Pool returns an attribute KeyValue conforming to the "pool" semantic +// conventions. It represents the name of the memory pool. +func Pool(val string) attribute.KeyValue { + return PoolKey.String(val) +} + +// These attributes may be used to describe the server in a connection-based +// network interaction where there is one side that initiates the connection +// (the client is the side that initiates the connection). This covers all TCP +// network interactions since TCP is connection-based and one side initiates +// the connection (an exception is made for peer-to-peer communication over TCP +// where the "user-facing" surface of the protocol / API does not expose a +// clear notion of client and server). This also covers UDP network +// interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) +// and DNS. +const ( + // ServerAddressKey is the attribute Key conforming to the "server.address" + // semantic conventions. It represents the logical server hostname, matches + // server FQDN if available, and IP or socket address if FQDN is not known. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'example.com' + ServerAddressKey = attribute.Key("server.address") + + // ServerPortKey is the attribute Key conforming to the "server.port" + // semantic conventions. It represents the logical server port number + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 80, 8080, 443 + ServerPortKey = attribute.Key("server.port") + + // ServerSocketDomainKey is the attribute Key conforming to the + // "server.socket.domain" semantic conventions. It represents the domain + // name of an immediate peer. + // + // Type: string + // RequirementLevel: Recommended (If different than `server.address`.) + // Stability: stable + // Examples: 'proxy.example.com' + // Note: Typically observed from the client side, and represents a proxy or + // other intermediary domain name. + ServerSocketDomainKey = attribute.Key("server.socket.domain") + + // ServerSocketAddressKey is the attribute Key conforming to the + // "server.socket.address" semantic conventions. It represents the physical + // server IP address or Unix socket address. If set from the client, should + // simply use the socket's peer address, and not attempt to find any actual + // server IP (i.e., if set from client, this may represent some proxy + // server instead of the logical server). + // + // Type: string + // RequirementLevel: Recommended (If different than `server.address`.) + // Stability: stable + // Examples: '10.5.3.2' + ServerSocketAddressKey = attribute.Key("server.socket.address") + + // ServerSocketPortKey is the attribute Key conforming to the + // "server.socket.port" semantic conventions. It represents the physical + // server port. + // + // Type: int + // RequirementLevel: Recommended (If different than `server.port`.) + // Stability: stable + // Examples: 16456 + ServerSocketPortKey = attribute.Key("server.socket.port") +) + +// ServerAddress returns an attribute KeyValue conforming to the +// "server.address" semantic conventions. It represents the logical server +// hostname, matches server FQDN if available, and IP or socket address if FQDN +// is not known. +func ServerAddress(val string) attribute.KeyValue { + return ServerAddressKey.String(val) +} + +// ServerPort returns an attribute KeyValue conforming to the "server.port" +// semantic conventions. It represents the logical server port number +func ServerPort(val int) attribute.KeyValue { + return ServerPortKey.Int(val) +} + +// ServerSocketDomain returns an attribute KeyValue conforming to the +// "server.socket.domain" semantic conventions. It represents the domain name +// of an immediate peer. +func ServerSocketDomain(val string) attribute.KeyValue { + return ServerSocketDomainKey.String(val) +} + +// ServerSocketAddress returns an attribute KeyValue conforming to the +// "server.socket.address" semantic conventions. It represents the physical +// server IP address or Unix socket address. If set from the client, should +// simply use the socket's peer address, and not attempt to find any actual +// server IP (i.e., if set from client, this may represent some proxy server +// instead of the logical server). +func ServerSocketAddress(val string) attribute.KeyValue { + return ServerSocketAddressKey.String(val) +} + +// ServerSocketPort returns an attribute KeyValue conforming to the +// "server.socket.port" semantic conventions. It represents the physical server +// port. +func ServerSocketPort(val int) attribute.KeyValue { + return ServerSocketPortKey.Int(val) +} + +// These attributes may be used to describe the sender of a network +// exchange/packet. These should be used when there is no client/server +// relationship between the two sides, or when that relationship is unknown. +// This covers low-level network interactions (e.g. packet tracing) where you +// don't know if there was a connection or which side initiated it. This also +// covers unidirectional UDP flows and peer-to-peer communication where the +// "user-facing" surface of the protocol / API does not expose a clear notion +// of client and server. +const ( + // SourceDomainKey is the attribute Key conforming to the "source.domain" + // semantic conventions. It represents the domain name of the source + // system. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'foo.example.com' + // Note: This value may be a host name, a fully qualified domain name, or + // another host naming format. + SourceDomainKey = attribute.Key("source.domain") + + // SourceAddressKey is the attribute Key conforming to the "source.address" + // semantic conventions. It represents the source address, for example IP + // address or Unix socket name. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '10.5.3.2' + SourceAddressKey = attribute.Key("source.address") + + // SourcePortKey is the attribute Key conforming to the "source.port" + // semantic conventions. It represents the source port number + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 3389, 2888 + SourcePortKey = attribute.Key("source.port") +) + +// SourceDomain returns an attribute KeyValue conforming to the +// "source.domain" semantic conventions. It represents the domain name of the +// source system. +func SourceDomain(val string) attribute.KeyValue { + return SourceDomainKey.String(val) +} + +// SourceAddress returns an attribute KeyValue conforming to the +// "source.address" semantic conventions. It represents the source address, for +// example IP address or Unix socket name. +func SourceAddress(val string) attribute.KeyValue { + return SourceAddressKey.String(val) +} + +// SourcePort returns an attribute KeyValue conforming to the "source.port" +// semantic conventions. It represents the source port number +func SourcePort(val int) attribute.KeyValue { + return SourcePortKey.Int(val) +} + +// These attributes may be used for any network related operation. +const ( + // NetworkTransportKey is the attribute Key conforming to the + // "network.transport" semantic conventions. It represents the [OSI + // Transport Layer](https://osi-model.com/transport-layer/) or + // [Inter-process Communication + // method](https://en.wikipedia.org/wiki/Inter-process_communication). The + // value SHOULD be normalized to lowercase. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Examples: 'tcp', 'udp' + NetworkTransportKey = attribute.Key("network.transport") + + // NetworkTypeKey is the attribute Key conforming to the "network.type" + // semantic conventions. It represents the [OSI Network + // Layer](https://osi-model.com/network-layer/) or non-OSI equivalent. The + // value SHOULD be normalized to lowercase. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Examples: 'ipv4', 'ipv6' + NetworkTypeKey = attribute.Key("network.type") + + // NetworkProtocolNameKey is the attribute Key conforming to the + // "network.protocol.name" semantic conventions. It represents the [OSI + // Application Layer](https://osi-model.com/application-layer/) or non-OSI + // equivalent. The value SHOULD be normalized to lowercase. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'amqp', 'http', 'mqtt' + NetworkProtocolNameKey = attribute.Key("network.protocol.name") + + // NetworkProtocolVersionKey is the attribute Key conforming to the + // "network.protocol.version" semantic conventions. It represents the + // version of the application layer protocol used. See note below. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '3.1.1' + // Note: `network.protocol.version` refers to the version of the protocol + // used and might be different from the protocol client's version. If the + // HTTP client used has a version of `0.27.2`, but sends HTTP version + // `1.1`, this attribute should be set to `1.1`. + NetworkProtocolVersionKey = attribute.Key("network.protocol.version") +) + +var ( + // TCP + NetworkTransportTCP = NetworkTransportKey.String("tcp") + // UDP + NetworkTransportUDP = NetworkTransportKey.String("udp") + // Named or anonymous pipe. See note below + NetworkTransportPipe = NetworkTransportKey.String("pipe") + // Unix domain socket + NetworkTransportUnix = NetworkTransportKey.String("unix") +) + +var ( + // IPv4 + NetworkTypeIpv4 = NetworkTypeKey.String("ipv4") + // IPv6 + NetworkTypeIpv6 = NetworkTypeKey.String("ipv6") +) + +// NetworkProtocolName returns an attribute KeyValue conforming to the +// "network.protocol.name" semantic conventions. It represents the [OSI +// Application Layer](https://osi-model.com/application-layer/) or non-OSI +// equivalent. The value SHOULD be normalized to lowercase. +func NetworkProtocolName(val string) attribute.KeyValue { + return NetworkProtocolNameKey.String(val) +} + +// NetworkProtocolVersion returns an attribute KeyValue conforming to the +// "network.protocol.version" semantic conventions. It represents the version +// of the application layer protocol used. See note below. +func NetworkProtocolVersion(val string) attribute.KeyValue { + return NetworkProtocolVersionKey.String(val) +} + +// These attributes may be used for any network related operation. +const ( + // NetworkConnectionTypeKey is the attribute Key conforming to the + // "network.connection.type" semantic conventions. It represents the + // internet connection type. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Examples: 'wifi' + NetworkConnectionTypeKey = attribute.Key("network.connection.type") + + // NetworkConnectionSubtypeKey is the attribute Key conforming to the + // "network.connection.subtype" semantic conventions. It represents the + // this describes more details regarding the connection.type. It may be the + // type of cell technology connection, but it could be used for describing + // details about a wifi connection. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Examples: 'LTE' + NetworkConnectionSubtypeKey = attribute.Key("network.connection.subtype") + + // NetworkCarrierNameKey is the attribute Key conforming to the + // "network.carrier.name" semantic conventions. It represents the name of + // the mobile carrier. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'sprint' + NetworkCarrierNameKey = attribute.Key("network.carrier.name") + + // NetworkCarrierMccKey is the attribute Key conforming to the + // "network.carrier.mcc" semantic conventions. It represents the mobile + // carrier country code. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '310' + NetworkCarrierMccKey = attribute.Key("network.carrier.mcc") + + // NetworkCarrierMncKey is the attribute Key conforming to the + // "network.carrier.mnc" semantic conventions. It represents the mobile + // carrier network code. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '001' + NetworkCarrierMncKey = attribute.Key("network.carrier.mnc") + + // NetworkCarrierIccKey is the attribute Key conforming to the + // "network.carrier.icc" semantic conventions. It represents the ISO 3166-1 + // alpha-2 2-character country code associated with the mobile carrier + // network. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'DE' + NetworkCarrierIccKey = attribute.Key("network.carrier.icc") +) + +var ( + // wifi + NetworkConnectionTypeWifi = NetworkConnectionTypeKey.String("wifi") + // wired + NetworkConnectionTypeWired = NetworkConnectionTypeKey.String("wired") + // cell + NetworkConnectionTypeCell = NetworkConnectionTypeKey.String("cell") + // unavailable + NetworkConnectionTypeUnavailable = NetworkConnectionTypeKey.String("unavailable") + // unknown + NetworkConnectionTypeUnknown = NetworkConnectionTypeKey.String("unknown") +) + +var ( + // GPRS + NetworkConnectionSubtypeGprs = NetworkConnectionSubtypeKey.String("gprs") + // EDGE + NetworkConnectionSubtypeEdge = NetworkConnectionSubtypeKey.String("edge") + // UMTS + NetworkConnectionSubtypeUmts = NetworkConnectionSubtypeKey.String("umts") + // CDMA + NetworkConnectionSubtypeCdma = NetworkConnectionSubtypeKey.String("cdma") + // EVDO Rel. 0 + NetworkConnectionSubtypeEvdo0 = NetworkConnectionSubtypeKey.String("evdo_0") + // EVDO Rev. A + NetworkConnectionSubtypeEvdoA = NetworkConnectionSubtypeKey.String("evdo_a") + // CDMA2000 1XRTT + NetworkConnectionSubtypeCdma20001xrtt = NetworkConnectionSubtypeKey.String("cdma2000_1xrtt") + // HSDPA + NetworkConnectionSubtypeHsdpa = NetworkConnectionSubtypeKey.String("hsdpa") + // HSUPA + NetworkConnectionSubtypeHsupa = NetworkConnectionSubtypeKey.String("hsupa") + // HSPA + NetworkConnectionSubtypeHspa = NetworkConnectionSubtypeKey.String("hspa") + // IDEN + NetworkConnectionSubtypeIden = NetworkConnectionSubtypeKey.String("iden") + // EVDO Rev. B + NetworkConnectionSubtypeEvdoB = NetworkConnectionSubtypeKey.String("evdo_b") + // LTE + NetworkConnectionSubtypeLte = NetworkConnectionSubtypeKey.String("lte") + // EHRPD + NetworkConnectionSubtypeEhrpd = NetworkConnectionSubtypeKey.String("ehrpd") + // HSPAP + NetworkConnectionSubtypeHspap = NetworkConnectionSubtypeKey.String("hspap") + // GSM + NetworkConnectionSubtypeGsm = NetworkConnectionSubtypeKey.String("gsm") + // TD-SCDMA + NetworkConnectionSubtypeTdScdma = NetworkConnectionSubtypeKey.String("td_scdma") + // IWLAN + NetworkConnectionSubtypeIwlan = NetworkConnectionSubtypeKey.String("iwlan") + // 5G NR (New Radio) + NetworkConnectionSubtypeNr = NetworkConnectionSubtypeKey.String("nr") + // 5G NRNSA (New Radio Non-Standalone) + NetworkConnectionSubtypeNrnsa = NetworkConnectionSubtypeKey.String("nrnsa") + // LTE CA + NetworkConnectionSubtypeLteCa = NetworkConnectionSubtypeKey.String("lte_ca") +) + +// NetworkCarrierName returns an attribute KeyValue conforming to the +// "network.carrier.name" semantic conventions. It represents the name of the +// mobile carrier. +func NetworkCarrierName(val string) attribute.KeyValue { + return NetworkCarrierNameKey.String(val) +} + +// NetworkCarrierMcc returns an attribute KeyValue conforming to the +// "network.carrier.mcc" semantic conventions. It represents the mobile carrier +// country code. +func NetworkCarrierMcc(val string) attribute.KeyValue { + return NetworkCarrierMccKey.String(val) +} + +// NetworkCarrierMnc returns an attribute KeyValue conforming to the +// "network.carrier.mnc" semantic conventions. It represents the mobile carrier +// network code. +func NetworkCarrierMnc(val string) attribute.KeyValue { + return NetworkCarrierMncKey.String(val) +} + +// NetworkCarrierIcc returns an attribute KeyValue conforming to the +// "network.carrier.icc" semantic conventions. It represents the ISO 3166-1 +// alpha-2 2-character country code associated with the mobile carrier network. +func NetworkCarrierIcc(val string) attribute.KeyValue { + return NetworkCarrierIccKey.String(val) +} + +// Semantic conventions for HTTP client and server Spans. +const ( + // HTTPRequestMethodOriginalKey is the attribute Key conforming to the + // "http.request.method_original" semantic conventions. It represents the + // original HTTP method sent by the client in the request line. + // + // Type: string + // RequirementLevel: ConditionallyRequired (If and only if it's different + // than `http.request.method`.) + // Stability: stable + // Examples: 'GeT', 'ACL', 'foo' + HTTPRequestMethodOriginalKey = attribute.Key("http.request.method_original") + + // HTTPRequestBodySizeKey is the attribute Key conforming to the + // "http.request.body.size" semantic conventions. It represents the size of + // the request payload body in bytes. This is the number of bytes + // transferred excluding headers and is often, but not always, present as + // the + // [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) + // header. For requests using transport encoding, this should be the + // compressed size. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 3495 + HTTPRequestBodySizeKey = attribute.Key("http.request.body.size") + + // HTTPResponseBodySizeKey is the attribute Key conforming to the + // "http.response.body.size" semantic conventions. It represents the size + // of the response payload body in bytes. This is the number of bytes + // transferred excluding headers and is often, but not always, present as + // the + // [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) + // header. For requests using transport encoding, this should be the + // compressed size. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 3495 + HTTPResponseBodySizeKey = attribute.Key("http.response.body.size") +) + +// HTTPRequestMethodOriginal returns an attribute KeyValue conforming to the +// "http.request.method_original" semantic conventions. It represents the +// original HTTP method sent by the client in the request line. +func HTTPRequestMethodOriginal(val string) attribute.KeyValue { + return HTTPRequestMethodOriginalKey.String(val) +} + +// HTTPRequestBodySize returns an attribute KeyValue conforming to the +// "http.request.body.size" semantic conventions. It represents the size of the +// request payload body in bytes. This is the number of bytes transferred +// excluding headers and is often, but not always, present as the +// [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) +// header. For requests using transport encoding, this should be the compressed +// size. +func HTTPRequestBodySize(val int) attribute.KeyValue { + return HTTPRequestBodySizeKey.Int(val) +} + +// HTTPResponseBodySize returns an attribute KeyValue conforming to the +// "http.response.body.size" semantic conventions. It represents the size of +// the response payload body in bytes. This is the number of bytes transferred +// excluding headers and is often, but not always, present as the +// [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) +// header. For requests using transport encoding, this should be the compressed +// size. +func HTTPResponseBodySize(val int) attribute.KeyValue { + return HTTPResponseBodySizeKey.Int(val) +} + +// Semantic convention describing per-message attributes populated on messaging +// spans or links. +const ( + // MessagingMessageIDKey is the attribute Key conforming to the + // "messaging.message.id" semantic conventions. It represents a value used + // by the messaging system as an identifier for the message, represented as + // a string. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '452a7c7c7c7048c2f887f61572b18fc2' + MessagingMessageIDKey = attribute.Key("messaging.message.id") + + // MessagingMessageConversationIDKey is the attribute Key conforming to the + // "messaging.message.conversation_id" semantic conventions. It represents + // the [conversation ID](#conversations) identifying the conversation to + // which the message belongs, represented as a string. Sometimes called + // "Correlation ID". + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'MyConversationID' + MessagingMessageConversationIDKey = attribute.Key("messaging.message.conversation_id") + + // MessagingMessagePayloadSizeBytesKey is the attribute Key conforming to + // the "messaging.message.payload_size_bytes" semantic conventions. It + // represents the (uncompressed) size of the message payload in bytes. Also + // use this attribute if it is unknown whether the compressed or + // uncompressed payload size is reported. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 2738 + MessagingMessagePayloadSizeBytesKey = attribute.Key("messaging.message.payload_size_bytes") + + // MessagingMessagePayloadCompressedSizeBytesKey is the attribute Key + // conforming to the "messaging.message.payload_compressed_size_bytes" + // semantic conventions. It represents the compressed size of the message + // payload in bytes. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 2048 + MessagingMessagePayloadCompressedSizeBytesKey = attribute.Key("messaging.message.payload_compressed_size_bytes") +) + +// MessagingMessageID returns an attribute KeyValue conforming to the +// "messaging.message.id" semantic conventions. It represents a value used by +// the messaging system as an identifier for the message, represented as a +// string. +func MessagingMessageID(val string) attribute.KeyValue { + return MessagingMessageIDKey.String(val) +} + +// MessagingMessageConversationID returns an attribute KeyValue conforming +// to the "messaging.message.conversation_id" semantic conventions. It +// represents the [conversation ID](#conversations) identifying the +// conversation to which the message belongs, represented as a string. +// Sometimes called "Correlation ID". +func MessagingMessageConversationID(val string) attribute.KeyValue { + return MessagingMessageConversationIDKey.String(val) +} + +// MessagingMessagePayloadSizeBytes returns an attribute KeyValue conforming +// to the "messaging.message.payload_size_bytes" semantic conventions. It +// represents the (uncompressed) size of the message payload in bytes. Also use +// this attribute if it is unknown whether the compressed or uncompressed +// payload size is reported. +func MessagingMessagePayloadSizeBytes(val int) attribute.KeyValue { + return MessagingMessagePayloadSizeBytesKey.Int(val) +} + +// MessagingMessagePayloadCompressedSizeBytes returns an attribute KeyValue +// conforming to the "messaging.message.payload_compressed_size_bytes" semantic +// conventions. It represents the compressed size of the message payload in +// bytes. +func MessagingMessagePayloadCompressedSizeBytes(val int) attribute.KeyValue { + return MessagingMessagePayloadCompressedSizeBytesKey.Int(val) +} + +// Semantic convention for attributes that describe messaging destination on +// broker +const ( + // MessagingDestinationNameKey is the attribute Key conforming to the + // "messaging.destination.name" semantic conventions. It represents the + // message destination name + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'MyQueue', 'MyTopic' + // Note: Destination name SHOULD uniquely identify a specific queue, topic + // or other entity within the broker. If + // the broker does not have such notion, the destination name SHOULD + // uniquely identify the broker. + MessagingDestinationNameKey = attribute.Key("messaging.destination.name") + + // MessagingDestinationTemplateKey is the attribute Key conforming to the + // "messaging.destination.template" semantic conventions. It represents the + // low cardinality representation of the messaging destination name + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '/customers/{customerID}' + // Note: Destination names could be constructed from templates. An example + // would be a destination name involving a user name or product id. + // Although the destination name in this case is of high cardinality, the + // underlying template is of low cardinality and can be effectively used + // for grouping and aggregation. + MessagingDestinationTemplateKey = attribute.Key("messaging.destination.template") + + // MessagingDestinationTemporaryKey is the attribute Key conforming to the + // "messaging.destination.temporary" semantic conventions. It represents a + // boolean that is true if the message destination is temporary and might + // not exist anymore after messages are processed. + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + MessagingDestinationTemporaryKey = attribute.Key("messaging.destination.temporary") + + // MessagingDestinationAnonymousKey is the attribute Key conforming to the + // "messaging.destination.anonymous" semantic conventions. It represents a + // boolean that is true if the message destination is anonymous (could be + // unnamed or have auto-generated name). + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + MessagingDestinationAnonymousKey = attribute.Key("messaging.destination.anonymous") +) + +// MessagingDestinationName returns an attribute KeyValue conforming to the +// "messaging.destination.name" semantic conventions. It represents the message +// destination name +func MessagingDestinationName(val string) attribute.KeyValue { + return MessagingDestinationNameKey.String(val) +} + +// MessagingDestinationTemplate returns an attribute KeyValue conforming to +// the "messaging.destination.template" semantic conventions. It represents the +// low cardinality representation of the messaging destination name +func MessagingDestinationTemplate(val string) attribute.KeyValue { + return MessagingDestinationTemplateKey.String(val) +} + +// MessagingDestinationTemporary returns an attribute KeyValue conforming to +// the "messaging.destination.temporary" semantic conventions. It represents a +// boolean that is true if the message destination is temporary and might not +// exist anymore after messages are processed. +func MessagingDestinationTemporary(val bool) attribute.KeyValue { + return MessagingDestinationTemporaryKey.Bool(val) +} + +// MessagingDestinationAnonymous returns an attribute KeyValue conforming to +// the "messaging.destination.anonymous" semantic conventions. It represents a +// boolean that is true if the message destination is anonymous (could be +// unnamed or have auto-generated name). +func MessagingDestinationAnonymous(val bool) attribute.KeyValue { + return MessagingDestinationAnonymousKey.Bool(val) +} + +// Attributes for RabbitMQ +const ( + // MessagingRabbitmqDestinationRoutingKeyKey is the attribute Key + // conforming to the "messaging.rabbitmq.destination.routing_key" semantic + // conventions. It represents the rabbitMQ message routing key. + // + // Type: string + // RequirementLevel: ConditionallyRequired (If not empty.) + // Stability: stable + // Examples: 'myKey' + MessagingRabbitmqDestinationRoutingKeyKey = attribute.Key("messaging.rabbitmq.destination.routing_key") +) + +// MessagingRabbitmqDestinationRoutingKey returns an attribute KeyValue +// conforming to the "messaging.rabbitmq.destination.routing_key" semantic +// conventions. It represents the rabbitMQ message routing key. +func MessagingRabbitmqDestinationRoutingKey(val string) attribute.KeyValue { + return MessagingRabbitmqDestinationRoutingKeyKey.String(val) +} + +// Attributes for Apache Kafka +const ( + // MessagingKafkaMessageKeyKey is the attribute Key conforming to the + // "messaging.kafka.message.key" semantic conventions. It represents the + // message keys in Kafka are used for grouping alike messages to ensure + // they're processed on the same partition. They differ from + // `messaging.message.id` in that they're not unique. If the key is `null`, + // the attribute MUST NOT be set. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'myKey' + // Note: If the key type is not string, it's string representation has to + // be supplied for the attribute. If the key has no unambiguous, canonical + // string form, don't include its value. + MessagingKafkaMessageKeyKey = attribute.Key("messaging.kafka.message.key") + + // MessagingKafkaConsumerGroupKey is the attribute Key conforming to the + // "messaging.kafka.consumer.group" semantic conventions. It represents the + // name of the Kafka Consumer Group that is handling the message. Only + // applies to consumers, not producers. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'my-group' + MessagingKafkaConsumerGroupKey = attribute.Key("messaging.kafka.consumer.group") + + // MessagingKafkaDestinationPartitionKey is the attribute Key conforming to + // the "messaging.kafka.destination.partition" semantic conventions. It + // represents the partition the message is sent to. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 2 + MessagingKafkaDestinationPartitionKey = attribute.Key("messaging.kafka.destination.partition") + + // MessagingKafkaMessageOffsetKey is the attribute Key conforming to the + // "messaging.kafka.message.offset" semantic conventions. It represents the + // offset of a record in the corresponding Kafka partition. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 42 + MessagingKafkaMessageOffsetKey = attribute.Key("messaging.kafka.message.offset") + + // MessagingKafkaMessageTombstoneKey is the attribute Key conforming to the + // "messaging.kafka.message.tombstone" semantic conventions. It represents + // a boolean that is true if the message is a tombstone. + // + // Type: boolean + // RequirementLevel: ConditionallyRequired (If value is `true`. When + // missing, the value is assumed to be `false`.) + // Stability: stable + MessagingKafkaMessageTombstoneKey = attribute.Key("messaging.kafka.message.tombstone") +) + +// MessagingKafkaMessageKey returns an attribute KeyValue conforming to the +// "messaging.kafka.message.key" semantic conventions. It represents the +// message keys in Kafka are used for grouping alike messages to ensure they're +// processed on the same partition. They differ from `messaging.message.id` in +// that they're not unique. If the key is `null`, the attribute MUST NOT be +// set. +func MessagingKafkaMessageKey(val string) attribute.KeyValue { + return MessagingKafkaMessageKeyKey.String(val) +} + +// MessagingKafkaConsumerGroup returns an attribute KeyValue conforming to +// the "messaging.kafka.consumer.group" semantic conventions. It represents the +// name of the Kafka Consumer Group that is handling the message. Only applies +// to consumers, not producers. +func MessagingKafkaConsumerGroup(val string) attribute.KeyValue { + return MessagingKafkaConsumerGroupKey.String(val) +} + +// MessagingKafkaDestinationPartition returns an attribute KeyValue +// conforming to the "messaging.kafka.destination.partition" semantic +// conventions. It represents the partition the message is sent to. +func MessagingKafkaDestinationPartition(val int) attribute.KeyValue { + return MessagingKafkaDestinationPartitionKey.Int(val) +} + +// MessagingKafkaMessageOffset returns an attribute KeyValue conforming to +// the "messaging.kafka.message.offset" semantic conventions. It represents the +// offset of a record in the corresponding Kafka partition. +func MessagingKafkaMessageOffset(val int) attribute.KeyValue { + return MessagingKafkaMessageOffsetKey.Int(val) +} + +// MessagingKafkaMessageTombstone returns an attribute KeyValue conforming +// to the "messaging.kafka.message.tombstone" semantic conventions. It +// represents a boolean that is true if the message is a tombstone. +func MessagingKafkaMessageTombstone(val bool) attribute.KeyValue { + return MessagingKafkaMessageTombstoneKey.Bool(val) +} + +// Attributes for Apache RocketMQ +const ( + // MessagingRocketmqNamespaceKey is the attribute Key conforming to the + // "messaging.rocketmq.namespace" semantic conventions. It represents the + // namespace of RocketMQ resources, resources in different namespaces are + // individual. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'myNamespace' + MessagingRocketmqNamespaceKey = attribute.Key("messaging.rocketmq.namespace") + + // MessagingRocketmqClientGroupKey is the attribute Key conforming to the + // "messaging.rocketmq.client_group" semantic conventions. It represents + // the name of the RocketMQ producer/consumer group that is handling the + // message. The client type is identified by the SpanKind. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'myConsumerGroup' + MessagingRocketmqClientGroupKey = attribute.Key("messaging.rocketmq.client_group") + + // MessagingRocketmqMessageDeliveryTimestampKey is the attribute Key + // conforming to the "messaging.rocketmq.message.delivery_timestamp" + // semantic conventions. It represents the timestamp in milliseconds that + // the delay message is expected to be delivered to consumer. + // + // Type: int + // RequirementLevel: ConditionallyRequired (If the message type is delay + // and delay time level is not specified.) + // Stability: stable + // Examples: 1665987217045 + MessagingRocketmqMessageDeliveryTimestampKey = attribute.Key("messaging.rocketmq.message.delivery_timestamp") + + // MessagingRocketmqMessageDelayTimeLevelKey is the attribute Key + // conforming to the "messaging.rocketmq.message.delay_time_level" semantic + // conventions. It represents the delay time level for delay message, which + // determines the message delay time. + // + // Type: int + // RequirementLevel: ConditionallyRequired (If the message type is delay + // and delivery timestamp is not specified.) + // Stability: stable + // Examples: 3 + MessagingRocketmqMessageDelayTimeLevelKey = attribute.Key("messaging.rocketmq.message.delay_time_level") + + // MessagingRocketmqMessageGroupKey is the attribute Key conforming to the + // "messaging.rocketmq.message.group" semantic conventions. It represents + // the it is essential for FIFO message. Messages that belong to the same + // message group are always processed one by one within the same consumer + // group. + // + // Type: string + // RequirementLevel: ConditionallyRequired (If the message type is FIFO.) + // Stability: stable + // Examples: 'myMessageGroup' + MessagingRocketmqMessageGroupKey = attribute.Key("messaging.rocketmq.message.group") + + // MessagingRocketmqMessageTypeKey is the attribute Key conforming to the + // "messaging.rocketmq.message.type" semantic conventions. It represents + // the type of message. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + MessagingRocketmqMessageTypeKey = attribute.Key("messaging.rocketmq.message.type") + + // MessagingRocketmqMessageTagKey is the attribute Key conforming to the + // "messaging.rocketmq.message.tag" semantic conventions. It represents the + // secondary classifier of message besides topic. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'tagA' + MessagingRocketmqMessageTagKey = attribute.Key("messaging.rocketmq.message.tag") + + // MessagingRocketmqMessageKeysKey is the attribute Key conforming to the + // "messaging.rocketmq.message.keys" semantic conventions. It represents + // the key(s) of message, another way to mark message besides message id. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: 'keyA', 'keyB' + MessagingRocketmqMessageKeysKey = attribute.Key("messaging.rocketmq.message.keys") + + // MessagingRocketmqConsumptionModelKey is the attribute Key conforming to + // the "messaging.rocketmq.consumption_model" semantic conventions. It + // represents the model of message consumption. This only applies to + // consumer spans. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + MessagingRocketmqConsumptionModelKey = attribute.Key("messaging.rocketmq.consumption_model") +) + +var ( + // Normal message + MessagingRocketmqMessageTypeNormal = MessagingRocketmqMessageTypeKey.String("normal") + // FIFO message + MessagingRocketmqMessageTypeFifo = MessagingRocketmqMessageTypeKey.String("fifo") + // Delay message + MessagingRocketmqMessageTypeDelay = MessagingRocketmqMessageTypeKey.String("delay") + // Transaction message + MessagingRocketmqMessageTypeTransaction = MessagingRocketmqMessageTypeKey.String("transaction") +) + +var ( + // Clustering consumption model + MessagingRocketmqConsumptionModelClustering = MessagingRocketmqConsumptionModelKey.String("clustering") + // Broadcasting consumption model + MessagingRocketmqConsumptionModelBroadcasting = MessagingRocketmqConsumptionModelKey.String("broadcasting") +) + +// MessagingRocketmqNamespace returns an attribute KeyValue conforming to +// the "messaging.rocketmq.namespace" semantic conventions. It represents the +// namespace of RocketMQ resources, resources in different namespaces are +// individual. +func MessagingRocketmqNamespace(val string) attribute.KeyValue { + return MessagingRocketmqNamespaceKey.String(val) +} + +// MessagingRocketmqClientGroup returns an attribute KeyValue conforming to +// the "messaging.rocketmq.client_group" semantic conventions. It represents +// the name of the RocketMQ producer/consumer group that is handling the +// message. The client type is identified by the SpanKind. +func MessagingRocketmqClientGroup(val string) attribute.KeyValue { + return MessagingRocketmqClientGroupKey.String(val) +} + +// MessagingRocketmqMessageDeliveryTimestamp returns an attribute KeyValue +// conforming to the "messaging.rocketmq.message.delivery_timestamp" semantic +// conventions. It represents the timestamp in milliseconds that the delay +// message is expected to be delivered to consumer. +func MessagingRocketmqMessageDeliveryTimestamp(val int) attribute.KeyValue { + return MessagingRocketmqMessageDeliveryTimestampKey.Int(val) +} + +// MessagingRocketmqMessageDelayTimeLevel returns an attribute KeyValue +// conforming to the "messaging.rocketmq.message.delay_time_level" semantic +// conventions. It represents the delay time level for delay message, which +// determines the message delay time. +func MessagingRocketmqMessageDelayTimeLevel(val int) attribute.KeyValue { + return MessagingRocketmqMessageDelayTimeLevelKey.Int(val) +} + +// MessagingRocketmqMessageGroup returns an attribute KeyValue conforming to +// the "messaging.rocketmq.message.group" semantic conventions. It represents +// the it is essential for FIFO message. Messages that belong to the same +// message group are always processed one by one within the same consumer +// group. +func MessagingRocketmqMessageGroup(val string) attribute.KeyValue { + return MessagingRocketmqMessageGroupKey.String(val) +} + +// MessagingRocketmqMessageTag returns an attribute KeyValue conforming to +// the "messaging.rocketmq.message.tag" semantic conventions. It represents the +// secondary classifier of message besides topic. +func MessagingRocketmqMessageTag(val string) attribute.KeyValue { + return MessagingRocketmqMessageTagKey.String(val) +} + +// MessagingRocketmqMessageKeys returns an attribute KeyValue conforming to +// the "messaging.rocketmq.message.keys" semantic conventions. It represents +// the key(s) of message, another way to mark message besides message id. +func MessagingRocketmqMessageKeys(val ...string) attribute.KeyValue { + return MessagingRocketmqMessageKeysKey.StringSlice(val) +} + +// Attributes describing URL. +const ( + // URLSchemeKey is the attribute Key conforming to the "url.scheme" + // semantic conventions. It represents the [URI + // scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component + // identifying the used protocol. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'https', 'ftp', 'telnet' + URLSchemeKey = attribute.Key("url.scheme") + + // URLFullKey is the attribute Key conforming to the "url.full" semantic + // conventions. It represents the absolute URL describing a network + // resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'https://www.foo.bar/search?q=OpenTelemetry#SemConv', + // '//localhost' + // Note: For network calls, URL usually has + // `scheme://host[:port][path][?query][#fragment]` format, where the + // fragment is not transmitted over HTTP, but if it is known, it should be + // included nevertheless. + // `url.full` MUST NOT contain credentials passed via URL in form of + // `https://username:password@www.example.com/`. In such case username and + // password should be redacted and attribute's value should be + // `https://REDACTED:REDACTED@www.example.com/`. + // `url.full` SHOULD capture the absolute URL when it is available (or can + // be reconstructed) and SHOULD NOT be validated or modified except for + // sanitizing purposes. + URLFullKey = attribute.Key("url.full") + + // URLPathKey is the attribute Key conforming to the "url.path" semantic + // conventions. It represents the [URI + // path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '/search' + // Note: When missing, the value is assumed to be `/` + URLPathKey = attribute.Key("url.path") + + // URLQueryKey is the attribute Key conforming to the "url.query" semantic + // conventions. It represents the [URI + // query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'q=OpenTelemetry' + // Note: Sensitive content provided in query string SHOULD be scrubbed when + // instrumentations can identify it. + URLQueryKey = attribute.Key("url.query") + + // URLFragmentKey is the attribute Key conforming to the "url.fragment" + // semantic conventions. It represents the [URI + // fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'SemConv' + URLFragmentKey = attribute.Key("url.fragment") +) + +// URLScheme returns an attribute KeyValue conforming to the "url.scheme" +// semantic conventions. It represents the [URI +// scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component +// identifying the used protocol. +func URLScheme(val string) attribute.KeyValue { + return URLSchemeKey.String(val) +} + +// URLFull returns an attribute KeyValue conforming to the "url.full" +// semantic conventions. It represents the absolute URL describing a network +// resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) +func URLFull(val string) attribute.KeyValue { + return URLFullKey.String(val) +} + +// URLPath returns an attribute KeyValue conforming to the "url.path" +// semantic conventions. It represents the [URI +// path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component +func URLPath(val string) attribute.KeyValue { + return URLPathKey.String(val) +} + +// URLQuery returns an attribute KeyValue conforming to the "url.query" +// semantic conventions. It represents the [URI +// query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component +func URLQuery(val string) attribute.KeyValue { + return URLQueryKey.String(val) +} + +// URLFragment returns an attribute KeyValue conforming to the +// "url.fragment" semantic conventions. It represents the [URI +// fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component +func URLFragment(val string) attribute.KeyValue { + return URLFragmentKey.String(val) +} + +// Describes user-agent attributes. +const ( + // UserAgentOriginalKey is the attribute Key conforming to the + // "user_agent.original" semantic conventions. It represents the value of + // the [HTTP + // User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) + // header sent by the client. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'CERN-LineMode/2.15 libwww/2.17b3' + UserAgentOriginalKey = attribute.Key("user_agent.original") +) + +// UserAgentOriginal returns an attribute KeyValue conforming to the +// "user_agent.original" semantic conventions. It represents the value of the +// [HTTP +// User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) +// header sent by the client. +func UserAgentOriginal(val string) attribute.KeyValue { + return UserAgentOriginalKey.String(val) +} diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/doc.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/doc.go new file mode 100644 index 00000000..7cf42485 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/doc.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package semconv implements OpenTelemetry semantic conventions. +// +// OpenTelemetry semantic conventions are agreed standardized naming +// patterns for OpenTelemetry things. This package represents the conventions +// as of the v1.21.0 version of the OpenTelemetry specification. +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/event.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/event.go new file mode 100644 index 00000000..30ae34fe --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/event.go @@ -0,0 +1,199 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated from semantic convention specification. DO NOT EDIT. + +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" + +import "go.opentelemetry.io/otel/attribute" + +// This semantic convention defines the attributes used to represent a feature +// flag evaluation as an event. +const ( + // FeatureFlagKeyKey is the attribute Key conforming to the + // "feature_flag.key" semantic conventions. It represents the unique + // identifier of the feature flag. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'logo-color' + FeatureFlagKeyKey = attribute.Key("feature_flag.key") + + // FeatureFlagProviderNameKey is the attribute Key conforming to the + // "feature_flag.provider_name" semantic conventions. It represents the + // name of the service provider that performs the flag evaluation. + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'Flag Manager' + FeatureFlagProviderNameKey = attribute.Key("feature_flag.provider_name") + + // FeatureFlagVariantKey is the attribute Key conforming to the + // "feature_flag.variant" semantic conventions. It represents the sHOULD be + // a semantic identifier for a value. If one is unavailable, a stringified + // version of the value can be used. + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'red', 'true', 'on' + // Note: A semantic identifier, commonly referred to as a variant, provides + // a means + // for referring to a value without including the value itself. This can + // provide additional context for understanding the meaning behind a value. + // For example, the variant `red` maybe be used for the value `#c05543`. + // + // A stringified version of the value can be used in situations where a + // semantic identifier is unavailable. String representation of the value + // should be determined by the implementer. + FeatureFlagVariantKey = attribute.Key("feature_flag.variant") +) + +// FeatureFlagKey returns an attribute KeyValue conforming to the +// "feature_flag.key" semantic conventions. It represents the unique identifier +// of the feature flag. +func FeatureFlagKey(val string) attribute.KeyValue { + return FeatureFlagKeyKey.String(val) +} + +// FeatureFlagProviderName returns an attribute KeyValue conforming to the +// "feature_flag.provider_name" semantic conventions. It represents the name of +// the service provider that performs the flag evaluation. +func FeatureFlagProviderName(val string) attribute.KeyValue { + return FeatureFlagProviderNameKey.String(val) +} + +// FeatureFlagVariant returns an attribute KeyValue conforming to the +// "feature_flag.variant" semantic conventions. It represents the sHOULD be a +// semantic identifier for a value. If one is unavailable, a stringified +// version of the value can be used. +func FeatureFlagVariant(val string) attribute.KeyValue { + return FeatureFlagVariantKey.String(val) +} + +// RPC received/sent message. +const ( + // MessageTypeKey is the attribute Key conforming to the "message.type" + // semantic conventions. It represents the whether this is a received or + // sent message. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + MessageTypeKey = attribute.Key("message.type") + + // MessageIDKey is the attribute Key conforming to the "message.id" + // semantic conventions. It represents the mUST be calculated as two + // different counters starting from `1` one for sent messages and one for + // received message. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Note: This way we guarantee that the values will be consistent between + // different implementations. + MessageIDKey = attribute.Key("message.id") + + // MessageCompressedSizeKey is the attribute Key conforming to the + // "message.compressed_size" semantic conventions. It represents the + // compressed size of the message in bytes. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + MessageCompressedSizeKey = attribute.Key("message.compressed_size") + + // MessageUncompressedSizeKey is the attribute Key conforming to the + // "message.uncompressed_size" semantic conventions. It represents the + // uncompressed size of the message in bytes. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + MessageUncompressedSizeKey = attribute.Key("message.uncompressed_size") +) + +var ( + // sent + MessageTypeSent = MessageTypeKey.String("SENT") + // received + MessageTypeReceived = MessageTypeKey.String("RECEIVED") +) + +// MessageID returns an attribute KeyValue conforming to the "message.id" +// semantic conventions. It represents the mUST be calculated as two different +// counters starting from `1` one for sent messages and one for received +// message. +func MessageID(val int) attribute.KeyValue { + return MessageIDKey.Int(val) +} + +// MessageCompressedSize returns an attribute KeyValue conforming to the +// "message.compressed_size" semantic conventions. It represents the compressed +// size of the message in bytes. +func MessageCompressedSize(val int) attribute.KeyValue { + return MessageCompressedSizeKey.Int(val) +} + +// MessageUncompressedSize returns an attribute KeyValue conforming to the +// "message.uncompressed_size" semantic conventions. It represents the +// uncompressed size of the message in bytes. +func MessageUncompressedSize(val int) attribute.KeyValue { + return MessageUncompressedSizeKey.Int(val) +} + +// The attributes used to report a single exception associated with a span. +const ( + // ExceptionEscapedKey is the attribute Key conforming to the + // "exception.escaped" semantic conventions. It represents the sHOULD be + // set to true if the exception event is recorded at a point where it is + // known that the exception is escaping the scope of the span. + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + // Note: An exception is considered to have escaped (or left) the scope of + // a span, + // if that span is ended while the exception is still logically "in + // flight". + // This may be actually "in flight" in some languages (e.g. if the + // exception + // is passed to a Context manager's `__exit__` method in Python) but will + // usually be caught at the point of recording the exception in most + // languages. + // + // It is usually not possible to determine at the point where an exception + // is thrown + // whether it will escape the scope of a span. + // However, it is trivial to know that an exception + // will escape, if one checks for an active exception just before ending + // the span, + // as done in the [example above](#recording-an-exception). + // + // It follows that an exception may still escape the scope of the span + // even if the `exception.escaped` attribute was not set or set to false, + // since the event might have been recorded at a time where it was not + // clear whether the exception will escape. + ExceptionEscapedKey = attribute.Key("exception.escaped") +) + +// ExceptionEscaped returns an attribute KeyValue conforming to the +// "exception.escaped" semantic conventions. It represents the sHOULD be set to +// true if the exception event is recorded at a point where it is known that +// the exception is escaping the scope of the span. +func ExceptionEscaped(val bool) attribute.KeyValue { + return ExceptionEscapedKey.Bool(val) +} diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/exception.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/exception.go new file mode 100644 index 00000000..93d3c176 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/exception.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" + +const ( + // ExceptionEventName is the name of the Span event representing an exception. + ExceptionEventName = "exception" +) diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/resource.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/resource.go new file mode 100644 index 00000000..b6d8935c --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/resource.go @@ -0,0 +1,2310 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated from semantic convention specification. DO NOT EDIT. + +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" + +import "go.opentelemetry.io/otel/attribute" + +// The web browser in which the application represented by the resource is +// running. The `browser.*` attributes MUST be used only for resources that +// represent applications running in a web browser (regardless of whether +// running on a mobile or desktop device). +const ( + // BrowserBrandsKey is the attribute Key conforming to the "browser.brands" + // semantic conventions. It represents the array of brand name and version + // separated by a space + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: ' Not A;Brand 99', 'Chromium 99', 'Chrome 99' + // Note: This value is intended to be taken from the [UA client hints + // API](https://wicg.github.io/ua-client-hints/#interface) + // (`navigator.userAgentData.brands`). + BrowserBrandsKey = attribute.Key("browser.brands") + + // BrowserPlatformKey is the attribute Key conforming to the + // "browser.platform" semantic conventions. It represents the platform on + // which the browser is running + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Windows', 'macOS', 'Android' + // Note: This value is intended to be taken from the [UA client hints + // API](https://wicg.github.io/ua-client-hints/#interface) + // (`navigator.userAgentData.platform`). If unavailable, the legacy + // `navigator.platform` API SHOULD NOT be used instead and this attribute + // SHOULD be left unset in order for the values to be consistent. + // The list of possible values is defined in the [W3C User-Agent Client + // Hints + // specification](https://wicg.github.io/ua-client-hints/#sec-ch-ua-platform). + // Note that some (but not all) of these values can overlap with values in + // the [`os.type` and `os.name` attributes](./os.md). However, for + // consistency, the values in the `browser.platform` attribute should + // capture the exact value that the user agent provides. + BrowserPlatformKey = attribute.Key("browser.platform") + + // BrowserMobileKey is the attribute Key conforming to the "browser.mobile" + // semantic conventions. It represents a boolean that is true if the + // browser is running on a mobile device + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + // Note: This value is intended to be taken from the [UA client hints + // API](https://wicg.github.io/ua-client-hints/#interface) + // (`navigator.userAgentData.mobile`). If unavailable, this attribute + // SHOULD be left unset. + BrowserMobileKey = attribute.Key("browser.mobile") + + // BrowserLanguageKey is the attribute Key conforming to the + // "browser.language" semantic conventions. It represents the preferred + // language of the user using the browser + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'en', 'en-US', 'fr', 'fr-FR' + // Note: This value is intended to be taken from the Navigator API + // `navigator.language`. + BrowserLanguageKey = attribute.Key("browser.language") +) + +// BrowserBrands returns an attribute KeyValue conforming to the +// "browser.brands" semantic conventions. It represents the array of brand name +// and version separated by a space +func BrowserBrands(val ...string) attribute.KeyValue { + return BrowserBrandsKey.StringSlice(val) +} + +// BrowserPlatform returns an attribute KeyValue conforming to the +// "browser.platform" semantic conventions. It represents the platform on which +// the browser is running +func BrowserPlatform(val string) attribute.KeyValue { + return BrowserPlatformKey.String(val) +} + +// BrowserMobile returns an attribute KeyValue conforming to the +// "browser.mobile" semantic conventions. It represents a boolean that is true +// if the browser is running on a mobile device +func BrowserMobile(val bool) attribute.KeyValue { + return BrowserMobileKey.Bool(val) +} + +// BrowserLanguage returns an attribute KeyValue conforming to the +// "browser.language" semantic conventions. It represents the preferred +// language of the user using the browser +func BrowserLanguage(val string) attribute.KeyValue { + return BrowserLanguageKey.String(val) +} + +// A cloud environment (e.g. GCP, Azure, AWS) +const ( + // CloudProviderKey is the attribute Key conforming to the "cloud.provider" + // semantic conventions. It represents the name of the cloud provider. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + CloudProviderKey = attribute.Key("cloud.provider") + + // CloudAccountIDKey is the attribute Key conforming to the + // "cloud.account.id" semantic conventions. It represents the cloud account + // ID the resource is assigned to. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '111111111111', 'opentelemetry' + CloudAccountIDKey = attribute.Key("cloud.account.id") + + // CloudRegionKey is the attribute Key conforming to the "cloud.region" + // semantic conventions. It represents the geographical region the resource + // is running. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'us-central1', 'us-east-1' + // Note: Refer to your provider's docs to see the available regions, for + // example [Alibaba Cloud + // regions](https://www.alibabacloud.com/help/doc-detail/40654.htm), [AWS + // regions](https://aws.amazon.com/about-aws/global-infrastructure/regions_az/), + // [Azure + // regions](https://azure.microsoft.com/en-us/global-infrastructure/geographies/), + // [Google Cloud regions](https://cloud.google.com/about/locations), or + // [Tencent Cloud + // regions](https://www.tencentcloud.com/document/product/213/6091). + CloudRegionKey = attribute.Key("cloud.region") + + // CloudResourceIDKey is the attribute Key conforming to the + // "cloud.resource_id" semantic conventions. It represents the cloud + // provider-specific native identifier of the monitored cloud resource + // (e.g. an + // [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) + // on AWS, a [fully qualified resource + // ID](https://learn.microsoft.com/en-us/rest/api/resources/resources/get-by-id) + // on Azure, a [full resource + // name](https://cloud.google.com/apis/design/resource_names#full_resource_name) + // on GCP) + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'arn:aws:lambda:REGION:ACCOUNT_ID:function:my-function', + // '//run.googleapis.com/projects/PROJECT_ID/locations/LOCATION_ID/services/SERVICE_ID', + // '/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/' + // Note: On some cloud providers, it may not be possible to determine the + // full ID at startup, + // so it may be necessary to set `cloud.resource_id` as a span attribute + // instead. + // + // The exact value to use for `cloud.resource_id` depends on the cloud + // provider. + // The following well-known definitions MUST be used if you set this + // attribute and they apply: + // + // * **AWS Lambda:** The function + // [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). + // Take care not to use the "invoked ARN" directly but replace any + // [alias + // suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) + // with the resolved function version, as the same runtime instance may + // be invokable with + // multiple different aliases. + // * **GCP:** The [URI of the + // resource](https://cloud.google.com/iam/docs/full-resource-names) + // * **Azure:** The [Fully Qualified Resource + // ID](https://docs.microsoft.com/en-us/rest/api/resources/resources/get-by-id) + // of the invoked function, + // *not* the function app, having the form + // `/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/`. + // This means that a span attribute MUST be used, as an Azure function + // app can host multiple functions that would usually share + // a TracerProvider. + CloudResourceIDKey = attribute.Key("cloud.resource_id") + + // CloudAvailabilityZoneKey is the attribute Key conforming to the + // "cloud.availability_zone" semantic conventions. It represents the cloud + // regions often have multiple, isolated locations known as zones to + // increase availability. Availability zone represents the zone where the + // resource is running. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'us-east-1c' + // Note: Availability zones are called "zones" on Alibaba Cloud and Google + // Cloud. + CloudAvailabilityZoneKey = attribute.Key("cloud.availability_zone") + + // CloudPlatformKey is the attribute Key conforming to the "cloud.platform" + // semantic conventions. It represents the cloud platform in use. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Note: The prefix of the service SHOULD match the one specified in + // `cloud.provider`. + CloudPlatformKey = attribute.Key("cloud.platform") +) + +var ( + // Alibaba Cloud + CloudProviderAlibabaCloud = CloudProviderKey.String("alibaba_cloud") + // Amazon Web Services + CloudProviderAWS = CloudProviderKey.String("aws") + // Microsoft Azure + CloudProviderAzure = CloudProviderKey.String("azure") + // Google Cloud Platform + CloudProviderGCP = CloudProviderKey.String("gcp") + // Heroku Platform as a Service + CloudProviderHeroku = CloudProviderKey.String("heroku") + // IBM Cloud + CloudProviderIbmCloud = CloudProviderKey.String("ibm_cloud") + // Tencent Cloud + CloudProviderTencentCloud = CloudProviderKey.String("tencent_cloud") +) + +var ( + // Alibaba Cloud Elastic Compute Service + CloudPlatformAlibabaCloudECS = CloudPlatformKey.String("alibaba_cloud_ecs") + // Alibaba Cloud Function Compute + CloudPlatformAlibabaCloudFc = CloudPlatformKey.String("alibaba_cloud_fc") + // Red Hat OpenShift on Alibaba Cloud + CloudPlatformAlibabaCloudOpenshift = CloudPlatformKey.String("alibaba_cloud_openshift") + // AWS Elastic Compute Cloud + CloudPlatformAWSEC2 = CloudPlatformKey.String("aws_ec2") + // AWS Elastic Container Service + CloudPlatformAWSECS = CloudPlatformKey.String("aws_ecs") + // AWS Elastic Kubernetes Service + CloudPlatformAWSEKS = CloudPlatformKey.String("aws_eks") + // AWS Lambda + CloudPlatformAWSLambda = CloudPlatformKey.String("aws_lambda") + // AWS Elastic Beanstalk + CloudPlatformAWSElasticBeanstalk = CloudPlatformKey.String("aws_elastic_beanstalk") + // AWS App Runner + CloudPlatformAWSAppRunner = CloudPlatformKey.String("aws_app_runner") + // Red Hat OpenShift on AWS (ROSA) + CloudPlatformAWSOpenshift = CloudPlatformKey.String("aws_openshift") + // Azure Virtual Machines + CloudPlatformAzureVM = CloudPlatformKey.String("azure_vm") + // Azure Container Instances + CloudPlatformAzureContainerInstances = CloudPlatformKey.String("azure_container_instances") + // Azure Kubernetes Service + CloudPlatformAzureAKS = CloudPlatformKey.String("azure_aks") + // Azure Functions + CloudPlatformAzureFunctions = CloudPlatformKey.String("azure_functions") + // Azure App Service + CloudPlatformAzureAppService = CloudPlatformKey.String("azure_app_service") + // Azure Red Hat OpenShift + CloudPlatformAzureOpenshift = CloudPlatformKey.String("azure_openshift") + // Google Bare Metal Solution (BMS) + CloudPlatformGCPBareMetalSolution = CloudPlatformKey.String("gcp_bare_metal_solution") + // Google Cloud Compute Engine (GCE) + CloudPlatformGCPComputeEngine = CloudPlatformKey.String("gcp_compute_engine") + // Google Cloud Run + CloudPlatformGCPCloudRun = CloudPlatformKey.String("gcp_cloud_run") + // Google Cloud Kubernetes Engine (GKE) + CloudPlatformGCPKubernetesEngine = CloudPlatformKey.String("gcp_kubernetes_engine") + // Google Cloud Functions (GCF) + CloudPlatformGCPCloudFunctions = CloudPlatformKey.String("gcp_cloud_functions") + // Google Cloud App Engine (GAE) + CloudPlatformGCPAppEngine = CloudPlatformKey.String("gcp_app_engine") + // Red Hat OpenShift on Google Cloud + CloudPlatformGCPOpenshift = CloudPlatformKey.String("gcp_openshift") + // Red Hat OpenShift on IBM Cloud + CloudPlatformIbmCloudOpenshift = CloudPlatformKey.String("ibm_cloud_openshift") + // Tencent Cloud Cloud Virtual Machine (CVM) + CloudPlatformTencentCloudCvm = CloudPlatformKey.String("tencent_cloud_cvm") + // Tencent Cloud Elastic Kubernetes Service (EKS) + CloudPlatformTencentCloudEKS = CloudPlatformKey.String("tencent_cloud_eks") + // Tencent Cloud Serverless Cloud Function (SCF) + CloudPlatformTencentCloudScf = CloudPlatformKey.String("tencent_cloud_scf") +) + +// CloudAccountID returns an attribute KeyValue conforming to the +// "cloud.account.id" semantic conventions. It represents the cloud account ID +// the resource is assigned to. +func CloudAccountID(val string) attribute.KeyValue { + return CloudAccountIDKey.String(val) +} + +// CloudRegion returns an attribute KeyValue conforming to the +// "cloud.region" semantic conventions. It represents the geographical region +// the resource is running. +func CloudRegion(val string) attribute.KeyValue { + return CloudRegionKey.String(val) +} + +// CloudResourceID returns an attribute KeyValue conforming to the +// "cloud.resource_id" semantic conventions. It represents the cloud +// provider-specific native identifier of the monitored cloud resource (e.g. an +// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) +// on AWS, a [fully qualified resource +// ID](https://learn.microsoft.com/en-us/rest/api/resources/resources/get-by-id) +// on Azure, a [full resource +// name](https://cloud.google.com/apis/design/resource_names#full_resource_name) +// on GCP) +func CloudResourceID(val string) attribute.KeyValue { + return CloudResourceIDKey.String(val) +} + +// CloudAvailabilityZone returns an attribute KeyValue conforming to the +// "cloud.availability_zone" semantic conventions. It represents the cloud +// regions often have multiple, isolated locations known as zones to increase +// availability. Availability zone represents the zone where the resource is +// running. +func CloudAvailabilityZone(val string) attribute.KeyValue { + return CloudAvailabilityZoneKey.String(val) +} + +// Resources used by AWS Elastic Container Service (ECS). +const ( + // AWSECSContainerARNKey is the attribute Key conforming to the + // "aws.ecs.container.arn" semantic conventions. It represents the Amazon + // Resource Name (ARN) of an [ECS container + // instance](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_instances.html). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: + // 'arn:aws:ecs:us-west-1:123456789123:container/32624152-9086-4f0e-acae-1a75b14fe4d9' + AWSECSContainerARNKey = attribute.Key("aws.ecs.container.arn") + + // AWSECSClusterARNKey is the attribute Key conforming to the + // "aws.ecs.cluster.arn" semantic conventions. It represents the ARN of an + // [ECS + // cluster](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'arn:aws:ecs:us-west-2:123456789123:cluster/my-cluster' + AWSECSClusterARNKey = attribute.Key("aws.ecs.cluster.arn") + + // AWSECSLaunchtypeKey is the attribute Key conforming to the + // "aws.ecs.launchtype" semantic conventions. It represents the [launch + // type](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_types.html) + // for an ECS task. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + AWSECSLaunchtypeKey = attribute.Key("aws.ecs.launchtype") + + // AWSECSTaskARNKey is the attribute Key conforming to the + // "aws.ecs.task.arn" semantic conventions. It represents the ARN of an + // [ECS task + // definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: + // 'arn:aws:ecs:us-west-1:123456789123:task/10838bed-421f-43ef-870a-f43feacbbb5b' + AWSECSTaskARNKey = attribute.Key("aws.ecs.task.arn") + + // AWSECSTaskFamilyKey is the attribute Key conforming to the + // "aws.ecs.task.family" semantic conventions. It represents the task + // definition family this task definition is a member of. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry-family' + AWSECSTaskFamilyKey = attribute.Key("aws.ecs.task.family") + + // AWSECSTaskRevisionKey is the attribute Key conforming to the + // "aws.ecs.task.revision" semantic conventions. It represents the revision + // for this task definition. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '8', '26' + AWSECSTaskRevisionKey = attribute.Key("aws.ecs.task.revision") +) + +var ( + // ec2 + AWSECSLaunchtypeEC2 = AWSECSLaunchtypeKey.String("ec2") + // fargate + AWSECSLaunchtypeFargate = AWSECSLaunchtypeKey.String("fargate") +) + +// AWSECSContainerARN returns an attribute KeyValue conforming to the +// "aws.ecs.container.arn" semantic conventions. It represents the Amazon +// Resource Name (ARN) of an [ECS container +// instance](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_instances.html). +func AWSECSContainerARN(val string) attribute.KeyValue { + return AWSECSContainerARNKey.String(val) +} + +// AWSECSClusterARN returns an attribute KeyValue conforming to the +// "aws.ecs.cluster.arn" semantic conventions. It represents the ARN of an [ECS +// cluster](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html). +func AWSECSClusterARN(val string) attribute.KeyValue { + return AWSECSClusterARNKey.String(val) +} + +// AWSECSTaskARN returns an attribute KeyValue conforming to the +// "aws.ecs.task.arn" semantic conventions. It represents the ARN of an [ECS +// task +// definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html). +func AWSECSTaskARN(val string) attribute.KeyValue { + return AWSECSTaskARNKey.String(val) +} + +// AWSECSTaskFamily returns an attribute KeyValue conforming to the +// "aws.ecs.task.family" semantic conventions. It represents the task +// definition family this task definition is a member of. +func AWSECSTaskFamily(val string) attribute.KeyValue { + return AWSECSTaskFamilyKey.String(val) +} + +// AWSECSTaskRevision returns an attribute KeyValue conforming to the +// "aws.ecs.task.revision" semantic conventions. It represents the revision for +// this task definition. +func AWSECSTaskRevision(val string) attribute.KeyValue { + return AWSECSTaskRevisionKey.String(val) +} + +// Resources used by AWS Elastic Kubernetes Service (EKS). +const ( + // AWSEKSClusterARNKey is the attribute Key conforming to the + // "aws.eks.cluster.arn" semantic conventions. It represents the ARN of an + // EKS cluster. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'arn:aws:ecs:us-west-2:123456789123:cluster/my-cluster' + AWSEKSClusterARNKey = attribute.Key("aws.eks.cluster.arn") +) + +// AWSEKSClusterARN returns an attribute KeyValue conforming to the +// "aws.eks.cluster.arn" semantic conventions. It represents the ARN of an EKS +// cluster. +func AWSEKSClusterARN(val string) attribute.KeyValue { + return AWSEKSClusterARNKey.String(val) +} + +// Resources specific to Amazon Web Services. +const ( + // AWSLogGroupNamesKey is the attribute Key conforming to the + // "aws.log.group.names" semantic conventions. It represents the name(s) of + // the AWS log group(s) an application is writing to. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: '/aws/lambda/my-function', 'opentelemetry-service' + // Note: Multiple log groups must be supported for cases like + // multi-container applications, where a single application has sidecar + // containers, and each write to their own log group. + AWSLogGroupNamesKey = attribute.Key("aws.log.group.names") + + // AWSLogGroupARNsKey is the attribute Key conforming to the + // "aws.log.group.arns" semantic conventions. It represents the Amazon + // Resource Name(s) (ARN) of the AWS log group(s). + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: + // 'arn:aws:logs:us-west-1:123456789012:log-group:/aws/my/group:*' + // Note: See the [log group ARN format + // documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/iam-access-control-overview-cwl.html#CWL_ARN_Format). + AWSLogGroupARNsKey = attribute.Key("aws.log.group.arns") + + // AWSLogStreamNamesKey is the attribute Key conforming to the + // "aws.log.stream.names" semantic conventions. It represents the name(s) + // of the AWS log stream(s) an application is writing to. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: 'logs/main/10838bed-421f-43ef-870a-f43feacbbb5b' + AWSLogStreamNamesKey = attribute.Key("aws.log.stream.names") + + // AWSLogStreamARNsKey is the attribute Key conforming to the + // "aws.log.stream.arns" semantic conventions. It represents the ARN(s) of + // the AWS log stream(s). + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: + // 'arn:aws:logs:us-west-1:123456789012:log-group:/aws/my/group:log-stream:logs/main/10838bed-421f-43ef-870a-f43feacbbb5b' + // Note: See the [log stream ARN format + // documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/iam-access-control-overview-cwl.html#CWL_ARN_Format). + // One log group can contain several log streams, so these ARNs necessarily + // identify both a log group and a log stream. + AWSLogStreamARNsKey = attribute.Key("aws.log.stream.arns") +) + +// AWSLogGroupNames returns an attribute KeyValue conforming to the +// "aws.log.group.names" semantic conventions. It represents the name(s) of the +// AWS log group(s) an application is writing to. +func AWSLogGroupNames(val ...string) attribute.KeyValue { + return AWSLogGroupNamesKey.StringSlice(val) +} + +// AWSLogGroupARNs returns an attribute KeyValue conforming to the +// "aws.log.group.arns" semantic conventions. It represents the Amazon Resource +// Name(s) (ARN) of the AWS log group(s). +func AWSLogGroupARNs(val ...string) attribute.KeyValue { + return AWSLogGroupARNsKey.StringSlice(val) +} + +// AWSLogStreamNames returns an attribute KeyValue conforming to the +// "aws.log.stream.names" semantic conventions. It represents the name(s) of +// the AWS log stream(s) an application is writing to. +func AWSLogStreamNames(val ...string) attribute.KeyValue { + return AWSLogStreamNamesKey.StringSlice(val) +} + +// AWSLogStreamARNs returns an attribute KeyValue conforming to the +// "aws.log.stream.arns" semantic conventions. It represents the ARN(s) of the +// AWS log stream(s). +func AWSLogStreamARNs(val ...string) attribute.KeyValue { + return AWSLogStreamARNsKey.StringSlice(val) +} + +// Resource used by Google Cloud Run. +const ( + // GCPCloudRunJobExecutionKey is the attribute Key conforming to the + // "gcp.cloud_run.job.execution" semantic conventions. It represents the + // name of the Cloud Run + // [execution](https://cloud.google.com/run/docs/managing/job-executions) + // being run for the Job, as set by the + // [`CLOUD_RUN_EXECUTION`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) + // environment variable. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'job-name-xxxx', 'sample-job-mdw84' + GCPCloudRunJobExecutionKey = attribute.Key("gcp.cloud_run.job.execution") + + // GCPCloudRunJobTaskIndexKey is the attribute Key conforming to the + // "gcp.cloud_run.job.task_index" semantic conventions. It represents the + // index for a task within an execution as provided by the + // [`CLOUD_RUN_TASK_INDEX`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) + // environment variable. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 0, 1 + GCPCloudRunJobTaskIndexKey = attribute.Key("gcp.cloud_run.job.task_index") +) + +// GCPCloudRunJobExecution returns an attribute KeyValue conforming to the +// "gcp.cloud_run.job.execution" semantic conventions. It represents the name +// of the Cloud Run +// [execution](https://cloud.google.com/run/docs/managing/job-executions) being +// run for the Job, as set by the +// [`CLOUD_RUN_EXECUTION`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) +// environment variable. +func GCPCloudRunJobExecution(val string) attribute.KeyValue { + return GCPCloudRunJobExecutionKey.String(val) +} + +// GCPCloudRunJobTaskIndex returns an attribute KeyValue conforming to the +// "gcp.cloud_run.job.task_index" semantic conventions. It represents the index +// for a task within an execution as provided by the +// [`CLOUD_RUN_TASK_INDEX`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) +// environment variable. +func GCPCloudRunJobTaskIndex(val int) attribute.KeyValue { + return GCPCloudRunJobTaskIndexKey.Int(val) +} + +// Resources used by Google Compute Engine (GCE). +const ( + // GCPGceInstanceNameKey is the attribute Key conforming to the + // "gcp.gce.instance.name" semantic conventions. It represents the instance + // name of a GCE instance. This is the value provided by `host.name`, the + // visible name of the instance in the Cloud Console UI, and the prefix for + // the default hostname of the instance as defined by the [default internal + // DNS + // name](https://cloud.google.com/compute/docs/internal-dns#instance-fully-qualified-domain-names). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'instance-1', 'my-vm-name' + GCPGceInstanceNameKey = attribute.Key("gcp.gce.instance.name") + + // GCPGceInstanceHostnameKey is the attribute Key conforming to the + // "gcp.gce.instance.hostname" semantic conventions. It represents the + // hostname of a GCE instance. This is the full value of the default or + // [custom + // hostname](https://cloud.google.com/compute/docs/instances/custom-hostname-vm). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'my-host1234.example.com', + // 'sample-vm.us-west1-b.c.my-project.internal' + GCPGceInstanceHostnameKey = attribute.Key("gcp.gce.instance.hostname") +) + +// GCPGceInstanceName returns an attribute KeyValue conforming to the +// "gcp.gce.instance.name" semantic conventions. It represents the instance +// name of a GCE instance. This is the value provided by `host.name`, the +// visible name of the instance in the Cloud Console UI, and the prefix for the +// default hostname of the instance as defined by the [default internal DNS +// name](https://cloud.google.com/compute/docs/internal-dns#instance-fully-qualified-domain-names). +func GCPGceInstanceName(val string) attribute.KeyValue { + return GCPGceInstanceNameKey.String(val) +} + +// GCPGceInstanceHostname returns an attribute KeyValue conforming to the +// "gcp.gce.instance.hostname" semantic conventions. It represents the hostname +// of a GCE instance. This is the full value of the default or [custom +// hostname](https://cloud.google.com/compute/docs/instances/custom-hostname-vm). +func GCPGceInstanceHostname(val string) attribute.KeyValue { + return GCPGceInstanceHostnameKey.String(val) +} + +// Heroku dyno metadata +const ( + // HerokuReleaseCreationTimestampKey is the attribute Key conforming to the + // "heroku.release.creation_timestamp" semantic conventions. It represents + // the time and date the release was created + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2022-10-23T18:00:42Z' + HerokuReleaseCreationTimestampKey = attribute.Key("heroku.release.creation_timestamp") + + // HerokuReleaseCommitKey is the attribute Key conforming to the + // "heroku.release.commit" semantic conventions. It represents the commit + // hash for the current release + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'e6134959463efd8966b20e75b913cafe3f5ec' + HerokuReleaseCommitKey = attribute.Key("heroku.release.commit") + + // HerokuAppIDKey is the attribute Key conforming to the "heroku.app.id" + // semantic conventions. It represents the unique identifier for the + // application + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2daa2797-e42b-4624-9322-ec3f968df4da' + HerokuAppIDKey = attribute.Key("heroku.app.id") +) + +// HerokuReleaseCreationTimestamp returns an attribute KeyValue conforming +// to the "heroku.release.creation_timestamp" semantic conventions. It +// represents the time and date the release was created +func HerokuReleaseCreationTimestamp(val string) attribute.KeyValue { + return HerokuReleaseCreationTimestampKey.String(val) +} + +// HerokuReleaseCommit returns an attribute KeyValue conforming to the +// "heroku.release.commit" semantic conventions. It represents the commit hash +// for the current release +func HerokuReleaseCommit(val string) attribute.KeyValue { + return HerokuReleaseCommitKey.String(val) +} + +// HerokuAppID returns an attribute KeyValue conforming to the +// "heroku.app.id" semantic conventions. It represents the unique identifier +// for the application +func HerokuAppID(val string) attribute.KeyValue { + return HerokuAppIDKey.String(val) +} + +// A container instance. +const ( + // ContainerNameKey is the attribute Key conforming to the "container.name" + // semantic conventions. It represents the container name used by container + // runtime. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry-autoconf' + ContainerNameKey = attribute.Key("container.name") + + // ContainerIDKey is the attribute Key conforming to the "container.id" + // semantic conventions. It represents the container ID. Usually a UUID, as + // for example used to [identify Docker + // containers](https://docs.docker.com/engine/reference/run/#container-identification). + // The UUID might be abbreviated. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'a3bf90e006b2' + ContainerIDKey = attribute.Key("container.id") + + // ContainerRuntimeKey is the attribute Key conforming to the + // "container.runtime" semantic conventions. It represents the container + // runtime managing this container. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'docker', 'containerd', 'rkt' + ContainerRuntimeKey = attribute.Key("container.runtime") + + // ContainerImageNameKey is the attribute Key conforming to the + // "container.image.name" semantic conventions. It represents the name of + // the image the container was built on. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'gcr.io/opentelemetry/operator' + ContainerImageNameKey = attribute.Key("container.image.name") + + // ContainerImageTagKey is the attribute Key conforming to the + // "container.image.tag" semantic conventions. It represents the container + // image tag. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '0.1' + ContainerImageTagKey = attribute.Key("container.image.tag") + + // ContainerImageIDKey is the attribute Key conforming to the + // "container.image.id" semantic conventions. It represents the runtime + // specific image identifier. Usually a hash algorithm followed by a UUID. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: + // 'sha256:19c92d0a00d1b66d897bceaa7319bee0dd38a10a851c60bcec9474aa3f01e50f' + // Note: Docker defines a sha256 of the image id; `container.image.id` + // corresponds to the `Image` field from the Docker container inspect + // [API](https://docs.docker.com/engine/api/v1.43/#tag/Container/operation/ContainerInspect) + // endpoint. + // K8S defines a link to the container registry repository with digest + // `"imageID": "registry.azurecr.io + // /namespace/service/dockerfile@sha256:bdeabd40c3a8a492eaf9e8e44d0ebbb84bac7ee25ac0cf8a7159d25f62555625"`. + // OCI defines a digest of manifest. + ContainerImageIDKey = attribute.Key("container.image.id") + + // ContainerCommandKey is the attribute Key conforming to the + // "container.command" semantic conventions. It represents the command used + // to run the container (i.e. the command name). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'otelcontribcol' + // Note: If using embedded credentials or sensitive data, it is recommended + // to remove them to prevent potential leakage. + ContainerCommandKey = attribute.Key("container.command") + + // ContainerCommandLineKey is the attribute Key conforming to the + // "container.command_line" semantic conventions. It represents the full + // command run by the container as a single string representing the full + // command. [2] + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'otelcontribcol --config config.yaml' + ContainerCommandLineKey = attribute.Key("container.command_line") + + // ContainerCommandArgsKey is the attribute Key conforming to the + // "container.command_args" semantic conventions. It represents the all the + // command arguments (including the command/executable itself) run by the + // container. [2] + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: 'otelcontribcol, --config, config.yaml' + ContainerCommandArgsKey = attribute.Key("container.command_args") +) + +// ContainerName returns an attribute KeyValue conforming to the +// "container.name" semantic conventions. It represents the container name used +// by container runtime. +func ContainerName(val string) attribute.KeyValue { + return ContainerNameKey.String(val) +} + +// ContainerID returns an attribute KeyValue conforming to the +// "container.id" semantic conventions. It represents the container ID. Usually +// a UUID, as for example used to [identify Docker +// containers](https://docs.docker.com/engine/reference/run/#container-identification). +// The UUID might be abbreviated. +func ContainerID(val string) attribute.KeyValue { + return ContainerIDKey.String(val) +} + +// ContainerRuntime returns an attribute KeyValue conforming to the +// "container.runtime" semantic conventions. It represents the container +// runtime managing this container. +func ContainerRuntime(val string) attribute.KeyValue { + return ContainerRuntimeKey.String(val) +} + +// ContainerImageName returns an attribute KeyValue conforming to the +// "container.image.name" semantic conventions. It represents the name of the +// image the container was built on. +func ContainerImageName(val string) attribute.KeyValue { + return ContainerImageNameKey.String(val) +} + +// ContainerImageTag returns an attribute KeyValue conforming to the +// "container.image.tag" semantic conventions. It represents the container +// image tag. +func ContainerImageTag(val string) attribute.KeyValue { + return ContainerImageTagKey.String(val) +} + +// ContainerImageID returns an attribute KeyValue conforming to the +// "container.image.id" semantic conventions. It represents the runtime +// specific image identifier. Usually a hash algorithm followed by a UUID. +func ContainerImageID(val string) attribute.KeyValue { + return ContainerImageIDKey.String(val) +} + +// ContainerCommand returns an attribute KeyValue conforming to the +// "container.command" semantic conventions. It represents the command used to +// run the container (i.e. the command name). +func ContainerCommand(val string) attribute.KeyValue { + return ContainerCommandKey.String(val) +} + +// ContainerCommandLine returns an attribute KeyValue conforming to the +// "container.command_line" semantic conventions. It represents the full +// command run by the container as a single string representing the full +// command. [2] +func ContainerCommandLine(val string) attribute.KeyValue { + return ContainerCommandLineKey.String(val) +} + +// ContainerCommandArgs returns an attribute KeyValue conforming to the +// "container.command_args" semantic conventions. It represents the all the +// command arguments (including the command/executable itself) run by the +// container. [2] +func ContainerCommandArgs(val ...string) attribute.KeyValue { + return ContainerCommandArgsKey.StringSlice(val) +} + +// The software deployment. +const ( + // DeploymentEnvironmentKey is the attribute Key conforming to the + // "deployment.environment" semantic conventions. It represents the name of + // the [deployment + // environment](https://en.wikipedia.org/wiki/Deployment_environment) (aka + // deployment tier). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'staging', 'production' + DeploymentEnvironmentKey = attribute.Key("deployment.environment") +) + +// DeploymentEnvironment returns an attribute KeyValue conforming to the +// "deployment.environment" semantic conventions. It represents the name of the +// [deployment +// environment](https://en.wikipedia.org/wiki/Deployment_environment) (aka +// deployment tier). +func DeploymentEnvironment(val string) attribute.KeyValue { + return DeploymentEnvironmentKey.String(val) +} + +// The device on which the process represented by this resource is running. +const ( + // DeviceIDKey is the attribute Key conforming to the "device.id" semantic + // conventions. It represents a unique identifier representing the device + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2ab2916d-a51f-4ac8-80ee-45ac31a28092' + // Note: The device identifier MUST only be defined using the values + // outlined below. This value is not an advertising identifier and MUST NOT + // be used as such. On iOS (Swift or Objective-C), this value MUST be equal + // to the [vendor + // identifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor). + // On Android (Java or Kotlin), this value MUST be equal to the Firebase + // Installation ID or a globally unique UUID which is persisted across + // sessions in your application. More information can be found + // [here](https://developer.android.com/training/articles/user-data-ids) on + // best practices and exact implementation details. Caution should be taken + // when storing personal data or anything which can identify a user. GDPR + // and data protection laws may apply, ensure you do your own due + // diligence. + DeviceIDKey = attribute.Key("device.id") + + // DeviceModelIdentifierKey is the attribute Key conforming to the + // "device.model.identifier" semantic conventions. It represents the model + // identifier for the device + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'iPhone3,4', 'SM-G920F' + // Note: It's recommended this value represents a machine readable version + // of the model identifier rather than the market or consumer-friendly name + // of the device. + DeviceModelIdentifierKey = attribute.Key("device.model.identifier") + + // DeviceModelNameKey is the attribute Key conforming to the + // "device.model.name" semantic conventions. It represents the marketing + // name for the device model + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'iPhone 6s Plus', 'Samsung Galaxy S6' + // Note: It's recommended this value represents a human readable version of + // the device model rather than a machine readable alternative. + DeviceModelNameKey = attribute.Key("device.model.name") + + // DeviceManufacturerKey is the attribute Key conforming to the + // "device.manufacturer" semantic conventions. It represents the name of + // the device manufacturer + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Apple', 'Samsung' + // Note: The Android OS provides this field via + // [Build](https://developer.android.com/reference/android/os/Build#MANUFACTURER). + // iOS apps SHOULD hardcode the value `Apple`. + DeviceManufacturerKey = attribute.Key("device.manufacturer") +) + +// DeviceID returns an attribute KeyValue conforming to the "device.id" +// semantic conventions. It represents a unique identifier representing the +// device +func DeviceID(val string) attribute.KeyValue { + return DeviceIDKey.String(val) +} + +// DeviceModelIdentifier returns an attribute KeyValue conforming to the +// "device.model.identifier" semantic conventions. It represents the model +// identifier for the device +func DeviceModelIdentifier(val string) attribute.KeyValue { + return DeviceModelIdentifierKey.String(val) +} + +// DeviceModelName returns an attribute KeyValue conforming to the +// "device.model.name" semantic conventions. It represents the marketing name +// for the device model +func DeviceModelName(val string) attribute.KeyValue { + return DeviceModelNameKey.String(val) +} + +// DeviceManufacturer returns an attribute KeyValue conforming to the +// "device.manufacturer" semantic conventions. It represents the name of the +// device manufacturer +func DeviceManufacturer(val string) attribute.KeyValue { + return DeviceManufacturerKey.String(val) +} + +// A serverless instance. +const ( + // FaaSNameKey is the attribute Key conforming to the "faas.name" semantic + // conventions. It represents the name of the single function that this + // runtime instance executes. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'my-function', 'myazurefunctionapp/some-function-name' + // Note: This is the name of the function as configured/deployed on the + // FaaS + // platform and is usually different from the name of the callback + // function (which may be stored in the + // [`code.namespace`/`code.function`](/docs/general/general-attributes.md#source-code-attributes) + // span attributes). + // + // For some cloud providers, the above definition is ambiguous. The + // following + // definition of function name MUST be used for this attribute + // (and consequently the span name) for the listed cloud + // providers/products: + // + // * **Azure:** The full name `/`, i.e., function app name + // followed by a forward slash followed by the function name (this form + // can also be seen in the resource JSON for the function). + // This means that a span attribute MUST be used, as an Azure function + // app can host multiple functions that would usually share + // a TracerProvider (see also the `cloud.resource_id` attribute). + FaaSNameKey = attribute.Key("faas.name") + + // FaaSVersionKey is the attribute Key conforming to the "faas.version" + // semantic conventions. It represents the immutable version of the + // function being executed. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '26', 'pinkfroid-00002' + // Note: Depending on the cloud provider and platform, use: + // + // * **AWS Lambda:** The [function + // version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html) + // (an integer represented as a decimal string). + // * **Google Cloud Run (Services):** The + // [revision](https://cloud.google.com/run/docs/managing/revisions) + // (i.e., the function name plus the revision suffix). + // * **Google Cloud Functions:** The value of the + // [`K_REVISION` environment + // variable](https://cloud.google.com/functions/docs/env-var#runtime_environment_variables_set_automatically). + // * **Azure Functions:** Not applicable. Do not set this attribute. + FaaSVersionKey = attribute.Key("faas.version") + + // FaaSInstanceKey is the attribute Key conforming to the "faas.instance" + // semantic conventions. It represents the execution environment ID as a + // string, that will be potentially reused for other invocations to the + // same function/function version. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2021/06/28/[$LATEST]2f399eb14537447da05ab2a2e39309de' + // Note: * **AWS Lambda:** Use the (full) log stream name. + FaaSInstanceKey = attribute.Key("faas.instance") + + // FaaSMaxMemoryKey is the attribute Key conforming to the + // "faas.max_memory" semantic conventions. It represents the amount of + // memory available to the serverless function converted to Bytes. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 134217728 + // Note: It's recommended to set this attribute since e.g. too little + // memory can easily stop a Java AWS Lambda function from working + // correctly. On AWS Lambda, the environment variable + // `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information (which must + // be multiplied by 1,048,576). + FaaSMaxMemoryKey = attribute.Key("faas.max_memory") +) + +// FaaSName returns an attribute KeyValue conforming to the "faas.name" +// semantic conventions. It represents the name of the single function that +// this runtime instance executes. +func FaaSName(val string) attribute.KeyValue { + return FaaSNameKey.String(val) +} + +// FaaSVersion returns an attribute KeyValue conforming to the +// "faas.version" semantic conventions. It represents the immutable version of +// the function being executed. +func FaaSVersion(val string) attribute.KeyValue { + return FaaSVersionKey.String(val) +} + +// FaaSInstance returns an attribute KeyValue conforming to the +// "faas.instance" semantic conventions. It represents the execution +// environment ID as a string, that will be potentially reused for other +// invocations to the same function/function version. +func FaaSInstance(val string) attribute.KeyValue { + return FaaSInstanceKey.String(val) +} + +// FaaSMaxMemory returns an attribute KeyValue conforming to the +// "faas.max_memory" semantic conventions. It represents the amount of memory +// available to the serverless function converted to Bytes. +func FaaSMaxMemory(val int) attribute.KeyValue { + return FaaSMaxMemoryKey.Int(val) +} + +// A host is defined as a computing instance. For example, physical servers, +// virtual machines, switches or disk array. +const ( + // HostIDKey is the attribute Key conforming to the "host.id" semantic + // conventions. It represents the unique host ID. For Cloud, this must be + // the instance_id assigned by the cloud provider. For non-containerized + // systems, this should be the `machine-id`. See the table below for the + // sources to use to determine the `machine-id` based on operating system. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'fdbf79e8af94cb7f9e8df36789187052' + HostIDKey = attribute.Key("host.id") + + // HostNameKey is the attribute Key conforming to the "host.name" semantic + // conventions. It represents the name of the host. On Unix systems, it may + // contain what the hostname command returns, or the fully qualified + // hostname, or another name specified by the user. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry-test' + HostNameKey = attribute.Key("host.name") + + // HostTypeKey is the attribute Key conforming to the "host.type" semantic + // conventions. It represents the type of host. For Cloud, this must be the + // machine type. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'n1-standard-1' + HostTypeKey = attribute.Key("host.type") + + // HostArchKey is the attribute Key conforming to the "host.arch" semantic + // conventions. It represents the CPU architecture the host system is + // running on. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + HostArchKey = attribute.Key("host.arch") + + // HostImageNameKey is the attribute Key conforming to the + // "host.image.name" semantic conventions. It represents the name of the VM + // image or OS install the host was instantiated from. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'infra-ami-eks-worker-node-7d4ec78312', 'CentOS-8-x86_64-1905' + HostImageNameKey = attribute.Key("host.image.name") + + // HostImageIDKey is the attribute Key conforming to the "host.image.id" + // semantic conventions. It represents the vM image ID or host OS image ID. + // For Cloud, this value is from the provider. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'ami-07b06b442921831e5' + HostImageIDKey = attribute.Key("host.image.id") + + // HostImageVersionKey is the attribute Key conforming to the + // "host.image.version" semantic conventions. It represents the version + // string of the VM image or host OS as defined in [Version + // Attributes](README.md#version-attributes). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '0.1' + HostImageVersionKey = attribute.Key("host.image.version") +) + +var ( + // AMD64 + HostArchAMD64 = HostArchKey.String("amd64") + // ARM32 + HostArchARM32 = HostArchKey.String("arm32") + // ARM64 + HostArchARM64 = HostArchKey.String("arm64") + // Itanium + HostArchIA64 = HostArchKey.String("ia64") + // 32-bit PowerPC + HostArchPPC32 = HostArchKey.String("ppc32") + // 64-bit PowerPC + HostArchPPC64 = HostArchKey.String("ppc64") + // IBM z/Architecture + HostArchS390x = HostArchKey.String("s390x") + // 32-bit x86 + HostArchX86 = HostArchKey.String("x86") +) + +// HostID returns an attribute KeyValue conforming to the "host.id" semantic +// conventions. It represents the unique host ID. For Cloud, this must be the +// instance_id assigned by the cloud provider. For non-containerized systems, +// this should be the `machine-id`. See the table below for the sources to use +// to determine the `machine-id` based on operating system. +func HostID(val string) attribute.KeyValue { + return HostIDKey.String(val) +} + +// HostName returns an attribute KeyValue conforming to the "host.name" +// semantic conventions. It represents the name of the host. On Unix systems, +// it may contain what the hostname command returns, or the fully qualified +// hostname, or another name specified by the user. +func HostName(val string) attribute.KeyValue { + return HostNameKey.String(val) +} + +// HostType returns an attribute KeyValue conforming to the "host.type" +// semantic conventions. It represents the type of host. For Cloud, this must +// be the machine type. +func HostType(val string) attribute.KeyValue { + return HostTypeKey.String(val) +} + +// HostImageName returns an attribute KeyValue conforming to the +// "host.image.name" semantic conventions. It represents the name of the VM +// image or OS install the host was instantiated from. +func HostImageName(val string) attribute.KeyValue { + return HostImageNameKey.String(val) +} + +// HostImageID returns an attribute KeyValue conforming to the +// "host.image.id" semantic conventions. It represents the vM image ID or host +// OS image ID. For Cloud, this value is from the provider. +func HostImageID(val string) attribute.KeyValue { + return HostImageIDKey.String(val) +} + +// HostImageVersion returns an attribute KeyValue conforming to the +// "host.image.version" semantic conventions. It represents the version string +// of the VM image or host OS as defined in [Version +// Attributes](README.md#version-attributes). +func HostImageVersion(val string) attribute.KeyValue { + return HostImageVersionKey.String(val) +} + +// A Kubernetes Cluster. +const ( + // K8SClusterNameKey is the attribute Key conforming to the + // "k8s.cluster.name" semantic conventions. It represents the name of the + // cluster. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry-cluster' + K8SClusterNameKey = attribute.Key("k8s.cluster.name") + + // K8SClusterUIDKey is the attribute Key conforming to the + // "k8s.cluster.uid" semantic conventions. It represents a pseudo-ID for + // the cluster, set to the UID of the `kube-system` namespace. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '218fc5a9-a5f1-4b54-aa05-46717d0ab26d' + // Note: K8S does not have support for obtaining a cluster ID. If this is + // ever + // added, we will recommend collecting the `k8s.cluster.uid` through the + // official APIs. In the meantime, we are able to use the `uid` of the + // `kube-system` namespace as a proxy for cluster ID. Read on for the + // rationale. + // + // Every object created in a K8S cluster is assigned a distinct UID. The + // `kube-system` namespace is used by Kubernetes itself and will exist + // for the lifetime of the cluster. Using the `uid` of the `kube-system` + // namespace is a reasonable proxy for the K8S ClusterID as it will only + // change if the cluster is rebuilt. Furthermore, Kubernetes UIDs are + // UUIDs as standardized by + // [ISO/IEC 9834-8 and ITU-T + // X.667](https://www.itu.int/ITU-T/studygroups/com17/oid.html). + // Which states: + // + // > If generated according to one of the mechanisms defined in Rec. + // ITU-T X.667 | ISO/IEC 9834-8, a UUID is either guaranteed to be + // different from all other UUIDs generated before 3603 A.D., or is + // extremely likely to be different (depending on the mechanism chosen). + // + // Therefore, UIDs between clusters should be extremely unlikely to + // conflict. + K8SClusterUIDKey = attribute.Key("k8s.cluster.uid") +) + +// K8SClusterName returns an attribute KeyValue conforming to the +// "k8s.cluster.name" semantic conventions. It represents the name of the +// cluster. +func K8SClusterName(val string) attribute.KeyValue { + return K8SClusterNameKey.String(val) +} + +// K8SClusterUID returns an attribute KeyValue conforming to the +// "k8s.cluster.uid" semantic conventions. It represents a pseudo-ID for the +// cluster, set to the UID of the `kube-system` namespace. +func K8SClusterUID(val string) attribute.KeyValue { + return K8SClusterUIDKey.String(val) +} + +// A Kubernetes Node object. +const ( + // K8SNodeNameKey is the attribute Key conforming to the "k8s.node.name" + // semantic conventions. It represents the name of the Node. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'node-1' + K8SNodeNameKey = attribute.Key("k8s.node.name") + + // K8SNodeUIDKey is the attribute Key conforming to the "k8s.node.uid" + // semantic conventions. It represents the UID of the Node. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '1eb3a0c6-0477-4080-a9cb-0cb7db65c6a2' + K8SNodeUIDKey = attribute.Key("k8s.node.uid") +) + +// K8SNodeName returns an attribute KeyValue conforming to the +// "k8s.node.name" semantic conventions. It represents the name of the Node. +func K8SNodeName(val string) attribute.KeyValue { + return K8SNodeNameKey.String(val) +} + +// K8SNodeUID returns an attribute KeyValue conforming to the "k8s.node.uid" +// semantic conventions. It represents the UID of the Node. +func K8SNodeUID(val string) attribute.KeyValue { + return K8SNodeUIDKey.String(val) +} + +// A Kubernetes Namespace. +const ( + // K8SNamespaceNameKey is the attribute Key conforming to the + // "k8s.namespace.name" semantic conventions. It represents the name of the + // namespace that the pod is running in. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'default' + K8SNamespaceNameKey = attribute.Key("k8s.namespace.name") +) + +// K8SNamespaceName returns an attribute KeyValue conforming to the +// "k8s.namespace.name" semantic conventions. It represents the name of the +// namespace that the pod is running in. +func K8SNamespaceName(val string) attribute.KeyValue { + return K8SNamespaceNameKey.String(val) +} + +// A Kubernetes Pod object. +const ( + // K8SPodUIDKey is the attribute Key conforming to the "k8s.pod.uid" + // semantic conventions. It represents the UID of the Pod. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SPodUIDKey = attribute.Key("k8s.pod.uid") + + // K8SPodNameKey is the attribute Key conforming to the "k8s.pod.name" + // semantic conventions. It represents the name of the Pod. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry-pod-autoconf' + K8SPodNameKey = attribute.Key("k8s.pod.name") +) + +// K8SPodUID returns an attribute KeyValue conforming to the "k8s.pod.uid" +// semantic conventions. It represents the UID of the Pod. +func K8SPodUID(val string) attribute.KeyValue { + return K8SPodUIDKey.String(val) +} + +// K8SPodName returns an attribute KeyValue conforming to the "k8s.pod.name" +// semantic conventions. It represents the name of the Pod. +func K8SPodName(val string) attribute.KeyValue { + return K8SPodNameKey.String(val) +} + +// A container in a +// [PodTemplate](https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates). +const ( + // K8SContainerNameKey is the attribute Key conforming to the + // "k8s.container.name" semantic conventions. It represents the name of the + // Container from Pod specification, must be unique within a Pod. Container + // runtime usually uses different globally unique name (`container.name`). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'redis' + K8SContainerNameKey = attribute.Key("k8s.container.name") + + // K8SContainerRestartCountKey is the attribute Key conforming to the + // "k8s.container.restart_count" semantic conventions. It represents the + // number of times the container was restarted. This attribute can be used + // to identify a particular container (running or stopped) within a + // container spec. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 0, 2 + K8SContainerRestartCountKey = attribute.Key("k8s.container.restart_count") +) + +// K8SContainerName returns an attribute KeyValue conforming to the +// "k8s.container.name" semantic conventions. It represents the name of the +// Container from Pod specification, must be unique within a Pod. Container +// runtime usually uses different globally unique name (`container.name`). +func K8SContainerName(val string) attribute.KeyValue { + return K8SContainerNameKey.String(val) +} + +// K8SContainerRestartCount returns an attribute KeyValue conforming to the +// "k8s.container.restart_count" semantic conventions. It represents the number +// of times the container was restarted. This attribute can be used to identify +// a particular container (running or stopped) within a container spec. +func K8SContainerRestartCount(val int) attribute.KeyValue { + return K8SContainerRestartCountKey.Int(val) +} + +// A Kubernetes ReplicaSet object. +const ( + // K8SReplicaSetUIDKey is the attribute Key conforming to the + // "k8s.replicaset.uid" semantic conventions. It represents the UID of the + // ReplicaSet. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SReplicaSetUIDKey = attribute.Key("k8s.replicaset.uid") + + // K8SReplicaSetNameKey is the attribute Key conforming to the + // "k8s.replicaset.name" semantic conventions. It represents the name of + // the ReplicaSet. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry' + K8SReplicaSetNameKey = attribute.Key("k8s.replicaset.name") +) + +// K8SReplicaSetUID returns an attribute KeyValue conforming to the +// "k8s.replicaset.uid" semantic conventions. It represents the UID of the +// ReplicaSet. +func K8SReplicaSetUID(val string) attribute.KeyValue { + return K8SReplicaSetUIDKey.String(val) +} + +// K8SReplicaSetName returns an attribute KeyValue conforming to the +// "k8s.replicaset.name" semantic conventions. It represents the name of the +// ReplicaSet. +func K8SReplicaSetName(val string) attribute.KeyValue { + return K8SReplicaSetNameKey.String(val) +} + +// A Kubernetes Deployment object. +const ( + // K8SDeploymentUIDKey is the attribute Key conforming to the + // "k8s.deployment.uid" semantic conventions. It represents the UID of the + // Deployment. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SDeploymentUIDKey = attribute.Key("k8s.deployment.uid") + + // K8SDeploymentNameKey is the attribute Key conforming to the + // "k8s.deployment.name" semantic conventions. It represents the name of + // the Deployment. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry' + K8SDeploymentNameKey = attribute.Key("k8s.deployment.name") +) + +// K8SDeploymentUID returns an attribute KeyValue conforming to the +// "k8s.deployment.uid" semantic conventions. It represents the UID of the +// Deployment. +func K8SDeploymentUID(val string) attribute.KeyValue { + return K8SDeploymentUIDKey.String(val) +} + +// K8SDeploymentName returns an attribute KeyValue conforming to the +// "k8s.deployment.name" semantic conventions. It represents the name of the +// Deployment. +func K8SDeploymentName(val string) attribute.KeyValue { + return K8SDeploymentNameKey.String(val) +} + +// A Kubernetes StatefulSet object. +const ( + // K8SStatefulSetUIDKey is the attribute Key conforming to the + // "k8s.statefulset.uid" semantic conventions. It represents the UID of the + // StatefulSet. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SStatefulSetUIDKey = attribute.Key("k8s.statefulset.uid") + + // K8SStatefulSetNameKey is the attribute Key conforming to the + // "k8s.statefulset.name" semantic conventions. It represents the name of + // the StatefulSet. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry' + K8SStatefulSetNameKey = attribute.Key("k8s.statefulset.name") +) + +// K8SStatefulSetUID returns an attribute KeyValue conforming to the +// "k8s.statefulset.uid" semantic conventions. It represents the UID of the +// StatefulSet. +func K8SStatefulSetUID(val string) attribute.KeyValue { + return K8SStatefulSetUIDKey.String(val) +} + +// K8SStatefulSetName returns an attribute KeyValue conforming to the +// "k8s.statefulset.name" semantic conventions. It represents the name of the +// StatefulSet. +func K8SStatefulSetName(val string) attribute.KeyValue { + return K8SStatefulSetNameKey.String(val) +} + +// A Kubernetes DaemonSet object. +const ( + // K8SDaemonSetUIDKey is the attribute Key conforming to the + // "k8s.daemonset.uid" semantic conventions. It represents the UID of the + // DaemonSet. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SDaemonSetUIDKey = attribute.Key("k8s.daemonset.uid") + + // K8SDaemonSetNameKey is the attribute Key conforming to the + // "k8s.daemonset.name" semantic conventions. It represents the name of the + // DaemonSet. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry' + K8SDaemonSetNameKey = attribute.Key("k8s.daemonset.name") +) + +// K8SDaemonSetUID returns an attribute KeyValue conforming to the +// "k8s.daemonset.uid" semantic conventions. It represents the UID of the +// DaemonSet. +func K8SDaemonSetUID(val string) attribute.KeyValue { + return K8SDaemonSetUIDKey.String(val) +} + +// K8SDaemonSetName returns an attribute KeyValue conforming to the +// "k8s.daemonset.name" semantic conventions. It represents the name of the +// DaemonSet. +func K8SDaemonSetName(val string) attribute.KeyValue { + return K8SDaemonSetNameKey.String(val) +} + +// A Kubernetes Job object. +const ( + // K8SJobUIDKey is the attribute Key conforming to the "k8s.job.uid" + // semantic conventions. It represents the UID of the Job. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SJobUIDKey = attribute.Key("k8s.job.uid") + + // K8SJobNameKey is the attribute Key conforming to the "k8s.job.name" + // semantic conventions. It represents the name of the Job. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry' + K8SJobNameKey = attribute.Key("k8s.job.name") +) + +// K8SJobUID returns an attribute KeyValue conforming to the "k8s.job.uid" +// semantic conventions. It represents the UID of the Job. +func K8SJobUID(val string) attribute.KeyValue { + return K8SJobUIDKey.String(val) +} + +// K8SJobName returns an attribute KeyValue conforming to the "k8s.job.name" +// semantic conventions. It represents the name of the Job. +func K8SJobName(val string) attribute.KeyValue { + return K8SJobNameKey.String(val) +} + +// A Kubernetes CronJob object. +const ( + // K8SCronJobUIDKey is the attribute Key conforming to the + // "k8s.cronjob.uid" semantic conventions. It represents the UID of the + // CronJob. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' + K8SCronJobUIDKey = attribute.Key("k8s.cronjob.uid") + + // K8SCronJobNameKey is the attribute Key conforming to the + // "k8s.cronjob.name" semantic conventions. It represents the name of the + // CronJob. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'opentelemetry' + K8SCronJobNameKey = attribute.Key("k8s.cronjob.name") +) + +// K8SCronJobUID returns an attribute KeyValue conforming to the +// "k8s.cronjob.uid" semantic conventions. It represents the UID of the +// CronJob. +func K8SCronJobUID(val string) attribute.KeyValue { + return K8SCronJobUIDKey.String(val) +} + +// K8SCronJobName returns an attribute KeyValue conforming to the +// "k8s.cronjob.name" semantic conventions. It represents the name of the +// CronJob. +func K8SCronJobName(val string) attribute.KeyValue { + return K8SCronJobNameKey.String(val) +} + +// The operating system (OS) on which the process represented by this resource +// is running. +const ( + // OSTypeKey is the attribute Key conforming to the "os.type" semantic + // conventions. It represents the operating system type. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + OSTypeKey = attribute.Key("os.type") + + // OSDescriptionKey is the attribute Key conforming to the "os.description" + // semantic conventions. It represents the human readable (not intended to + // be parsed) OS version information, like e.g. reported by `ver` or + // `lsb_release -a` commands. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Microsoft Windows [Version 10.0.18363.778]', 'Ubuntu 18.04.1 + // LTS' + OSDescriptionKey = attribute.Key("os.description") + + // OSNameKey is the attribute Key conforming to the "os.name" semantic + // conventions. It represents the human readable operating system name. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'iOS', 'Android', 'Ubuntu' + OSNameKey = attribute.Key("os.name") + + // OSVersionKey is the attribute Key conforming to the "os.version" + // semantic conventions. It represents the version string of the operating + // system as defined in [Version + // Attributes](/docs/resource/README.md#version-attributes). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '14.2.1', '18.04.1' + OSVersionKey = attribute.Key("os.version") +) + +var ( + // Microsoft Windows + OSTypeWindows = OSTypeKey.String("windows") + // Linux + OSTypeLinux = OSTypeKey.String("linux") + // Apple Darwin + OSTypeDarwin = OSTypeKey.String("darwin") + // FreeBSD + OSTypeFreeBSD = OSTypeKey.String("freebsd") + // NetBSD + OSTypeNetBSD = OSTypeKey.String("netbsd") + // OpenBSD + OSTypeOpenBSD = OSTypeKey.String("openbsd") + // DragonFly BSD + OSTypeDragonflyBSD = OSTypeKey.String("dragonflybsd") + // HP-UX (Hewlett Packard Unix) + OSTypeHPUX = OSTypeKey.String("hpux") + // AIX (Advanced Interactive eXecutive) + OSTypeAIX = OSTypeKey.String("aix") + // SunOS, Oracle Solaris + OSTypeSolaris = OSTypeKey.String("solaris") + // IBM z/OS + OSTypeZOS = OSTypeKey.String("z_os") +) + +// OSDescription returns an attribute KeyValue conforming to the +// "os.description" semantic conventions. It represents the human readable (not +// intended to be parsed) OS version information, like e.g. reported by `ver` +// or `lsb_release -a` commands. +func OSDescription(val string) attribute.KeyValue { + return OSDescriptionKey.String(val) +} + +// OSName returns an attribute KeyValue conforming to the "os.name" semantic +// conventions. It represents the human readable operating system name. +func OSName(val string) attribute.KeyValue { + return OSNameKey.String(val) +} + +// OSVersion returns an attribute KeyValue conforming to the "os.version" +// semantic conventions. It represents the version string of the operating +// system as defined in [Version +// Attributes](/docs/resource/README.md#version-attributes). +func OSVersion(val string) attribute.KeyValue { + return OSVersionKey.String(val) +} + +// An operating system process. +const ( + // ProcessPIDKey is the attribute Key conforming to the "process.pid" + // semantic conventions. It represents the process identifier (PID). + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 1234 + ProcessPIDKey = attribute.Key("process.pid") + + // ProcessParentPIDKey is the attribute Key conforming to the + // "process.parent_pid" semantic conventions. It represents the parent + // Process identifier (PID). + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 111 + ProcessParentPIDKey = attribute.Key("process.parent_pid") + + // ProcessExecutableNameKey is the attribute Key conforming to the + // "process.executable.name" semantic conventions. It represents the name + // of the process executable. On Linux based systems, can be set to the + // `Name` in `proc/[pid]/status`. On Windows, can be set to the base name + // of `GetProcessImageFileNameW`. + // + // Type: string + // RequirementLevel: ConditionallyRequired (See alternative attributes + // below.) + // Stability: stable + // Examples: 'otelcol' + ProcessExecutableNameKey = attribute.Key("process.executable.name") + + // ProcessExecutablePathKey is the attribute Key conforming to the + // "process.executable.path" semantic conventions. It represents the full + // path to the process executable. On Linux based systems, can be set to + // the target of `proc/[pid]/exe`. On Windows, can be set to the result of + // `GetProcessImageFileNameW`. + // + // Type: string + // RequirementLevel: ConditionallyRequired (See alternative attributes + // below.) + // Stability: stable + // Examples: '/usr/bin/cmd/otelcol' + ProcessExecutablePathKey = attribute.Key("process.executable.path") + + // ProcessCommandKey is the attribute Key conforming to the + // "process.command" semantic conventions. It represents the command used + // to launch the process (i.e. the command name). On Linux based systems, + // can be set to the zeroth string in `proc/[pid]/cmdline`. On Windows, can + // be set to the first parameter extracted from `GetCommandLineW`. + // + // Type: string + // RequirementLevel: ConditionallyRequired (See alternative attributes + // below.) + // Stability: stable + // Examples: 'cmd/otelcol' + ProcessCommandKey = attribute.Key("process.command") + + // ProcessCommandLineKey is the attribute Key conforming to the + // "process.command_line" semantic conventions. It represents the full + // command used to launch the process as a single string representing the + // full command. On Windows, can be set to the result of `GetCommandLineW`. + // Do not set this if you have to assemble it just for monitoring; use + // `process.command_args` instead. + // + // Type: string + // RequirementLevel: ConditionallyRequired (See alternative attributes + // below.) + // Stability: stable + // Examples: 'C:\\cmd\\otecol --config="my directory\\config.yaml"' + ProcessCommandLineKey = attribute.Key("process.command_line") + + // ProcessCommandArgsKey is the attribute Key conforming to the + // "process.command_args" semantic conventions. It represents the all the + // command arguments (including the command/executable itself) as received + // by the process. On Linux-based systems (and some other Unixoid systems + // supporting procfs), can be set according to the list of null-delimited + // strings extracted from `proc/[pid]/cmdline`. For libc-based executables, + // this would be the full argv vector passed to `main`. + // + // Type: string[] + // RequirementLevel: ConditionallyRequired (See alternative attributes + // below.) + // Stability: stable + // Examples: 'cmd/otecol', '--config=config.yaml' + ProcessCommandArgsKey = attribute.Key("process.command_args") + + // ProcessOwnerKey is the attribute Key conforming to the "process.owner" + // semantic conventions. It represents the username of the user that owns + // the process. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'root' + ProcessOwnerKey = attribute.Key("process.owner") +) + +// ProcessPID returns an attribute KeyValue conforming to the "process.pid" +// semantic conventions. It represents the process identifier (PID). +func ProcessPID(val int) attribute.KeyValue { + return ProcessPIDKey.Int(val) +} + +// ProcessParentPID returns an attribute KeyValue conforming to the +// "process.parent_pid" semantic conventions. It represents the parent Process +// identifier (PID). +func ProcessParentPID(val int) attribute.KeyValue { + return ProcessParentPIDKey.Int(val) +} + +// ProcessExecutableName returns an attribute KeyValue conforming to the +// "process.executable.name" semantic conventions. It represents the name of +// the process executable. On Linux based systems, can be set to the `Name` in +// `proc/[pid]/status`. On Windows, can be set to the base name of +// `GetProcessImageFileNameW`. +func ProcessExecutableName(val string) attribute.KeyValue { + return ProcessExecutableNameKey.String(val) +} + +// ProcessExecutablePath returns an attribute KeyValue conforming to the +// "process.executable.path" semantic conventions. It represents the full path +// to the process executable. On Linux based systems, can be set to the target +// of `proc/[pid]/exe`. On Windows, can be set to the result of +// `GetProcessImageFileNameW`. +func ProcessExecutablePath(val string) attribute.KeyValue { + return ProcessExecutablePathKey.String(val) +} + +// ProcessCommand returns an attribute KeyValue conforming to the +// "process.command" semantic conventions. It represents the command used to +// launch the process (i.e. the command name). On Linux based systems, can be +// set to the zeroth string in `proc/[pid]/cmdline`. On Windows, can be set to +// the first parameter extracted from `GetCommandLineW`. +func ProcessCommand(val string) attribute.KeyValue { + return ProcessCommandKey.String(val) +} + +// ProcessCommandLine returns an attribute KeyValue conforming to the +// "process.command_line" semantic conventions. It represents the full command +// used to launch the process as a single string representing the full command. +// On Windows, can be set to the result of `GetCommandLineW`. Do not set this +// if you have to assemble it just for monitoring; use `process.command_args` +// instead. +func ProcessCommandLine(val string) attribute.KeyValue { + return ProcessCommandLineKey.String(val) +} + +// ProcessCommandArgs returns an attribute KeyValue conforming to the +// "process.command_args" semantic conventions. It represents the all the +// command arguments (including the command/executable itself) as received by +// the process. On Linux-based systems (and some other Unixoid systems +// supporting procfs), can be set according to the list of null-delimited +// strings extracted from `proc/[pid]/cmdline`. For libc-based executables, +// this would be the full argv vector passed to `main`. +func ProcessCommandArgs(val ...string) attribute.KeyValue { + return ProcessCommandArgsKey.StringSlice(val) +} + +// ProcessOwner returns an attribute KeyValue conforming to the +// "process.owner" semantic conventions. It represents the username of the user +// that owns the process. +func ProcessOwner(val string) attribute.KeyValue { + return ProcessOwnerKey.String(val) +} + +// The single (language) runtime instance which is monitored. +const ( + // ProcessRuntimeNameKey is the attribute Key conforming to the + // "process.runtime.name" semantic conventions. It represents the name of + // the runtime of this process. For compiled native binaries, this SHOULD + // be the name of the compiler. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'OpenJDK Runtime Environment' + ProcessRuntimeNameKey = attribute.Key("process.runtime.name") + + // ProcessRuntimeVersionKey is the attribute Key conforming to the + // "process.runtime.version" semantic conventions. It represents the + // version of the runtime of this process, as returned by the runtime + // without modification. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '14.0.2' + ProcessRuntimeVersionKey = attribute.Key("process.runtime.version") + + // ProcessRuntimeDescriptionKey is the attribute Key conforming to the + // "process.runtime.description" semantic conventions. It represents an + // additional description about the runtime of the process, for example a + // specific vendor customization of the runtime environment. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Eclipse OpenJ9 Eclipse OpenJ9 VM openj9-0.21.0' + ProcessRuntimeDescriptionKey = attribute.Key("process.runtime.description") +) + +// ProcessRuntimeName returns an attribute KeyValue conforming to the +// "process.runtime.name" semantic conventions. It represents the name of the +// runtime of this process. For compiled native binaries, this SHOULD be the +// name of the compiler. +func ProcessRuntimeName(val string) attribute.KeyValue { + return ProcessRuntimeNameKey.String(val) +} + +// ProcessRuntimeVersion returns an attribute KeyValue conforming to the +// "process.runtime.version" semantic conventions. It represents the version of +// the runtime of this process, as returned by the runtime without +// modification. +func ProcessRuntimeVersion(val string) attribute.KeyValue { + return ProcessRuntimeVersionKey.String(val) +} + +// ProcessRuntimeDescription returns an attribute KeyValue conforming to the +// "process.runtime.description" semantic conventions. It represents an +// additional description about the runtime of the process, for example a +// specific vendor customization of the runtime environment. +func ProcessRuntimeDescription(val string) attribute.KeyValue { + return ProcessRuntimeDescriptionKey.String(val) +} + +// A service instance. +const ( + // ServiceNameKey is the attribute Key conforming to the "service.name" + // semantic conventions. It represents the logical name of the service. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'shoppingcart' + // Note: MUST be the same for all instances of horizontally scaled + // services. If the value was not specified, SDKs MUST fallback to + // `unknown_service:` concatenated with + // [`process.executable.name`](process.md#process), e.g. + // `unknown_service:bash`. If `process.executable.name` is not available, + // the value MUST be set to `unknown_service`. + ServiceNameKey = attribute.Key("service.name") + + // ServiceVersionKey is the attribute Key conforming to the + // "service.version" semantic conventions. It represents the version string + // of the service API or implementation. The format is not defined by these + // conventions. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2.0.0', 'a01dbef8a' + ServiceVersionKey = attribute.Key("service.version") +) + +// ServiceName returns an attribute KeyValue conforming to the +// "service.name" semantic conventions. It represents the logical name of the +// service. +func ServiceName(val string) attribute.KeyValue { + return ServiceNameKey.String(val) +} + +// ServiceVersion returns an attribute KeyValue conforming to the +// "service.version" semantic conventions. It represents the version string of +// the service API or implementation. The format is not defined by these +// conventions. +func ServiceVersion(val string) attribute.KeyValue { + return ServiceVersionKey.String(val) +} + +// A service instance. +const ( + // ServiceNamespaceKey is the attribute Key conforming to the + // "service.namespace" semantic conventions. It represents a namespace for + // `service.name`. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Shop' + // Note: A string value having a meaning that helps to distinguish a group + // of services, for example the team name that owns a group of services. + // `service.name` is expected to be unique within the same namespace. If + // `service.namespace` is not specified in the Resource then `service.name` + // is expected to be unique for all services that have no explicit + // namespace defined (so the empty/unspecified namespace is simply one more + // valid namespace). Zero-length namespace string is assumed equal to + // unspecified namespace. + ServiceNamespaceKey = attribute.Key("service.namespace") + + // ServiceInstanceIDKey is the attribute Key conforming to the + // "service.instance.id" semantic conventions. It represents the string ID + // of the service instance. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'my-k8s-pod-deployment-1', + // '627cc493-f310-47de-96bd-71410b7dec09' + // Note: MUST be unique for each instance of the same + // `service.namespace,service.name` pair (in other words + // `service.namespace,service.name,service.instance.id` triplet MUST be + // globally unique). The ID helps to distinguish instances of the same + // service that exist at the same time (e.g. instances of a horizontally + // scaled service). It is preferable for the ID to be persistent and stay + // the same for the lifetime of the service instance, however it is + // acceptable that the ID is ephemeral and changes during important + // lifetime events for the service (e.g. service restarts). If the service + // has no inherent unique ID that can be used as the value of this + // attribute it is recommended to generate a random Version 1 or Version 4 + // RFC 4122 UUID (services aiming for reproducible UUIDs may also use + // Version 5, see RFC 4122 for more recommendations). + ServiceInstanceIDKey = attribute.Key("service.instance.id") +) + +// ServiceNamespace returns an attribute KeyValue conforming to the +// "service.namespace" semantic conventions. It represents a namespace for +// `service.name`. +func ServiceNamespace(val string) attribute.KeyValue { + return ServiceNamespaceKey.String(val) +} + +// ServiceInstanceID returns an attribute KeyValue conforming to the +// "service.instance.id" semantic conventions. It represents the string ID of +// the service instance. +func ServiceInstanceID(val string) attribute.KeyValue { + return ServiceInstanceIDKey.String(val) +} + +// The telemetry SDK used to capture data recorded by the instrumentation +// libraries. +const ( + // TelemetrySDKNameKey is the attribute Key conforming to the + // "telemetry.sdk.name" semantic conventions. It represents the name of the + // telemetry SDK as defined above. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'opentelemetry' + // Note: The OpenTelemetry SDK MUST set the `telemetry.sdk.name` attribute + // to `opentelemetry`. + // If another SDK, like a fork or a vendor-provided implementation, is + // used, this SDK MUST set the + // `telemetry.sdk.name` attribute to the fully-qualified class or module + // name of this SDK's main entry point + // or another suitable identifier depending on the language. + // The identifier `opentelemetry` is reserved and MUST NOT be used in this + // case. + // All custom identifiers SHOULD be stable across different versions of an + // implementation. + TelemetrySDKNameKey = attribute.Key("telemetry.sdk.name") + + // TelemetrySDKLanguageKey is the attribute Key conforming to the + // "telemetry.sdk.language" semantic conventions. It represents the + // language of the telemetry SDK. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + TelemetrySDKLanguageKey = attribute.Key("telemetry.sdk.language") + + // TelemetrySDKVersionKey is the attribute Key conforming to the + // "telemetry.sdk.version" semantic conventions. It represents the version + // string of the telemetry SDK. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: '1.2.3' + TelemetrySDKVersionKey = attribute.Key("telemetry.sdk.version") +) + +var ( + // cpp + TelemetrySDKLanguageCPP = TelemetrySDKLanguageKey.String("cpp") + // dotnet + TelemetrySDKLanguageDotnet = TelemetrySDKLanguageKey.String("dotnet") + // erlang + TelemetrySDKLanguageErlang = TelemetrySDKLanguageKey.String("erlang") + // go + TelemetrySDKLanguageGo = TelemetrySDKLanguageKey.String("go") + // java + TelemetrySDKLanguageJava = TelemetrySDKLanguageKey.String("java") + // nodejs + TelemetrySDKLanguageNodejs = TelemetrySDKLanguageKey.String("nodejs") + // php + TelemetrySDKLanguagePHP = TelemetrySDKLanguageKey.String("php") + // python + TelemetrySDKLanguagePython = TelemetrySDKLanguageKey.String("python") + // ruby + TelemetrySDKLanguageRuby = TelemetrySDKLanguageKey.String("ruby") + // rust + TelemetrySDKLanguageRust = TelemetrySDKLanguageKey.String("rust") + // swift + TelemetrySDKLanguageSwift = TelemetrySDKLanguageKey.String("swift") + // webjs + TelemetrySDKLanguageWebjs = TelemetrySDKLanguageKey.String("webjs") +) + +// TelemetrySDKName returns an attribute KeyValue conforming to the +// "telemetry.sdk.name" semantic conventions. It represents the name of the +// telemetry SDK as defined above. +func TelemetrySDKName(val string) attribute.KeyValue { + return TelemetrySDKNameKey.String(val) +} + +// TelemetrySDKVersion returns an attribute KeyValue conforming to the +// "telemetry.sdk.version" semantic conventions. It represents the version +// string of the telemetry SDK. +func TelemetrySDKVersion(val string) attribute.KeyValue { + return TelemetrySDKVersionKey.String(val) +} + +// The telemetry SDK used to capture data recorded by the instrumentation +// libraries. +const ( + // TelemetryAutoVersionKey is the attribute Key conforming to the + // "telemetry.auto.version" semantic conventions. It represents the version + // string of the auto instrumentation agent, if used. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '1.2.3' + TelemetryAutoVersionKey = attribute.Key("telemetry.auto.version") +) + +// TelemetryAutoVersion returns an attribute KeyValue conforming to the +// "telemetry.auto.version" semantic conventions. It represents the version +// string of the auto instrumentation agent, if used. +func TelemetryAutoVersion(val string) attribute.KeyValue { + return TelemetryAutoVersionKey.String(val) +} + +// Resource describing the packaged software running the application code. Web +// engines are typically executed using process.runtime. +const ( + // WebEngineNameKey is the attribute Key conforming to the "webengine.name" + // semantic conventions. It represents the name of the web engine. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'WildFly' + WebEngineNameKey = attribute.Key("webengine.name") + + // WebEngineVersionKey is the attribute Key conforming to the + // "webengine.version" semantic conventions. It represents the version of + // the web engine. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '21.0.0' + WebEngineVersionKey = attribute.Key("webengine.version") + + // WebEngineDescriptionKey is the attribute Key conforming to the + // "webengine.description" semantic conventions. It represents the + // additional description of the web engine (e.g. detailed version and + // edition information). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'WildFly Full 21.0.0.Final (WildFly Core 13.0.1.Final) - + // 2.2.2.Final' + WebEngineDescriptionKey = attribute.Key("webengine.description") +) + +// WebEngineName returns an attribute KeyValue conforming to the +// "webengine.name" semantic conventions. It represents the name of the web +// engine. +func WebEngineName(val string) attribute.KeyValue { + return WebEngineNameKey.String(val) +} + +// WebEngineVersion returns an attribute KeyValue conforming to the +// "webengine.version" semantic conventions. It represents the version of the +// web engine. +func WebEngineVersion(val string) attribute.KeyValue { + return WebEngineVersionKey.String(val) +} + +// WebEngineDescription returns an attribute KeyValue conforming to the +// "webengine.description" semantic conventions. It represents the additional +// description of the web engine (e.g. detailed version and edition +// information). +func WebEngineDescription(val string) attribute.KeyValue { + return WebEngineDescriptionKey.String(val) +} + +// Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's +// concepts. +const ( + // OTelScopeNameKey is the attribute Key conforming to the + // "otel.scope.name" semantic conventions. It represents the name of the + // instrumentation scope - (`InstrumentationScope.Name` in OTLP). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'io.opentelemetry.contrib.mongodb' + OTelScopeNameKey = attribute.Key("otel.scope.name") + + // OTelScopeVersionKey is the attribute Key conforming to the + // "otel.scope.version" semantic conventions. It represents the version of + // the instrumentation scope - (`InstrumentationScope.Version` in OTLP). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '1.0.0' + OTelScopeVersionKey = attribute.Key("otel.scope.version") +) + +// OTelScopeName returns an attribute KeyValue conforming to the +// "otel.scope.name" semantic conventions. It represents the name of the +// instrumentation scope - (`InstrumentationScope.Name` in OTLP). +func OTelScopeName(val string) attribute.KeyValue { + return OTelScopeNameKey.String(val) +} + +// OTelScopeVersion returns an attribute KeyValue conforming to the +// "otel.scope.version" semantic conventions. It represents the version of the +// instrumentation scope - (`InstrumentationScope.Version` in OTLP). +func OTelScopeVersion(val string) attribute.KeyValue { + return OTelScopeVersionKey.String(val) +} + +// Span attributes used by non-OTLP exporters to represent OpenTelemetry +// Scope's concepts. +const ( + // OTelLibraryNameKey is the attribute Key conforming to the + // "otel.library.name" semantic conventions. It represents the deprecated, + // use the `otel.scope.name` attribute. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: 'io.opentelemetry.contrib.mongodb' + OTelLibraryNameKey = attribute.Key("otel.library.name") + + // OTelLibraryVersionKey is the attribute Key conforming to the + // "otel.library.version" semantic conventions. It represents the + // deprecated, use the `otel.scope.version` attribute. + // + // Type: string + // RequirementLevel: Optional + // Stability: deprecated + // Examples: '1.0.0' + OTelLibraryVersionKey = attribute.Key("otel.library.version") +) + +// OTelLibraryName returns an attribute KeyValue conforming to the +// "otel.library.name" semantic conventions. It represents the deprecated, use +// the `otel.scope.name` attribute. +func OTelLibraryName(val string) attribute.KeyValue { + return OTelLibraryNameKey.String(val) +} + +// OTelLibraryVersion returns an attribute KeyValue conforming to the +// "otel.library.version" semantic conventions. It represents the deprecated, +// use the `otel.scope.version` attribute. +func OTelLibraryVersion(val string) attribute.KeyValue { + return OTelLibraryVersionKey.String(val) +} diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/schema.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/schema.go new file mode 100644 index 00000000..66ffd598 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/schema.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" + +// SchemaURL is the schema URL that matches the version of the semantic conventions +// that this package defines. Semconv packages starting from v1.4.0 must declare +// non-empty schema URL in the form https://opentelemetry.io/schemas/ +const SchemaURL = "https://opentelemetry.io/schemas/1.21.0" diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/trace.go b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/trace.go new file mode 100644 index 00000000..b5a91450 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/semconv/v1.21.0/trace.go @@ -0,0 +1,2495 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated from semantic convention specification. DO NOT EDIT. + +package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0" + +import "go.opentelemetry.io/otel/attribute" + +// The shared attributes used to report a single exception associated with a +// span or log. +const ( + // ExceptionTypeKey is the attribute Key conforming to the "exception.type" + // semantic conventions. It represents the type of the exception (its + // fully-qualified class name, if applicable). The dynamic type of the + // exception should be preferred over the static type in languages that + // support it. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'java.net.ConnectException', 'OSError' + ExceptionTypeKey = attribute.Key("exception.type") + + // ExceptionMessageKey is the attribute Key conforming to the + // "exception.message" semantic conventions. It represents the exception + // message. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Division by zero', "Can't convert 'int' object to str + // implicitly" + ExceptionMessageKey = attribute.Key("exception.message") + + // ExceptionStacktraceKey is the attribute Key conforming to the + // "exception.stacktrace" semantic conventions. It represents a stacktrace + // as a string in the natural representation for the language runtime. The + // representation is to be determined and documented by each language SIG. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Exception in thread "main" java.lang.RuntimeException: Test + // exception\\n at ' + // 'com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at ' + // 'com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at ' + // 'com.example.GenerateTrace.main(GenerateTrace.java:5)' + ExceptionStacktraceKey = attribute.Key("exception.stacktrace") +) + +// ExceptionType returns an attribute KeyValue conforming to the +// "exception.type" semantic conventions. It represents the type of the +// exception (its fully-qualified class name, if applicable). The dynamic type +// of the exception should be preferred over the static type in languages that +// support it. +func ExceptionType(val string) attribute.KeyValue { + return ExceptionTypeKey.String(val) +} + +// ExceptionMessage returns an attribute KeyValue conforming to the +// "exception.message" semantic conventions. It represents the exception +// message. +func ExceptionMessage(val string) attribute.KeyValue { + return ExceptionMessageKey.String(val) +} + +// ExceptionStacktrace returns an attribute KeyValue conforming to the +// "exception.stacktrace" semantic conventions. It represents a stacktrace as a +// string in the natural representation for the language runtime. The +// representation is to be determined and documented by each language SIG. +func ExceptionStacktrace(val string) attribute.KeyValue { + return ExceptionStacktraceKey.String(val) +} + +// Span attributes used by AWS Lambda (in addition to general `faas` +// attributes). +const ( + // AWSLambdaInvokedARNKey is the attribute Key conforming to the + // "aws.lambda.invoked_arn" semantic conventions. It represents the full + // invoked ARN as provided on the `Context` passed to the function + // (`Lambda-Runtime-Invoked-Function-ARN` header on the + // `/runtime/invocation/next` applicable). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'arn:aws:lambda:us-east-1:123456:function:myfunction:myalias' + // Note: This may be different from `cloud.resource_id` if an alias is + // involved. + AWSLambdaInvokedARNKey = attribute.Key("aws.lambda.invoked_arn") +) + +// AWSLambdaInvokedARN returns an attribute KeyValue conforming to the +// "aws.lambda.invoked_arn" semantic conventions. It represents the full +// invoked ARN as provided on the `Context` passed to the function +// (`Lambda-Runtime-Invoked-Function-ARN` header on the +// `/runtime/invocation/next` applicable). +func AWSLambdaInvokedARN(val string) attribute.KeyValue { + return AWSLambdaInvokedARNKey.String(val) +} + +// Attributes for CloudEvents. CloudEvents is a specification on how to define +// event data in a standard way. These attributes can be attached to spans when +// performing operations with CloudEvents, regardless of the protocol being +// used. +const ( + // CloudeventsEventIDKey is the attribute Key conforming to the + // "cloudevents.event_id" semantic conventions. It represents the + // [event_id](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#id) + // uniquely identifies the event. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: '123e4567-e89b-12d3-a456-426614174000', '0001' + CloudeventsEventIDKey = attribute.Key("cloudevents.event_id") + + // CloudeventsEventSourceKey is the attribute Key conforming to the + // "cloudevents.event_source" semantic conventions. It represents the + // [source](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#source-1) + // identifies the context in which an event happened. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'https://github.com/cloudevents', + // '/cloudevents/spec/pull/123', 'my-service' + CloudeventsEventSourceKey = attribute.Key("cloudevents.event_source") + + // CloudeventsEventSpecVersionKey is the attribute Key conforming to the + // "cloudevents.event_spec_version" semantic conventions. It represents the + // [version of the CloudEvents + // specification](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#specversion) + // which the event uses. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '1.0' + CloudeventsEventSpecVersionKey = attribute.Key("cloudevents.event_spec_version") + + // CloudeventsEventTypeKey is the attribute Key conforming to the + // "cloudevents.event_type" semantic conventions. It represents the + // [event_type](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#type) + // contains a value describing the type of event related to the originating + // occurrence. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'com.github.pull_request.opened', + // 'com.example.object.deleted.v2' + CloudeventsEventTypeKey = attribute.Key("cloudevents.event_type") + + // CloudeventsEventSubjectKey is the attribute Key conforming to the + // "cloudevents.event_subject" semantic conventions. It represents the + // [subject](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#subject) + // of the event in the context of the event producer (identified by + // source). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'mynewfile.jpg' + CloudeventsEventSubjectKey = attribute.Key("cloudevents.event_subject") +) + +// CloudeventsEventID returns an attribute KeyValue conforming to the +// "cloudevents.event_id" semantic conventions. It represents the +// [event_id](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#id) +// uniquely identifies the event. +func CloudeventsEventID(val string) attribute.KeyValue { + return CloudeventsEventIDKey.String(val) +} + +// CloudeventsEventSource returns an attribute KeyValue conforming to the +// "cloudevents.event_source" semantic conventions. It represents the +// [source](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#source-1) +// identifies the context in which an event happened. +func CloudeventsEventSource(val string) attribute.KeyValue { + return CloudeventsEventSourceKey.String(val) +} + +// CloudeventsEventSpecVersion returns an attribute KeyValue conforming to +// the "cloudevents.event_spec_version" semantic conventions. It represents the +// [version of the CloudEvents +// specification](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#specversion) +// which the event uses. +func CloudeventsEventSpecVersion(val string) attribute.KeyValue { + return CloudeventsEventSpecVersionKey.String(val) +} + +// CloudeventsEventType returns an attribute KeyValue conforming to the +// "cloudevents.event_type" semantic conventions. It represents the +// [event_type](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#type) +// contains a value describing the type of event related to the originating +// occurrence. +func CloudeventsEventType(val string) attribute.KeyValue { + return CloudeventsEventTypeKey.String(val) +} + +// CloudeventsEventSubject returns an attribute KeyValue conforming to the +// "cloudevents.event_subject" semantic conventions. It represents the +// [subject](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#subject) +// of the event in the context of the event producer (identified by source). +func CloudeventsEventSubject(val string) attribute.KeyValue { + return CloudeventsEventSubjectKey.String(val) +} + +// Semantic conventions for the OpenTracing Shim +const ( + // OpentracingRefTypeKey is the attribute Key conforming to the + // "opentracing.ref_type" semantic conventions. It represents the + // parent-child Reference type + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Note: The causal relationship between a child Span and a parent Span. + OpentracingRefTypeKey = attribute.Key("opentracing.ref_type") +) + +var ( + // The parent Span depends on the child Span in some capacity + OpentracingRefTypeChildOf = OpentracingRefTypeKey.String("child_of") + // The parent Span does not depend in any way on the result of the child Span + OpentracingRefTypeFollowsFrom = OpentracingRefTypeKey.String("follows_from") +) + +// The attributes used to perform database client calls. +const ( + // DBSystemKey is the attribute Key conforming to the "db.system" semantic + // conventions. It represents an identifier for the database management + // system (DBMS) product being used. See below for a list of well-known + // identifiers. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + DBSystemKey = attribute.Key("db.system") + + // DBConnectionStringKey is the attribute Key conforming to the + // "db.connection_string" semantic conventions. It represents the + // connection string used to connect to the database. It is recommended to + // remove embedded credentials. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Server=(localdb)\\v11.0;Integrated Security=true;' + DBConnectionStringKey = attribute.Key("db.connection_string") + + // DBUserKey is the attribute Key conforming to the "db.user" semantic + // conventions. It represents the username for accessing the database. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'readonly_user', 'reporting_user' + DBUserKey = attribute.Key("db.user") + + // DBJDBCDriverClassnameKey is the attribute Key conforming to the + // "db.jdbc.driver_classname" semantic conventions. It represents the + // fully-qualified class name of the [Java Database Connectivity + // (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) + // driver used to connect. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'org.postgresql.Driver', + // 'com.microsoft.sqlserver.jdbc.SQLServerDriver' + DBJDBCDriverClassnameKey = attribute.Key("db.jdbc.driver_classname") + + // DBNameKey is the attribute Key conforming to the "db.name" semantic + // conventions. It represents the this attribute is used to report the name + // of the database being accessed. For commands that switch the database, + // this should be set to the target database (even if the command fails). + // + // Type: string + // RequirementLevel: ConditionallyRequired (If applicable.) + // Stability: stable + // Examples: 'customers', 'main' + // Note: In some SQL databases, the database name to be used is called + // "schema name". In case there are multiple layers that could be + // considered for database name (e.g. Oracle instance name and schema + // name), the database name to be used is the more specific layer (e.g. + // Oracle schema name). + DBNameKey = attribute.Key("db.name") + + // DBStatementKey is the attribute Key conforming to the "db.statement" + // semantic conventions. It represents the database statement being + // executed. + // + // Type: string + // RequirementLevel: Recommended (Should be collected by default only if + // there is sanitization that excludes sensitive information.) + // Stability: stable + // Examples: 'SELECT * FROM wuser_table', 'SET mykey "WuValue"' + DBStatementKey = attribute.Key("db.statement") + + // DBOperationKey is the attribute Key conforming to the "db.operation" + // semantic conventions. It represents the name of the operation being + // executed, e.g. the [MongoDB command + // name](https://docs.mongodb.com/manual/reference/command/#database-operations) + // such as `findAndModify`, or the SQL keyword. + // + // Type: string + // RequirementLevel: ConditionallyRequired (If `db.statement` is not + // applicable.) + // Stability: stable + // Examples: 'findAndModify', 'HMSET', 'SELECT' + // Note: When setting this to an SQL keyword, it is not recommended to + // attempt any client-side parsing of `db.statement` just to get this + // property, but it should be set if the operation name is provided by the + // library being instrumented. If the SQL statement has an ambiguous + // operation, or performs more than one operation, this value may be + // omitted. + DBOperationKey = attribute.Key("db.operation") +) + +var ( + // Some other SQL database. Fallback only. See notes + DBSystemOtherSQL = DBSystemKey.String("other_sql") + // Microsoft SQL Server + DBSystemMSSQL = DBSystemKey.String("mssql") + // Microsoft SQL Server Compact + DBSystemMssqlcompact = DBSystemKey.String("mssqlcompact") + // MySQL + DBSystemMySQL = DBSystemKey.String("mysql") + // Oracle Database + DBSystemOracle = DBSystemKey.String("oracle") + // IBM DB2 + DBSystemDB2 = DBSystemKey.String("db2") + // PostgreSQL + DBSystemPostgreSQL = DBSystemKey.String("postgresql") + // Amazon Redshift + DBSystemRedshift = DBSystemKey.String("redshift") + // Apache Hive + DBSystemHive = DBSystemKey.String("hive") + // Cloudscape + DBSystemCloudscape = DBSystemKey.String("cloudscape") + // HyperSQL DataBase + DBSystemHSQLDB = DBSystemKey.String("hsqldb") + // Progress Database + DBSystemProgress = DBSystemKey.String("progress") + // SAP MaxDB + DBSystemMaxDB = DBSystemKey.String("maxdb") + // SAP HANA + DBSystemHanaDB = DBSystemKey.String("hanadb") + // Ingres + DBSystemIngres = DBSystemKey.String("ingres") + // FirstSQL + DBSystemFirstSQL = DBSystemKey.String("firstsql") + // EnterpriseDB + DBSystemEDB = DBSystemKey.String("edb") + // InterSystems Caché + DBSystemCache = DBSystemKey.String("cache") + // Adabas (Adaptable Database System) + DBSystemAdabas = DBSystemKey.String("adabas") + // Firebird + DBSystemFirebird = DBSystemKey.String("firebird") + // Apache Derby + DBSystemDerby = DBSystemKey.String("derby") + // FileMaker + DBSystemFilemaker = DBSystemKey.String("filemaker") + // Informix + DBSystemInformix = DBSystemKey.String("informix") + // InstantDB + DBSystemInstantDB = DBSystemKey.String("instantdb") + // InterBase + DBSystemInterbase = DBSystemKey.String("interbase") + // MariaDB + DBSystemMariaDB = DBSystemKey.String("mariadb") + // Netezza + DBSystemNetezza = DBSystemKey.String("netezza") + // Pervasive PSQL + DBSystemPervasive = DBSystemKey.String("pervasive") + // PointBase + DBSystemPointbase = DBSystemKey.String("pointbase") + // SQLite + DBSystemSqlite = DBSystemKey.String("sqlite") + // Sybase + DBSystemSybase = DBSystemKey.String("sybase") + // Teradata + DBSystemTeradata = DBSystemKey.String("teradata") + // Vertica + DBSystemVertica = DBSystemKey.String("vertica") + // H2 + DBSystemH2 = DBSystemKey.String("h2") + // ColdFusion IMQ + DBSystemColdfusion = DBSystemKey.String("coldfusion") + // Apache Cassandra + DBSystemCassandra = DBSystemKey.String("cassandra") + // Apache HBase + DBSystemHBase = DBSystemKey.String("hbase") + // MongoDB + DBSystemMongoDB = DBSystemKey.String("mongodb") + // Redis + DBSystemRedis = DBSystemKey.String("redis") + // Couchbase + DBSystemCouchbase = DBSystemKey.String("couchbase") + // CouchDB + DBSystemCouchDB = DBSystemKey.String("couchdb") + // Microsoft Azure Cosmos DB + DBSystemCosmosDB = DBSystemKey.String("cosmosdb") + // Amazon DynamoDB + DBSystemDynamoDB = DBSystemKey.String("dynamodb") + // Neo4j + DBSystemNeo4j = DBSystemKey.String("neo4j") + // Apache Geode + DBSystemGeode = DBSystemKey.String("geode") + // Elasticsearch + DBSystemElasticsearch = DBSystemKey.String("elasticsearch") + // Memcached + DBSystemMemcached = DBSystemKey.String("memcached") + // CockroachDB + DBSystemCockroachdb = DBSystemKey.String("cockroachdb") + // OpenSearch + DBSystemOpensearch = DBSystemKey.String("opensearch") + // ClickHouse + DBSystemClickhouse = DBSystemKey.String("clickhouse") + // Cloud Spanner + DBSystemSpanner = DBSystemKey.String("spanner") + // Trino + DBSystemTrino = DBSystemKey.String("trino") +) + +// DBConnectionString returns an attribute KeyValue conforming to the +// "db.connection_string" semantic conventions. It represents the connection +// string used to connect to the database. It is recommended to remove embedded +// credentials. +func DBConnectionString(val string) attribute.KeyValue { + return DBConnectionStringKey.String(val) +} + +// DBUser returns an attribute KeyValue conforming to the "db.user" semantic +// conventions. It represents the username for accessing the database. +func DBUser(val string) attribute.KeyValue { + return DBUserKey.String(val) +} + +// DBJDBCDriverClassname returns an attribute KeyValue conforming to the +// "db.jdbc.driver_classname" semantic conventions. It represents the +// fully-qualified class name of the [Java Database Connectivity +// (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver +// used to connect. +func DBJDBCDriverClassname(val string) attribute.KeyValue { + return DBJDBCDriverClassnameKey.String(val) +} + +// DBName returns an attribute KeyValue conforming to the "db.name" semantic +// conventions. It represents the this attribute is used to report the name of +// the database being accessed. For commands that switch the database, this +// should be set to the target database (even if the command fails). +func DBName(val string) attribute.KeyValue { + return DBNameKey.String(val) +} + +// DBStatement returns an attribute KeyValue conforming to the +// "db.statement" semantic conventions. It represents the database statement +// being executed. +func DBStatement(val string) attribute.KeyValue { + return DBStatementKey.String(val) +} + +// DBOperation returns an attribute KeyValue conforming to the +// "db.operation" semantic conventions. It represents the name of the operation +// being executed, e.g. the [MongoDB command +// name](https://docs.mongodb.com/manual/reference/command/#database-operations) +// such as `findAndModify`, or the SQL keyword. +func DBOperation(val string) attribute.KeyValue { + return DBOperationKey.String(val) +} + +// Connection-level attributes for Microsoft SQL Server +const ( + // DBMSSQLInstanceNameKey is the attribute Key conforming to the + // "db.mssql.instance_name" semantic conventions. It represents the + // Microsoft SQL Server [instance + // name](https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) + // connecting to. This name is used to determine the port of a named + // instance. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'MSSQLSERVER' + // Note: If setting a `db.mssql.instance_name`, `server.port` is no longer + // required (but still recommended if non-standard). + DBMSSQLInstanceNameKey = attribute.Key("db.mssql.instance_name") +) + +// DBMSSQLInstanceName returns an attribute KeyValue conforming to the +// "db.mssql.instance_name" semantic conventions. It represents the Microsoft +// SQL Server [instance +// name](https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) +// connecting to. This name is used to determine the port of a named instance. +func DBMSSQLInstanceName(val string) attribute.KeyValue { + return DBMSSQLInstanceNameKey.String(val) +} + +// Call-level attributes for Cassandra +const ( + // DBCassandraPageSizeKey is the attribute Key conforming to the + // "db.cassandra.page_size" semantic conventions. It represents the fetch + // size used for paging, i.e. how many rows will be returned at once. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 5000 + DBCassandraPageSizeKey = attribute.Key("db.cassandra.page_size") + + // DBCassandraConsistencyLevelKey is the attribute Key conforming to the + // "db.cassandra.consistency_level" semantic conventions. It represents the + // consistency level of the query. Based on consistency values from + // [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html). + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + DBCassandraConsistencyLevelKey = attribute.Key("db.cassandra.consistency_level") + + // DBCassandraTableKey is the attribute Key conforming to the + // "db.cassandra.table" semantic conventions. It represents the name of the + // primary table that the operation is acting upon, including the keyspace + // name (if applicable). + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'mytable' + // Note: This mirrors the db.sql.table attribute but references cassandra + // rather than sql. It is not recommended to attempt any client-side + // parsing of `db.statement` just to get this property, but it should be + // set if it is provided by the library being instrumented. If the + // operation is acting upon an anonymous table, or more than one table, + // this value MUST NOT be set. + DBCassandraTableKey = attribute.Key("db.cassandra.table") + + // DBCassandraIdempotenceKey is the attribute Key conforming to the + // "db.cassandra.idempotence" semantic conventions. It represents the + // whether or not the query is idempotent. + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + DBCassandraIdempotenceKey = attribute.Key("db.cassandra.idempotence") + + // DBCassandraSpeculativeExecutionCountKey is the attribute Key conforming + // to the "db.cassandra.speculative_execution_count" semantic conventions. + // It represents the number of times a query was speculatively executed. + // Not set or `0` if the query was not executed speculatively. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 0, 2 + DBCassandraSpeculativeExecutionCountKey = attribute.Key("db.cassandra.speculative_execution_count") + + // DBCassandraCoordinatorIDKey is the attribute Key conforming to the + // "db.cassandra.coordinator.id" semantic conventions. It represents the ID + // of the coordinating node for a query. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'be13faa2-8574-4d71-926d-27f16cf8a7af' + DBCassandraCoordinatorIDKey = attribute.Key("db.cassandra.coordinator.id") + + // DBCassandraCoordinatorDCKey is the attribute Key conforming to the + // "db.cassandra.coordinator.dc" semantic conventions. It represents the + // data center of the coordinating node for a query. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'us-west-2' + DBCassandraCoordinatorDCKey = attribute.Key("db.cassandra.coordinator.dc") +) + +var ( + // all + DBCassandraConsistencyLevelAll = DBCassandraConsistencyLevelKey.String("all") + // each_quorum + DBCassandraConsistencyLevelEachQuorum = DBCassandraConsistencyLevelKey.String("each_quorum") + // quorum + DBCassandraConsistencyLevelQuorum = DBCassandraConsistencyLevelKey.String("quorum") + // local_quorum + DBCassandraConsistencyLevelLocalQuorum = DBCassandraConsistencyLevelKey.String("local_quorum") + // one + DBCassandraConsistencyLevelOne = DBCassandraConsistencyLevelKey.String("one") + // two + DBCassandraConsistencyLevelTwo = DBCassandraConsistencyLevelKey.String("two") + // three + DBCassandraConsistencyLevelThree = DBCassandraConsistencyLevelKey.String("three") + // local_one + DBCassandraConsistencyLevelLocalOne = DBCassandraConsistencyLevelKey.String("local_one") + // any + DBCassandraConsistencyLevelAny = DBCassandraConsistencyLevelKey.String("any") + // serial + DBCassandraConsistencyLevelSerial = DBCassandraConsistencyLevelKey.String("serial") + // local_serial + DBCassandraConsistencyLevelLocalSerial = DBCassandraConsistencyLevelKey.String("local_serial") +) + +// DBCassandraPageSize returns an attribute KeyValue conforming to the +// "db.cassandra.page_size" semantic conventions. It represents the fetch size +// used for paging, i.e. how many rows will be returned at once. +func DBCassandraPageSize(val int) attribute.KeyValue { + return DBCassandraPageSizeKey.Int(val) +} + +// DBCassandraTable returns an attribute KeyValue conforming to the +// "db.cassandra.table" semantic conventions. It represents the name of the +// primary table that the operation is acting upon, including the keyspace name +// (if applicable). +func DBCassandraTable(val string) attribute.KeyValue { + return DBCassandraTableKey.String(val) +} + +// DBCassandraIdempotence returns an attribute KeyValue conforming to the +// "db.cassandra.idempotence" semantic conventions. It represents the whether +// or not the query is idempotent. +func DBCassandraIdempotence(val bool) attribute.KeyValue { + return DBCassandraIdempotenceKey.Bool(val) +} + +// DBCassandraSpeculativeExecutionCount returns an attribute KeyValue +// conforming to the "db.cassandra.speculative_execution_count" semantic +// conventions. It represents the number of times a query was speculatively +// executed. Not set or `0` if the query was not executed speculatively. +func DBCassandraSpeculativeExecutionCount(val int) attribute.KeyValue { + return DBCassandraSpeculativeExecutionCountKey.Int(val) +} + +// DBCassandraCoordinatorID returns an attribute KeyValue conforming to the +// "db.cassandra.coordinator.id" semantic conventions. It represents the ID of +// the coordinating node for a query. +func DBCassandraCoordinatorID(val string) attribute.KeyValue { + return DBCassandraCoordinatorIDKey.String(val) +} + +// DBCassandraCoordinatorDC returns an attribute KeyValue conforming to the +// "db.cassandra.coordinator.dc" semantic conventions. It represents the data +// center of the coordinating node for a query. +func DBCassandraCoordinatorDC(val string) attribute.KeyValue { + return DBCassandraCoordinatorDCKey.String(val) +} + +// Call-level attributes for Redis +const ( + // DBRedisDBIndexKey is the attribute Key conforming to the + // "db.redis.database_index" semantic conventions. It represents the index + // of the database being accessed as used in the [`SELECT` + // command](https://redis.io/commands/select), provided as an integer. To + // be used instead of the generic `db.name` attribute. + // + // Type: int + // RequirementLevel: ConditionallyRequired (If other than the default + // database (`0`).) + // Stability: stable + // Examples: 0, 1, 15 + DBRedisDBIndexKey = attribute.Key("db.redis.database_index") +) + +// DBRedisDBIndex returns an attribute KeyValue conforming to the +// "db.redis.database_index" semantic conventions. It represents the index of +// the database being accessed as used in the [`SELECT` +// command](https://redis.io/commands/select), provided as an integer. To be +// used instead of the generic `db.name` attribute. +func DBRedisDBIndex(val int) attribute.KeyValue { + return DBRedisDBIndexKey.Int(val) +} + +// Call-level attributes for MongoDB +const ( + // DBMongoDBCollectionKey is the attribute Key conforming to the + // "db.mongodb.collection" semantic conventions. It represents the + // collection being accessed within the database stated in `db.name`. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'customers', 'products' + DBMongoDBCollectionKey = attribute.Key("db.mongodb.collection") +) + +// DBMongoDBCollection returns an attribute KeyValue conforming to the +// "db.mongodb.collection" semantic conventions. It represents the collection +// being accessed within the database stated in `db.name`. +func DBMongoDBCollection(val string) attribute.KeyValue { + return DBMongoDBCollectionKey.String(val) +} + +// Call-level attributes for SQL databases +const ( + // DBSQLTableKey is the attribute Key conforming to the "db.sql.table" + // semantic conventions. It represents the name of the primary table that + // the operation is acting upon, including the database name (if + // applicable). + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'public.users', 'customers' + // Note: It is not recommended to attempt any client-side parsing of + // `db.statement` just to get this property, but it should be set if it is + // provided by the library being instrumented. If the operation is acting + // upon an anonymous table, or more than one table, this value MUST NOT be + // set. + DBSQLTableKey = attribute.Key("db.sql.table") +) + +// DBSQLTable returns an attribute KeyValue conforming to the "db.sql.table" +// semantic conventions. It represents the name of the primary table that the +// operation is acting upon, including the database name (if applicable). +func DBSQLTable(val string) attribute.KeyValue { + return DBSQLTableKey.String(val) +} + +// Call-level attributes for Cosmos DB. +const ( + // DBCosmosDBClientIDKey is the attribute Key conforming to the + // "db.cosmosdb.client_id" semantic conventions. It represents the unique + // Cosmos client instance id. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '3ba4827d-4422-483f-b59f-85b74211c11d' + DBCosmosDBClientIDKey = attribute.Key("db.cosmosdb.client_id") + + // DBCosmosDBOperationTypeKey is the attribute Key conforming to the + // "db.cosmosdb.operation_type" semantic conventions. It represents the + // cosmosDB Operation Type. + // + // Type: Enum + // RequirementLevel: ConditionallyRequired (when performing one of the + // operations in this list) + // Stability: stable + DBCosmosDBOperationTypeKey = attribute.Key("db.cosmosdb.operation_type") + + // DBCosmosDBConnectionModeKey is the attribute Key conforming to the + // "db.cosmosdb.connection_mode" semantic conventions. It represents the + // cosmos client connection mode. + // + // Type: Enum + // RequirementLevel: ConditionallyRequired (if not `direct` (or pick gw as + // default)) + // Stability: stable + DBCosmosDBConnectionModeKey = attribute.Key("db.cosmosdb.connection_mode") + + // DBCosmosDBContainerKey is the attribute Key conforming to the + // "db.cosmosdb.container" semantic conventions. It represents the cosmos + // DB container name. + // + // Type: string + // RequirementLevel: ConditionallyRequired (if available) + // Stability: stable + // Examples: 'anystring' + DBCosmosDBContainerKey = attribute.Key("db.cosmosdb.container") + + // DBCosmosDBRequestContentLengthKey is the attribute Key conforming to the + // "db.cosmosdb.request_content_length" semantic conventions. It represents + // the request payload size in bytes + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + DBCosmosDBRequestContentLengthKey = attribute.Key("db.cosmosdb.request_content_length") + + // DBCosmosDBStatusCodeKey is the attribute Key conforming to the + // "db.cosmosdb.status_code" semantic conventions. It represents the cosmos + // DB status code. + // + // Type: int + // RequirementLevel: ConditionallyRequired (if response was received) + // Stability: stable + // Examples: 200, 201 + DBCosmosDBStatusCodeKey = attribute.Key("db.cosmosdb.status_code") + + // DBCosmosDBSubStatusCodeKey is the attribute Key conforming to the + // "db.cosmosdb.sub_status_code" semantic conventions. It represents the + // cosmos DB sub status code. + // + // Type: int + // RequirementLevel: ConditionallyRequired (when response was received and + // contained sub-code.) + // Stability: stable + // Examples: 1000, 1002 + DBCosmosDBSubStatusCodeKey = attribute.Key("db.cosmosdb.sub_status_code") + + // DBCosmosDBRequestChargeKey is the attribute Key conforming to the + // "db.cosmosdb.request_charge" semantic conventions. It represents the rU + // consumed for that operation + // + // Type: double + // RequirementLevel: ConditionallyRequired (when available) + // Stability: stable + // Examples: 46.18, 1.0 + DBCosmosDBRequestChargeKey = attribute.Key("db.cosmosdb.request_charge") +) + +var ( + // invalid + DBCosmosDBOperationTypeInvalid = DBCosmosDBOperationTypeKey.String("Invalid") + // create + DBCosmosDBOperationTypeCreate = DBCosmosDBOperationTypeKey.String("Create") + // patch + DBCosmosDBOperationTypePatch = DBCosmosDBOperationTypeKey.String("Patch") + // read + DBCosmosDBOperationTypeRead = DBCosmosDBOperationTypeKey.String("Read") + // read_feed + DBCosmosDBOperationTypeReadFeed = DBCosmosDBOperationTypeKey.String("ReadFeed") + // delete + DBCosmosDBOperationTypeDelete = DBCosmosDBOperationTypeKey.String("Delete") + // replace + DBCosmosDBOperationTypeReplace = DBCosmosDBOperationTypeKey.String("Replace") + // execute + DBCosmosDBOperationTypeExecute = DBCosmosDBOperationTypeKey.String("Execute") + // query + DBCosmosDBOperationTypeQuery = DBCosmosDBOperationTypeKey.String("Query") + // head + DBCosmosDBOperationTypeHead = DBCosmosDBOperationTypeKey.String("Head") + // head_feed + DBCosmosDBOperationTypeHeadFeed = DBCosmosDBOperationTypeKey.String("HeadFeed") + // upsert + DBCosmosDBOperationTypeUpsert = DBCosmosDBOperationTypeKey.String("Upsert") + // batch + DBCosmosDBOperationTypeBatch = DBCosmosDBOperationTypeKey.String("Batch") + // query_plan + DBCosmosDBOperationTypeQueryPlan = DBCosmosDBOperationTypeKey.String("QueryPlan") + // execute_javascript + DBCosmosDBOperationTypeExecuteJavascript = DBCosmosDBOperationTypeKey.String("ExecuteJavaScript") +) + +var ( + // Gateway (HTTP) connections mode + DBCosmosDBConnectionModeGateway = DBCosmosDBConnectionModeKey.String("gateway") + // Direct connection + DBCosmosDBConnectionModeDirect = DBCosmosDBConnectionModeKey.String("direct") +) + +// DBCosmosDBClientID returns an attribute KeyValue conforming to the +// "db.cosmosdb.client_id" semantic conventions. It represents the unique +// Cosmos client instance id. +func DBCosmosDBClientID(val string) attribute.KeyValue { + return DBCosmosDBClientIDKey.String(val) +} + +// DBCosmosDBContainer returns an attribute KeyValue conforming to the +// "db.cosmosdb.container" semantic conventions. It represents the cosmos DB +// container name. +func DBCosmosDBContainer(val string) attribute.KeyValue { + return DBCosmosDBContainerKey.String(val) +} + +// DBCosmosDBRequestContentLength returns an attribute KeyValue conforming +// to the "db.cosmosdb.request_content_length" semantic conventions. It +// represents the request payload size in bytes +func DBCosmosDBRequestContentLength(val int) attribute.KeyValue { + return DBCosmosDBRequestContentLengthKey.Int(val) +} + +// DBCosmosDBStatusCode returns an attribute KeyValue conforming to the +// "db.cosmosdb.status_code" semantic conventions. It represents the cosmos DB +// status code. +func DBCosmosDBStatusCode(val int) attribute.KeyValue { + return DBCosmosDBStatusCodeKey.Int(val) +} + +// DBCosmosDBSubStatusCode returns an attribute KeyValue conforming to the +// "db.cosmosdb.sub_status_code" semantic conventions. It represents the cosmos +// DB sub status code. +func DBCosmosDBSubStatusCode(val int) attribute.KeyValue { + return DBCosmosDBSubStatusCodeKey.Int(val) +} + +// DBCosmosDBRequestCharge returns an attribute KeyValue conforming to the +// "db.cosmosdb.request_charge" semantic conventions. It represents the rU +// consumed for that operation +func DBCosmosDBRequestCharge(val float64) attribute.KeyValue { + return DBCosmosDBRequestChargeKey.Float64(val) +} + +// Span attributes used by non-OTLP exporters to represent OpenTelemetry Span's +// concepts. +const ( + // OTelStatusCodeKey is the attribute Key conforming to the + // "otel.status_code" semantic conventions. It represents the name of the + // code, either "OK" or "ERROR". MUST NOT be set if the status code is + // UNSET. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + OTelStatusCodeKey = attribute.Key("otel.status_code") + + // OTelStatusDescriptionKey is the attribute Key conforming to the + // "otel.status_description" semantic conventions. It represents the + // description of the Status if it has a value, otherwise not set. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'resource not found' + OTelStatusDescriptionKey = attribute.Key("otel.status_description") +) + +var ( + // The operation has been validated by an Application developer or Operator to have completed successfully + OTelStatusCodeOk = OTelStatusCodeKey.String("OK") + // The operation contains an error + OTelStatusCodeError = OTelStatusCodeKey.String("ERROR") +) + +// OTelStatusDescription returns an attribute KeyValue conforming to the +// "otel.status_description" semantic conventions. It represents the +// description of the Status if it has a value, otherwise not set. +func OTelStatusDescription(val string) attribute.KeyValue { + return OTelStatusDescriptionKey.String(val) +} + +// This semantic convention describes an instance of a function that runs +// without provisioning or managing of servers (also known as serverless +// functions or Function as a Service (FaaS)) with spans. +const ( + // FaaSTriggerKey is the attribute Key conforming to the "faas.trigger" + // semantic conventions. It represents the type of the trigger which caused + // this function invocation. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Note: For the server/consumer span on the incoming side, + // `faas.trigger` MUST be set. + // + // Clients invoking FaaS instances usually cannot set `faas.trigger`, + // since they would typically need to look in the payload to determine + // the event type. If clients set it, it should be the same as the + // trigger that corresponding incoming would have (i.e., this has + // nothing to do with the underlying transport used to make the API + // call to invoke the lambda, which is often HTTP). + FaaSTriggerKey = attribute.Key("faas.trigger") + + // FaaSInvocationIDKey is the attribute Key conforming to the + // "faas.invocation_id" semantic conventions. It represents the invocation + // ID of the current function invocation. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'af9d5aa4-a685-4c5f-a22b-444f80b3cc28' + FaaSInvocationIDKey = attribute.Key("faas.invocation_id") +) + +var ( + // A response to some data source operation such as a database or filesystem read/write + FaaSTriggerDatasource = FaaSTriggerKey.String("datasource") + // To provide an answer to an inbound HTTP request + FaaSTriggerHTTP = FaaSTriggerKey.String("http") + // A function is set to be executed when messages are sent to a messaging system + FaaSTriggerPubsub = FaaSTriggerKey.String("pubsub") + // A function is scheduled to be executed regularly + FaaSTriggerTimer = FaaSTriggerKey.String("timer") + // If none of the others apply + FaaSTriggerOther = FaaSTriggerKey.String("other") +) + +// FaaSInvocationID returns an attribute KeyValue conforming to the +// "faas.invocation_id" semantic conventions. It represents the invocation ID +// of the current function invocation. +func FaaSInvocationID(val string) attribute.KeyValue { + return FaaSInvocationIDKey.String(val) +} + +// Semantic Convention for FaaS triggered as a response to some data source +// operation such as a database or filesystem read/write. +const ( + // FaaSDocumentCollectionKey is the attribute Key conforming to the + // "faas.document.collection" semantic conventions. It represents the name + // of the source on which the triggering operation was performed. For + // example, in Cloud Storage or S3 corresponds to the bucket name, and in + // Cosmos DB to the database name. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'myBucketName', 'myDBName' + FaaSDocumentCollectionKey = attribute.Key("faas.document.collection") + + // FaaSDocumentOperationKey is the attribute Key conforming to the + // "faas.document.operation" semantic conventions. It represents the + // describes the type of the operation that was performed on the data. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + FaaSDocumentOperationKey = attribute.Key("faas.document.operation") + + // FaaSDocumentTimeKey is the attribute Key conforming to the + // "faas.document.time" semantic conventions. It represents a string + // containing the time when the data was accessed in the [ISO + // 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format + // expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2020-01-23T13:47:06Z' + FaaSDocumentTimeKey = attribute.Key("faas.document.time") + + // FaaSDocumentNameKey is the attribute Key conforming to the + // "faas.document.name" semantic conventions. It represents the document + // name/table subjected to the operation. For example, in Cloud Storage or + // S3 is the name of the file, and in Cosmos DB the table name. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'myFile.txt', 'myTableName' + FaaSDocumentNameKey = attribute.Key("faas.document.name") +) + +var ( + // When a new object is created + FaaSDocumentOperationInsert = FaaSDocumentOperationKey.String("insert") + // When an object is modified + FaaSDocumentOperationEdit = FaaSDocumentOperationKey.String("edit") + // When an object is deleted + FaaSDocumentOperationDelete = FaaSDocumentOperationKey.String("delete") +) + +// FaaSDocumentCollection returns an attribute KeyValue conforming to the +// "faas.document.collection" semantic conventions. It represents the name of +// the source on which the triggering operation was performed. For example, in +// Cloud Storage or S3 corresponds to the bucket name, and in Cosmos DB to the +// database name. +func FaaSDocumentCollection(val string) attribute.KeyValue { + return FaaSDocumentCollectionKey.String(val) +} + +// FaaSDocumentTime returns an attribute KeyValue conforming to the +// "faas.document.time" semantic conventions. It represents a string containing +// the time when the data was accessed in the [ISO +// 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format +// expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). +func FaaSDocumentTime(val string) attribute.KeyValue { + return FaaSDocumentTimeKey.String(val) +} + +// FaaSDocumentName returns an attribute KeyValue conforming to the +// "faas.document.name" semantic conventions. It represents the document +// name/table subjected to the operation. For example, in Cloud Storage or S3 +// is the name of the file, and in Cosmos DB the table name. +func FaaSDocumentName(val string) attribute.KeyValue { + return FaaSDocumentNameKey.String(val) +} + +// Semantic Convention for FaaS scheduled to be executed regularly. +const ( + // FaaSTimeKey is the attribute Key conforming to the "faas.time" semantic + // conventions. It represents a string containing the function invocation + // time in the [ISO + // 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format + // expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '2020-01-23T13:47:06Z' + FaaSTimeKey = attribute.Key("faas.time") + + // FaaSCronKey is the attribute Key conforming to the "faas.cron" semantic + // conventions. It represents a string containing the schedule period as + // [Cron + // Expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '0/5 * * * ? *' + FaaSCronKey = attribute.Key("faas.cron") +) + +// FaaSTime returns an attribute KeyValue conforming to the "faas.time" +// semantic conventions. It represents a string containing the function +// invocation time in the [ISO +// 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format +// expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). +func FaaSTime(val string) attribute.KeyValue { + return FaaSTimeKey.String(val) +} + +// FaaSCron returns an attribute KeyValue conforming to the "faas.cron" +// semantic conventions. It represents a string containing the schedule period +// as [Cron +// Expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm). +func FaaSCron(val string) attribute.KeyValue { + return FaaSCronKey.String(val) +} + +// Contains additional attributes for incoming FaaS spans. +const ( + // FaaSColdstartKey is the attribute Key conforming to the "faas.coldstart" + // semantic conventions. It represents a boolean that is true if the + // serverless function is executed for the first time (aka cold-start). + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + FaaSColdstartKey = attribute.Key("faas.coldstart") +) + +// FaaSColdstart returns an attribute KeyValue conforming to the +// "faas.coldstart" semantic conventions. It represents a boolean that is true +// if the serverless function is executed for the first time (aka cold-start). +func FaaSColdstart(val bool) attribute.KeyValue { + return FaaSColdstartKey.Bool(val) +} + +// Contains additional attributes for outgoing FaaS spans. +const ( + // FaaSInvokedNameKey is the attribute Key conforming to the + // "faas.invoked_name" semantic conventions. It represents the name of the + // invoked function. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'my-function' + // Note: SHOULD be equal to the `faas.name` resource attribute of the + // invoked function. + FaaSInvokedNameKey = attribute.Key("faas.invoked_name") + + // FaaSInvokedProviderKey is the attribute Key conforming to the + // "faas.invoked_provider" semantic conventions. It represents the cloud + // provider of the invoked function. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + // Note: SHOULD be equal to the `cloud.provider` resource attribute of the + // invoked function. + FaaSInvokedProviderKey = attribute.Key("faas.invoked_provider") + + // FaaSInvokedRegionKey is the attribute Key conforming to the + // "faas.invoked_region" semantic conventions. It represents the cloud + // region of the invoked function. + // + // Type: string + // RequirementLevel: ConditionallyRequired (For some cloud providers, like + // AWS or GCP, the region in which a function is hosted is essential to + // uniquely identify the function and also part of its endpoint. Since it's + // part of the endpoint being called, the region is always known to + // clients. In these cases, `faas.invoked_region` MUST be set accordingly. + // If the region is unknown to the client or not required for identifying + // the invoked function, setting `faas.invoked_region` is optional.) + // Stability: stable + // Examples: 'eu-central-1' + // Note: SHOULD be equal to the `cloud.region` resource attribute of the + // invoked function. + FaaSInvokedRegionKey = attribute.Key("faas.invoked_region") +) + +var ( + // Alibaba Cloud + FaaSInvokedProviderAlibabaCloud = FaaSInvokedProviderKey.String("alibaba_cloud") + // Amazon Web Services + FaaSInvokedProviderAWS = FaaSInvokedProviderKey.String("aws") + // Microsoft Azure + FaaSInvokedProviderAzure = FaaSInvokedProviderKey.String("azure") + // Google Cloud Platform + FaaSInvokedProviderGCP = FaaSInvokedProviderKey.String("gcp") + // Tencent Cloud + FaaSInvokedProviderTencentCloud = FaaSInvokedProviderKey.String("tencent_cloud") +) + +// FaaSInvokedName returns an attribute KeyValue conforming to the +// "faas.invoked_name" semantic conventions. It represents the name of the +// invoked function. +func FaaSInvokedName(val string) attribute.KeyValue { + return FaaSInvokedNameKey.String(val) +} + +// FaaSInvokedRegion returns an attribute KeyValue conforming to the +// "faas.invoked_region" semantic conventions. It represents the cloud region +// of the invoked function. +func FaaSInvokedRegion(val string) attribute.KeyValue { + return FaaSInvokedRegionKey.String(val) +} + +// Operations that access some remote service. +const ( + // PeerServiceKey is the attribute Key conforming to the "peer.service" + // semantic conventions. It represents the + // [`service.name`](/docs/resource/README.md#service) of the remote + // service. SHOULD be equal to the actual `service.name` resource attribute + // of the remote service if any. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'AuthTokenCache' + PeerServiceKey = attribute.Key("peer.service") +) + +// PeerService returns an attribute KeyValue conforming to the +// "peer.service" semantic conventions. It represents the +// [`service.name`](/docs/resource/README.md#service) of the remote service. +// SHOULD be equal to the actual `service.name` resource attribute of the +// remote service if any. +func PeerService(val string) attribute.KeyValue { + return PeerServiceKey.String(val) +} + +// These attributes may be used for any operation with an authenticated and/or +// authorized enduser. +const ( + // EnduserIDKey is the attribute Key conforming to the "enduser.id" + // semantic conventions. It represents the username or client_id extracted + // from the access token or + // [Authorization](https://tools.ietf.org/html/rfc7235#section-4.2) header + // in the inbound request from outside the system. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'username' + EnduserIDKey = attribute.Key("enduser.id") + + // EnduserRoleKey is the attribute Key conforming to the "enduser.role" + // semantic conventions. It represents the actual/assumed role the client + // is making the request under extracted from token or application security + // context. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'admin' + EnduserRoleKey = attribute.Key("enduser.role") + + // EnduserScopeKey is the attribute Key conforming to the "enduser.scope" + // semantic conventions. It represents the scopes or granted authorities + // the client currently possesses extracted from token or application + // security context. The value would come from the scope associated with an + // [OAuth 2.0 Access + // Token](https://tools.ietf.org/html/rfc6749#section-3.3) or an attribute + // value in a [SAML 2.0 + // Assertion](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'read:message, write:files' + EnduserScopeKey = attribute.Key("enduser.scope") +) + +// EnduserID returns an attribute KeyValue conforming to the "enduser.id" +// semantic conventions. It represents the username or client_id extracted from +// the access token or +// [Authorization](https://tools.ietf.org/html/rfc7235#section-4.2) header in +// the inbound request from outside the system. +func EnduserID(val string) attribute.KeyValue { + return EnduserIDKey.String(val) +} + +// EnduserRole returns an attribute KeyValue conforming to the +// "enduser.role" semantic conventions. It represents the actual/assumed role +// the client is making the request under extracted from token or application +// security context. +func EnduserRole(val string) attribute.KeyValue { + return EnduserRoleKey.String(val) +} + +// EnduserScope returns an attribute KeyValue conforming to the +// "enduser.scope" semantic conventions. It represents the scopes or granted +// authorities the client currently possesses extracted from token or +// application security context. The value would come from the scope associated +// with an [OAuth 2.0 Access +// Token](https://tools.ietf.org/html/rfc6749#section-3.3) or an attribute +// value in a [SAML 2.0 +// Assertion](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html). +func EnduserScope(val string) attribute.KeyValue { + return EnduserScopeKey.String(val) +} + +// These attributes may be used for any operation to store information about a +// thread that started a span. +const ( + // ThreadIDKey is the attribute Key conforming to the "thread.id" semantic + // conventions. It represents the current "managed" thread ID (as opposed + // to OS thread ID). + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 42 + ThreadIDKey = attribute.Key("thread.id") + + // ThreadNameKey is the attribute Key conforming to the "thread.name" + // semantic conventions. It represents the current thread name. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'main' + ThreadNameKey = attribute.Key("thread.name") +) + +// ThreadID returns an attribute KeyValue conforming to the "thread.id" +// semantic conventions. It represents the current "managed" thread ID (as +// opposed to OS thread ID). +func ThreadID(val int) attribute.KeyValue { + return ThreadIDKey.Int(val) +} + +// ThreadName returns an attribute KeyValue conforming to the "thread.name" +// semantic conventions. It represents the current thread name. +func ThreadName(val string) attribute.KeyValue { + return ThreadNameKey.String(val) +} + +// These attributes allow to report this unit of code and therefore to provide +// more context about the span. +const ( + // CodeFunctionKey is the attribute Key conforming to the "code.function" + // semantic conventions. It represents the method or function name, or + // equivalent (usually rightmost part of the code unit's name). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'serveRequest' + CodeFunctionKey = attribute.Key("code.function") + + // CodeNamespaceKey is the attribute Key conforming to the "code.namespace" + // semantic conventions. It represents the "namespace" within which + // `code.function` is defined. Usually the qualified class or module name, + // such that `code.namespace` + some separator + `code.function` form a + // unique identifier for the code unit. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'com.example.MyHTTPService' + CodeNamespaceKey = attribute.Key("code.namespace") + + // CodeFilepathKey is the attribute Key conforming to the "code.filepath" + // semantic conventions. It represents the source code file name that + // identifies the code unit as uniquely as possible (preferably an absolute + // file path). + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '/usr/local/MyApplication/content_root/app/index.php' + CodeFilepathKey = attribute.Key("code.filepath") + + // CodeLineNumberKey is the attribute Key conforming to the "code.lineno" + // semantic conventions. It represents the line number in `code.filepath` + // best representing the operation. It SHOULD point within the code unit + // named in `code.function`. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 42 + CodeLineNumberKey = attribute.Key("code.lineno") + + // CodeColumnKey is the attribute Key conforming to the "code.column" + // semantic conventions. It represents the column number in `code.filepath` + // best representing the operation. It SHOULD point within the code unit + // named in `code.function`. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 16 + CodeColumnKey = attribute.Key("code.column") +) + +// CodeFunction returns an attribute KeyValue conforming to the +// "code.function" semantic conventions. It represents the method or function +// name, or equivalent (usually rightmost part of the code unit's name). +func CodeFunction(val string) attribute.KeyValue { + return CodeFunctionKey.String(val) +} + +// CodeNamespace returns an attribute KeyValue conforming to the +// "code.namespace" semantic conventions. It represents the "namespace" within +// which `code.function` is defined. Usually the qualified class or module +// name, such that `code.namespace` + some separator + `code.function` form a +// unique identifier for the code unit. +func CodeNamespace(val string) attribute.KeyValue { + return CodeNamespaceKey.String(val) +} + +// CodeFilepath returns an attribute KeyValue conforming to the +// "code.filepath" semantic conventions. It represents the source code file +// name that identifies the code unit as uniquely as possible (preferably an +// absolute file path). +func CodeFilepath(val string) attribute.KeyValue { + return CodeFilepathKey.String(val) +} + +// CodeLineNumber returns an attribute KeyValue conforming to the "code.lineno" +// semantic conventions. It represents the line number in `code.filepath` best +// representing the operation. It SHOULD point within the code unit named in +// `code.function`. +func CodeLineNumber(val int) attribute.KeyValue { + return CodeLineNumberKey.Int(val) +} + +// CodeColumn returns an attribute KeyValue conforming to the "code.column" +// semantic conventions. It represents the column number in `code.filepath` +// best representing the operation. It SHOULD point within the code unit named +// in `code.function`. +func CodeColumn(val int) attribute.KeyValue { + return CodeColumnKey.Int(val) +} + +// Semantic Convention for HTTP Client +const ( + // HTTPResendCountKey is the attribute Key conforming to the + // "http.resend_count" semantic conventions. It represents the ordinal + // number of request resending attempt (for any reason, including + // redirects). + // + // Type: int + // RequirementLevel: Recommended (if and only if request was retried.) + // Stability: stable + // Examples: 3 + // Note: The resend count SHOULD be updated each time an HTTP request gets + // resent by the client, regardless of what was the cause of the resending + // (e.g. redirection, authorization failure, 503 Server Unavailable, + // network issues, or any other). + HTTPResendCountKey = attribute.Key("http.resend_count") +) + +// HTTPResendCount returns an attribute KeyValue conforming to the +// "http.resend_count" semantic conventions. It represents the ordinal number +// of request resending attempt (for any reason, including redirects). +func HTTPResendCount(val int) attribute.KeyValue { + return HTTPResendCountKey.Int(val) +} + +// The `aws` conventions apply to operations using the AWS SDK. They map +// request or response parameters in AWS SDK API calls to attributes on a Span. +// The conventions have been collected over time based on feedback from AWS +// users of tracing and will continue to evolve as new interesting conventions +// are found. +// Some descriptions are also provided for populating general OpenTelemetry +// semantic conventions based on these APIs. +const ( + // AWSRequestIDKey is the attribute Key conforming to the "aws.request_id" + // semantic conventions. It represents the AWS request ID as returned in + // the response headers `x-amz-request-id` or `x-amz-requestid`. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '79b9da39-b7ae-508a-a6bc-864b2829c622', 'C9ER4AJX75574TDJ' + AWSRequestIDKey = attribute.Key("aws.request_id") +) + +// AWSRequestID returns an attribute KeyValue conforming to the +// "aws.request_id" semantic conventions. It represents the AWS request ID as +// returned in the response headers `x-amz-request-id` or `x-amz-requestid`. +func AWSRequestID(val string) attribute.KeyValue { + return AWSRequestIDKey.String(val) +} + +// Attributes that exist for multiple DynamoDB request types. +const ( + // AWSDynamoDBTableNamesKey is the attribute Key conforming to the + // "aws.dynamodb.table_names" semantic conventions. It represents the keys + // in the `RequestItems` object field. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Users', 'Cats' + AWSDynamoDBTableNamesKey = attribute.Key("aws.dynamodb.table_names") + + // AWSDynamoDBConsumedCapacityKey is the attribute Key conforming to the + // "aws.dynamodb.consumed_capacity" semantic conventions. It represents the + // JSON-serialized value of each item in the `ConsumedCapacity` response + // field. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: '{ "CapacityUnits": number, "GlobalSecondaryIndexes": { + // "string" : { "CapacityUnits": number, "ReadCapacityUnits": number, + // "WriteCapacityUnits": number } }, "LocalSecondaryIndexes": { "string" : + // { "CapacityUnits": number, "ReadCapacityUnits": number, + // "WriteCapacityUnits": number } }, "ReadCapacityUnits": number, "Table": + // { "CapacityUnits": number, "ReadCapacityUnits": number, + // "WriteCapacityUnits": number }, "TableName": "string", + // "WriteCapacityUnits": number }' + AWSDynamoDBConsumedCapacityKey = attribute.Key("aws.dynamodb.consumed_capacity") + + // AWSDynamoDBItemCollectionMetricsKey is the attribute Key conforming to + // the "aws.dynamodb.item_collection_metrics" semantic conventions. It + // represents the JSON-serialized value of the `ItemCollectionMetrics` + // response field. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '{ "string" : [ { "ItemCollectionKey": { "string" : { "B": + // blob, "BOOL": boolean, "BS": [ blob ], "L": [ "AttributeValue" ], "M": { + // "string" : "AttributeValue" }, "N": "string", "NS": [ "string" ], + // "NULL": boolean, "S": "string", "SS": [ "string" ] } }, + // "SizeEstimateRangeGB": [ number ] } ] }' + AWSDynamoDBItemCollectionMetricsKey = attribute.Key("aws.dynamodb.item_collection_metrics") + + // AWSDynamoDBProvisionedReadCapacityKey is the attribute Key conforming to + // the "aws.dynamodb.provisioned_read_capacity" semantic conventions. It + // represents the value of the `ProvisionedThroughput.ReadCapacityUnits` + // request parameter. + // + // Type: double + // RequirementLevel: Optional + // Stability: stable + // Examples: 1.0, 2.0 + AWSDynamoDBProvisionedReadCapacityKey = attribute.Key("aws.dynamodb.provisioned_read_capacity") + + // AWSDynamoDBProvisionedWriteCapacityKey is the attribute Key conforming + // to the "aws.dynamodb.provisioned_write_capacity" semantic conventions. + // It represents the value of the + // `ProvisionedThroughput.WriteCapacityUnits` request parameter. + // + // Type: double + // RequirementLevel: Optional + // Stability: stable + // Examples: 1.0, 2.0 + AWSDynamoDBProvisionedWriteCapacityKey = attribute.Key("aws.dynamodb.provisioned_write_capacity") + + // AWSDynamoDBConsistentReadKey is the attribute Key conforming to the + // "aws.dynamodb.consistent_read" semantic conventions. It represents the + // value of the `ConsistentRead` request parameter. + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + AWSDynamoDBConsistentReadKey = attribute.Key("aws.dynamodb.consistent_read") + + // AWSDynamoDBProjectionKey is the attribute Key conforming to the + // "aws.dynamodb.projection" semantic conventions. It represents the value + // of the `ProjectionExpression` request parameter. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Title', 'Title, Price, Color', 'Title, Description, + // RelatedItems, ProductReviews' + AWSDynamoDBProjectionKey = attribute.Key("aws.dynamodb.projection") + + // AWSDynamoDBLimitKey is the attribute Key conforming to the + // "aws.dynamodb.limit" semantic conventions. It represents the value of + // the `Limit` request parameter. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 10 + AWSDynamoDBLimitKey = attribute.Key("aws.dynamodb.limit") + + // AWSDynamoDBAttributesToGetKey is the attribute Key conforming to the + // "aws.dynamodb.attributes_to_get" semantic conventions. It represents the + // value of the `AttributesToGet` request parameter. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: 'lives', 'id' + AWSDynamoDBAttributesToGetKey = attribute.Key("aws.dynamodb.attributes_to_get") + + // AWSDynamoDBIndexNameKey is the attribute Key conforming to the + // "aws.dynamodb.index_name" semantic conventions. It represents the value + // of the `IndexName` request parameter. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'name_to_group' + AWSDynamoDBIndexNameKey = attribute.Key("aws.dynamodb.index_name") + + // AWSDynamoDBSelectKey is the attribute Key conforming to the + // "aws.dynamodb.select" semantic conventions. It represents the value of + // the `Select` request parameter. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'ALL_ATTRIBUTES', 'COUNT' + AWSDynamoDBSelectKey = attribute.Key("aws.dynamodb.select") +) + +// AWSDynamoDBTableNames returns an attribute KeyValue conforming to the +// "aws.dynamodb.table_names" semantic conventions. It represents the keys in +// the `RequestItems` object field. +func AWSDynamoDBTableNames(val ...string) attribute.KeyValue { + return AWSDynamoDBTableNamesKey.StringSlice(val) +} + +// AWSDynamoDBConsumedCapacity returns an attribute KeyValue conforming to +// the "aws.dynamodb.consumed_capacity" semantic conventions. It represents the +// JSON-serialized value of each item in the `ConsumedCapacity` response field. +func AWSDynamoDBConsumedCapacity(val ...string) attribute.KeyValue { + return AWSDynamoDBConsumedCapacityKey.StringSlice(val) +} + +// AWSDynamoDBItemCollectionMetrics returns an attribute KeyValue conforming +// to the "aws.dynamodb.item_collection_metrics" semantic conventions. It +// represents the JSON-serialized value of the `ItemCollectionMetrics` response +// field. +func AWSDynamoDBItemCollectionMetrics(val string) attribute.KeyValue { + return AWSDynamoDBItemCollectionMetricsKey.String(val) +} + +// AWSDynamoDBProvisionedReadCapacity returns an attribute KeyValue +// conforming to the "aws.dynamodb.provisioned_read_capacity" semantic +// conventions. It represents the value of the +// `ProvisionedThroughput.ReadCapacityUnits` request parameter. +func AWSDynamoDBProvisionedReadCapacity(val float64) attribute.KeyValue { + return AWSDynamoDBProvisionedReadCapacityKey.Float64(val) +} + +// AWSDynamoDBProvisionedWriteCapacity returns an attribute KeyValue +// conforming to the "aws.dynamodb.provisioned_write_capacity" semantic +// conventions. It represents the value of the +// `ProvisionedThroughput.WriteCapacityUnits` request parameter. +func AWSDynamoDBProvisionedWriteCapacity(val float64) attribute.KeyValue { + return AWSDynamoDBProvisionedWriteCapacityKey.Float64(val) +} + +// AWSDynamoDBConsistentRead returns an attribute KeyValue conforming to the +// "aws.dynamodb.consistent_read" semantic conventions. It represents the value +// of the `ConsistentRead` request parameter. +func AWSDynamoDBConsistentRead(val bool) attribute.KeyValue { + return AWSDynamoDBConsistentReadKey.Bool(val) +} + +// AWSDynamoDBProjection returns an attribute KeyValue conforming to the +// "aws.dynamodb.projection" semantic conventions. It represents the value of +// the `ProjectionExpression` request parameter. +func AWSDynamoDBProjection(val string) attribute.KeyValue { + return AWSDynamoDBProjectionKey.String(val) +} + +// AWSDynamoDBLimit returns an attribute KeyValue conforming to the +// "aws.dynamodb.limit" semantic conventions. It represents the value of the +// `Limit` request parameter. +func AWSDynamoDBLimit(val int) attribute.KeyValue { + return AWSDynamoDBLimitKey.Int(val) +} + +// AWSDynamoDBAttributesToGet returns an attribute KeyValue conforming to +// the "aws.dynamodb.attributes_to_get" semantic conventions. It represents the +// value of the `AttributesToGet` request parameter. +func AWSDynamoDBAttributesToGet(val ...string) attribute.KeyValue { + return AWSDynamoDBAttributesToGetKey.StringSlice(val) +} + +// AWSDynamoDBIndexName returns an attribute KeyValue conforming to the +// "aws.dynamodb.index_name" semantic conventions. It represents the value of +// the `IndexName` request parameter. +func AWSDynamoDBIndexName(val string) attribute.KeyValue { + return AWSDynamoDBIndexNameKey.String(val) +} + +// AWSDynamoDBSelect returns an attribute KeyValue conforming to the +// "aws.dynamodb.select" semantic conventions. It represents the value of the +// `Select` request parameter. +func AWSDynamoDBSelect(val string) attribute.KeyValue { + return AWSDynamoDBSelectKey.String(val) +} + +// DynamoDB.CreateTable +const ( + // AWSDynamoDBGlobalSecondaryIndexesKey is the attribute Key conforming to + // the "aws.dynamodb.global_secondary_indexes" semantic conventions. It + // represents the JSON-serialized value of each item of the + // `GlobalSecondaryIndexes` request field + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: '{ "IndexName": "string", "KeySchema": [ { "AttributeName": + // "string", "KeyType": "string" } ], "Projection": { "NonKeyAttributes": [ + // "string" ], "ProjectionType": "string" }, "ProvisionedThroughput": { + // "ReadCapacityUnits": number, "WriteCapacityUnits": number } }' + AWSDynamoDBGlobalSecondaryIndexesKey = attribute.Key("aws.dynamodb.global_secondary_indexes") + + // AWSDynamoDBLocalSecondaryIndexesKey is the attribute Key conforming to + // the "aws.dynamodb.local_secondary_indexes" semantic conventions. It + // represents the JSON-serialized value of each item of the + // `LocalSecondaryIndexes` request field. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: '{ "IndexARN": "string", "IndexName": "string", + // "IndexSizeBytes": number, "ItemCount": number, "KeySchema": [ { + // "AttributeName": "string", "KeyType": "string" } ], "Projection": { + // "NonKeyAttributes": [ "string" ], "ProjectionType": "string" } }' + AWSDynamoDBLocalSecondaryIndexesKey = attribute.Key("aws.dynamodb.local_secondary_indexes") +) + +// AWSDynamoDBGlobalSecondaryIndexes returns an attribute KeyValue +// conforming to the "aws.dynamodb.global_secondary_indexes" semantic +// conventions. It represents the JSON-serialized value of each item of the +// `GlobalSecondaryIndexes` request field +func AWSDynamoDBGlobalSecondaryIndexes(val ...string) attribute.KeyValue { + return AWSDynamoDBGlobalSecondaryIndexesKey.StringSlice(val) +} + +// AWSDynamoDBLocalSecondaryIndexes returns an attribute KeyValue conforming +// to the "aws.dynamodb.local_secondary_indexes" semantic conventions. It +// represents the JSON-serialized value of each item of the +// `LocalSecondaryIndexes` request field. +func AWSDynamoDBLocalSecondaryIndexes(val ...string) attribute.KeyValue { + return AWSDynamoDBLocalSecondaryIndexesKey.StringSlice(val) +} + +// DynamoDB.ListTables +const ( + // AWSDynamoDBExclusiveStartTableKey is the attribute Key conforming to the + // "aws.dynamodb.exclusive_start_table" semantic conventions. It represents + // the value of the `ExclusiveStartTableName` request parameter. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Users', 'CatsTable' + AWSDynamoDBExclusiveStartTableKey = attribute.Key("aws.dynamodb.exclusive_start_table") + + // AWSDynamoDBTableCountKey is the attribute Key conforming to the + // "aws.dynamodb.table_count" semantic conventions. It represents the the + // number of items in the `TableNames` response parameter. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 20 + AWSDynamoDBTableCountKey = attribute.Key("aws.dynamodb.table_count") +) + +// AWSDynamoDBExclusiveStartTable returns an attribute KeyValue conforming +// to the "aws.dynamodb.exclusive_start_table" semantic conventions. It +// represents the value of the `ExclusiveStartTableName` request parameter. +func AWSDynamoDBExclusiveStartTable(val string) attribute.KeyValue { + return AWSDynamoDBExclusiveStartTableKey.String(val) +} + +// AWSDynamoDBTableCount returns an attribute KeyValue conforming to the +// "aws.dynamodb.table_count" semantic conventions. It represents the the +// number of items in the `TableNames` response parameter. +func AWSDynamoDBTableCount(val int) attribute.KeyValue { + return AWSDynamoDBTableCountKey.Int(val) +} + +// DynamoDB.Query +const ( + // AWSDynamoDBScanForwardKey is the attribute Key conforming to the + // "aws.dynamodb.scan_forward" semantic conventions. It represents the + // value of the `ScanIndexForward` request parameter. + // + // Type: boolean + // RequirementLevel: Optional + // Stability: stable + AWSDynamoDBScanForwardKey = attribute.Key("aws.dynamodb.scan_forward") +) + +// AWSDynamoDBScanForward returns an attribute KeyValue conforming to the +// "aws.dynamodb.scan_forward" semantic conventions. It represents the value of +// the `ScanIndexForward` request parameter. +func AWSDynamoDBScanForward(val bool) attribute.KeyValue { + return AWSDynamoDBScanForwardKey.Bool(val) +} + +// DynamoDB.Scan +const ( + // AWSDynamoDBSegmentKey is the attribute Key conforming to the + // "aws.dynamodb.segment" semantic conventions. It represents the value of + // the `Segment` request parameter. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 10 + AWSDynamoDBSegmentKey = attribute.Key("aws.dynamodb.segment") + + // AWSDynamoDBTotalSegmentsKey is the attribute Key conforming to the + // "aws.dynamodb.total_segments" semantic conventions. It represents the + // value of the `TotalSegments` request parameter. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 100 + AWSDynamoDBTotalSegmentsKey = attribute.Key("aws.dynamodb.total_segments") + + // AWSDynamoDBCountKey is the attribute Key conforming to the + // "aws.dynamodb.count" semantic conventions. It represents the value of + // the `Count` response parameter. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 10 + AWSDynamoDBCountKey = attribute.Key("aws.dynamodb.count") + + // AWSDynamoDBScannedCountKey is the attribute Key conforming to the + // "aws.dynamodb.scanned_count" semantic conventions. It represents the + // value of the `ScannedCount` response parameter. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 50 + AWSDynamoDBScannedCountKey = attribute.Key("aws.dynamodb.scanned_count") +) + +// AWSDynamoDBSegment returns an attribute KeyValue conforming to the +// "aws.dynamodb.segment" semantic conventions. It represents the value of the +// `Segment` request parameter. +func AWSDynamoDBSegment(val int) attribute.KeyValue { + return AWSDynamoDBSegmentKey.Int(val) +} + +// AWSDynamoDBTotalSegments returns an attribute KeyValue conforming to the +// "aws.dynamodb.total_segments" semantic conventions. It represents the value +// of the `TotalSegments` request parameter. +func AWSDynamoDBTotalSegments(val int) attribute.KeyValue { + return AWSDynamoDBTotalSegmentsKey.Int(val) +} + +// AWSDynamoDBCount returns an attribute KeyValue conforming to the +// "aws.dynamodb.count" semantic conventions. It represents the value of the +// `Count` response parameter. +func AWSDynamoDBCount(val int) attribute.KeyValue { + return AWSDynamoDBCountKey.Int(val) +} + +// AWSDynamoDBScannedCount returns an attribute KeyValue conforming to the +// "aws.dynamodb.scanned_count" semantic conventions. It represents the value +// of the `ScannedCount` response parameter. +func AWSDynamoDBScannedCount(val int) attribute.KeyValue { + return AWSDynamoDBScannedCountKey.Int(val) +} + +// DynamoDB.UpdateTable +const ( + // AWSDynamoDBAttributeDefinitionsKey is the attribute Key conforming to + // the "aws.dynamodb.attribute_definitions" semantic conventions. It + // represents the JSON-serialized value of each item in the + // `AttributeDefinitions` request field. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: '{ "AttributeName": "string", "AttributeType": "string" }' + AWSDynamoDBAttributeDefinitionsKey = attribute.Key("aws.dynamodb.attribute_definitions") + + // AWSDynamoDBGlobalSecondaryIndexUpdatesKey is the attribute Key + // conforming to the "aws.dynamodb.global_secondary_index_updates" semantic + // conventions. It represents the JSON-serialized value of each item in the + // the `GlobalSecondaryIndexUpdates` request field. + // + // Type: string[] + // RequirementLevel: Optional + // Stability: stable + // Examples: '{ "Create": { "IndexName": "string", "KeySchema": [ { + // "AttributeName": "string", "KeyType": "string" } ], "Projection": { + // "NonKeyAttributes": [ "string" ], "ProjectionType": "string" }, + // "ProvisionedThroughput": { "ReadCapacityUnits": number, + // "WriteCapacityUnits": number } }' + AWSDynamoDBGlobalSecondaryIndexUpdatesKey = attribute.Key("aws.dynamodb.global_secondary_index_updates") +) + +// AWSDynamoDBAttributeDefinitions returns an attribute KeyValue conforming +// to the "aws.dynamodb.attribute_definitions" semantic conventions. It +// represents the JSON-serialized value of each item in the +// `AttributeDefinitions` request field. +func AWSDynamoDBAttributeDefinitions(val ...string) attribute.KeyValue { + return AWSDynamoDBAttributeDefinitionsKey.StringSlice(val) +} + +// AWSDynamoDBGlobalSecondaryIndexUpdates returns an attribute KeyValue +// conforming to the "aws.dynamodb.global_secondary_index_updates" semantic +// conventions. It represents the JSON-serialized value of each item in the the +// `GlobalSecondaryIndexUpdates` request field. +func AWSDynamoDBGlobalSecondaryIndexUpdates(val ...string) attribute.KeyValue { + return AWSDynamoDBGlobalSecondaryIndexUpdatesKey.StringSlice(val) +} + +// Attributes that exist for S3 request types. +const ( + // AWSS3BucketKey is the attribute Key conforming to the "aws.s3.bucket" + // semantic conventions. It represents the S3 bucket name the request + // refers to. Corresponds to the `--bucket` parameter of the [S3 + // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) + // operations. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'some-bucket-name' + // Note: The `bucket` attribute is applicable to all S3 operations that + // reference a bucket, i.e. that require the bucket name as a mandatory + // parameter. + // This applies to almost all S3 operations except `list-buckets`. + AWSS3BucketKey = attribute.Key("aws.s3.bucket") + + // AWSS3KeyKey is the attribute Key conforming to the "aws.s3.key" semantic + // conventions. It represents the S3 object key the request refers to. + // Corresponds to the `--key` parameter of the [S3 + // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) + // operations. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'someFile.yml' + // Note: The `key` attribute is applicable to all object-related S3 + // operations, i.e. that require the object key as a mandatory parameter. + // This applies in particular to the following operations: + // + // - + // [copy-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html) + // - + // [delete-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-object.html) + // - + // [get-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/get-object.html) + // - + // [head-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/head-object.html) + // - + // [put-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html) + // - + // [restore-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/restore-object.html) + // - + // [select-object-content](https://docs.aws.amazon.com/cli/latest/reference/s3api/select-object-content.html) + // - + // [abort-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/abort-multipart-upload.html) + // - + // [complete-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/complete-multipart-upload.html) + // - + // [create-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/create-multipart-upload.html) + // - + // [list-parts](https://docs.aws.amazon.com/cli/latest/reference/s3api/list-parts.html) + // - + // [upload-part](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html) + // - + // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) + AWSS3KeyKey = attribute.Key("aws.s3.key") + + // AWSS3CopySourceKey is the attribute Key conforming to the + // "aws.s3.copy_source" semantic conventions. It represents the source + // object (in the form `bucket`/`key`) for the copy operation. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'someFile.yml' + // Note: The `copy_source` attribute applies to S3 copy operations and + // corresponds to the `--copy-source` parameter + // of the [copy-object operation within the S3 + // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html). + // This applies in particular to the following operations: + // + // - + // [copy-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html) + // - + // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) + AWSS3CopySourceKey = attribute.Key("aws.s3.copy_source") + + // AWSS3UploadIDKey is the attribute Key conforming to the + // "aws.s3.upload_id" semantic conventions. It represents the upload ID + // that identifies the multipart upload. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'dfRtDYWFbkRONycy.Yxwh66Yjlx.cph0gtNBtJ' + // Note: The `upload_id` attribute applies to S3 multipart-upload + // operations and corresponds to the `--upload-id` parameter + // of the [S3 + // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) + // multipart operations. + // This applies in particular to the following operations: + // + // - + // [abort-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/abort-multipart-upload.html) + // - + // [complete-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/complete-multipart-upload.html) + // - + // [list-parts](https://docs.aws.amazon.com/cli/latest/reference/s3api/list-parts.html) + // - + // [upload-part](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html) + // - + // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) + AWSS3UploadIDKey = attribute.Key("aws.s3.upload_id") + + // AWSS3DeleteKey is the attribute Key conforming to the "aws.s3.delete" + // semantic conventions. It represents the delete request container that + // specifies the objects to be deleted. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: + // 'Objects=[{Key=string,VersionID=string},{Key=string,VersionID=string}],Quiet=boolean' + // Note: The `delete` attribute is only applicable to the + // [delete-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-object.html) + // operation. + // The `delete` attribute corresponds to the `--delete` parameter of the + // [delete-objects operation within the S3 + // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-objects.html). + AWSS3DeleteKey = attribute.Key("aws.s3.delete") + + // AWSS3PartNumberKey is the attribute Key conforming to the + // "aws.s3.part_number" semantic conventions. It represents the part number + // of the part being uploaded in a multipart-upload operation. This is a + // positive integer between 1 and 10,000. + // + // Type: int + // RequirementLevel: Optional + // Stability: stable + // Examples: 3456 + // Note: The `part_number` attribute is only applicable to the + // [upload-part](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html) + // and + // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) + // operations. + // The `part_number` attribute corresponds to the `--part-number` parameter + // of the + // [upload-part operation within the S3 + // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html). + AWSS3PartNumberKey = attribute.Key("aws.s3.part_number") +) + +// AWSS3Bucket returns an attribute KeyValue conforming to the +// "aws.s3.bucket" semantic conventions. It represents the S3 bucket name the +// request refers to. Corresponds to the `--bucket` parameter of the [S3 +// API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) +// operations. +func AWSS3Bucket(val string) attribute.KeyValue { + return AWSS3BucketKey.String(val) +} + +// AWSS3Key returns an attribute KeyValue conforming to the "aws.s3.key" +// semantic conventions. It represents the S3 object key the request refers to. +// Corresponds to the `--key` parameter of the [S3 +// API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) +// operations. +func AWSS3Key(val string) attribute.KeyValue { + return AWSS3KeyKey.String(val) +} + +// AWSS3CopySource returns an attribute KeyValue conforming to the +// "aws.s3.copy_source" semantic conventions. It represents the source object +// (in the form `bucket`/`key`) for the copy operation. +func AWSS3CopySource(val string) attribute.KeyValue { + return AWSS3CopySourceKey.String(val) +} + +// AWSS3UploadID returns an attribute KeyValue conforming to the +// "aws.s3.upload_id" semantic conventions. It represents the upload ID that +// identifies the multipart upload. +func AWSS3UploadID(val string) attribute.KeyValue { + return AWSS3UploadIDKey.String(val) +} + +// AWSS3Delete returns an attribute KeyValue conforming to the +// "aws.s3.delete" semantic conventions. It represents the delete request +// container that specifies the objects to be deleted. +func AWSS3Delete(val string) attribute.KeyValue { + return AWSS3DeleteKey.String(val) +} + +// AWSS3PartNumber returns an attribute KeyValue conforming to the +// "aws.s3.part_number" semantic conventions. It represents the part number of +// the part being uploaded in a multipart-upload operation. This is a positive +// integer between 1 and 10,000. +func AWSS3PartNumber(val int) attribute.KeyValue { + return AWSS3PartNumberKey.Int(val) +} + +// Semantic conventions to apply when instrumenting the GraphQL implementation. +// They map GraphQL operations to attributes on a Span. +const ( + // GraphqlOperationNameKey is the attribute Key conforming to the + // "graphql.operation.name" semantic conventions. It represents the name of + // the operation being executed. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'findBookByID' + GraphqlOperationNameKey = attribute.Key("graphql.operation.name") + + // GraphqlOperationTypeKey is the attribute Key conforming to the + // "graphql.operation.type" semantic conventions. It represents the type of + // the operation being executed. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + // Examples: 'query', 'mutation', 'subscription' + GraphqlOperationTypeKey = attribute.Key("graphql.operation.type") + + // GraphqlDocumentKey is the attribute Key conforming to the + // "graphql.document" semantic conventions. It represents the GraphQL + // document being executed. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'query findBookByID { bookByID(id: ?) { name } }' + // Note: The value may be sanitized to exclude sensitive information. + GraphqlDocumentKey = attribute.Key("graphql.document") +) + +var ( + // GraphQL query + GraphqlOperationTypeQuery = GraphqlOperationTypeKey.String("query") + // GraphQL mutation + GraphqlOperationTypeMutation = GraphqlOperationTypeKey.String("mutation") + // GraphQL subscription + GraphqlOperationTypeSubscription = GraphqlOperationTypeKey.String("subscription") +) + +// GraphqlOperationName returns an attribute KeyValue conforming to the +// "graphql.operation.name" semantic conventions. It represents the name of the +// operation being executed. +func GraphqlOperationName(val string) attribute.KeyValue { + return GraphqlOperationNameKey.String(val) +} + +// GraphqlDocument returns an attribute KeyValue conforming to the +// "graphql.document" semantic conventions. It represents the GraphQL document +// being executed. +func GraphqlDocument(val string) attribute.KeyValue { + return GraphqlDocumentKey.String(val) +} + +// General attributes used in messaging systems. +const ( + // MessagingSystemKey is the attribute Key conforming to the + // "messaging.system" semantic conventions. It represents a string + // identifying the messaging system. + // + // Type: string + // RequirementLevel: Required + // Stability: stable + // Examples: 'kafka', 'rabbitmq', 'rocketmq', 'activemq', 'AmazonSQS' + MessagingSystemKey = attribute.Key("messaging.system") + + // MessagingOperationKey is the attribute Key conforming to the + // "messaging.operation" semantic conventions. It represents a string + // identifying the kind of messaging operation as defined in the [Operation + // names](#operation-names) section above. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + // Note: If a custom value is used, it MUST be of low cardinality. + MessagingOperationKey = attribute.Key("messaging.operation") + + // MessagingBatchMessageCountKey is the attribute Key conforming to the + // "messaging.batch.message_count" semantic conventions. It represents the + // number of messages sent, received, or processed in the scope of the + // batching operation. + // + // Type: int + // RequirementLevel: ConditionallyRequired (If the span describes an + // operation on a batch of messages.) + // Stability: stable + // Examples: 0, 1, 2 + // Note: Instrumentations SHOULD NOT set `messaging.batch.message_count` on + // spans that operate with a single message. When a messaging client + // library supports both batch and single-message API for the same + // operation, instrumentations SHOULD use `messaging.batch.message_count` + // for batching APIs and SHOULD NOT use it for single-message APIs. + MessagingBatchMessageCountKey = attribute.Key("messaging.batch.message_count") + + // MessagingClientIDKey is the attribute Key conforming to the + // "messaging.client_id" semantic conventions. It represents a unique + // identifier for the client that consumes or produces a message. + // + // Type: string + // RequirementLevel: Recommended (If a client id is available) + // Stability: stable + // Examples: 'client-5', 'myhost@8742@s8083jm' + MessagingClientIDKey = attribute.Key("messaging.client_id") +) + +var ( + // publish + MessagingOperationPublish = MessagingOperationKey.String("publish") + // receive + MessagingOperationReceive = MessagingOperationKey.String("receive") + // process + MessagingOperationProcess = MessagingOperationKey.String("process") +) + +// MessagingSystem returns an attribute KeyValue conforming to the +// "messaging.system" semantic conventions. It represents a string identifying +// the messaging system. +func MessagingSystem(val string) attribute.KeyValue { + return MessagingSystemKey.String(val) +} + +// MessagingBatchMessageCount returns an attribute KeyValue conforming to +// the "messaging.batch.message_count" semantic conventions. It represents the +// number of messages sent, received, or processed in the scope of the batching +// operation. +func MessagingBatchMessageCount(val int) attribute.KeyValue { + return MessagingBatchMessageCountKey.Int(val) +} + +// MessagingClientID returns an attribute KeyValue conforming to the +// "messaging.client_id" semantic conventions. It represents a unique +// identifier for the client that consumes or produces a message. +func MessagingClientID(val string) attribute.KeyValue { + return MessagingClientIDKey.String(val) +} + +// Semantic conventions for remote procedure calls. +const ( + // RPCSystemKey is the attribute Key conforming to the "rpc.system" + // semantic conventions. It represents a string identifying the remoting + // system. See below for a list of well-known identifiers. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + RPCSystemKey = attribute.Key("rpc.system") + + // RPCServiceKey is the attribute Key conforming to the "rpc.service" + // semantic conventions. It represents the full (logical) name of the + // service being called, including its package name, if applicable. + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'myservice.EchoService' + // Note: This is the logical name of the service from the RPC interface + // perspective, which can be different from the name of any implementing + // class. The `code.namespace` attribute may be used to store the latter + // (despite the attribute name, it may include a class name; e.g., class + // with method actually executing the call on the server side, RPC client + // stub class on the client side). + RPCServiceKey = attribute.Key("rpc.service") + + // RPCMethodKey is the attribute Key conforming to the "rpc.method" + // semantic conventions. It represents the name of the (logical) method + // being called, must be equal to the $method part in the span name. + // + // Type: string + // RequirementLevel: Recommended + // Stability: stable + // Examples: 'exampleMethod' + // Note: This is the logical name of the method from the RPC interface + // perspective, which can be different from the name of any implementing + // method/function. The `code.function` attribute may be used to store the + // latter (e.g., method actually executing the call on the server side, RPC + // client stub method on the client side). + RPCMethodKey = attribute.Key("rpc.method") +) + +var ( + // gRPC + RPCSystemGRPC = RPCSystemKey.String("grpc") + // Java RMI + RPCSystemJavaRmi = RPCSystemKey.String("java_rmi") + // .NET WCF + RPCSystemDotnetWcf = RPCSystemKey.String("dotnet_wcf") + // Apache Dubbo + RPCSystemApacheDubbo = RPCSystemKey.String("apache_dubbo") + // Connect RPC + RPCSystemConnectRPC = RPCSystemKey.String("connect_rpc") +) + +// RPCService returns an attribute KeyValue conforming to the "rpc.service" +// semantic conventions. It represents the full (logical) name of the service +// being called, including its package name, if applicable. +func RPCService(val string) attribute.KeyValue { + return RPCServiceKey.String(val) +} + +// RPCMethod returns an attribute KeyValue conforming to the "rpc.method" +// semantic conventions. It represents the name of the (logical) method being +// called, must be equal to the $method part in the span name. +func RPCMethod(val string) attribute.KeyValue { + return RPCMethodKey.String(val) +} + +// Tech-specific attributes for gRPC. +const ( + // RPCGRPCStatusCodeKey is the attribute Key conforming to the + // "rpc.grpc.status_code" semantic conventions. It represents the [numeric + // status + // code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of + // the gRPC request. + // + // Type: Enum + // RequirementLevel: Required + // Stability: stable + RPCGRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code") +) + +var ( + // OK + RPCGRPCStatusCodeOk = RPCGRPCStatusCodeKey.Int(0) + // CANCELLED + RPCGRPCStatusCodeCancelled = RPCGRPCStatusCodeKey.Int(1) + // UNKNOWN + RPCGRPCStatusCodeUnknown = RPCGRPCStatusCodeKey.Int(2) + // INVALID_ARGUMENT + RPCGRPCStatusCodeInvalidArgument = RPCGRPCStatusCodeKey.Int(3) + // DEADLINE_EXCEEDED + RPCGRPCStatusCodeDeadlineExceeded = RPCGRPCStatusCodeKey.Int(4) + // NOT_FOUND + RPCGRPCStatusCodeNotFound = RPCGRPCStatusCodeKey.Int(5) + // ALREADY_EXISTS + RPCGRPCStatusCodeAlreadyExists = RPCGRPCStatusCodeKey.Int(6) + // PERMISSION_DENIED + RPCGRPCStatusCodePermissionDenied = RPCGRPCStatusCodeKey.Int(7) + // RESOURCE_EXHAUSTED + RPCGRPCStatusCodeResourceExhausted = RPCGRPCStatusCodeKey.Int(8) + // FAILED_PRECONDITION + RPCGRPCStatusCodeFailedPrecondition = RPCGRPCStatusCodeKey.Int(9) + // ABORTED + RPCGRPCStatusCodeAborted = RPCGRPCStatusCodeKey.Int(10) + // OUT_OF_RANGE + RPCGRPCStatusCodeOutOfRange = RPCGRPCStatusCodeKey.Int(11) + // UNIMPLEMENTED + RPCGRPCStatusCodeUnimplemented = RPCGRPCStatusCodeKey.Int(12) + // INTERNAL + RPCGRPCStatusCodeInternal = RPCGRPCStatusCodeKey.Int(13) + // UNAVAILABLE + RPCGRPCStatusCodeUnavailable = RPCGRPCStatusCodeKey.Int(14) + // DATA_LOSS + RPCGRPCStatusCodeDataLoss = RPCGRPCStatusCodeKey.Int(15) + // UNAUTHENTICATED + RPCGRPCStatusCodeUnauthenticated = RPCGRPCStatusCodeKey.Int(16) +) + +// Tech-specific attributes for [JSON RPC](https://www.jsonrpc.org/). +const ( + // RPCJsonrpcVersionKey is the attribute Key conforming to the + // "rpc.jsonrpc.version" semantic conventions. It represents the protocol + // version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 + // does not specify this, the value can be omitted. + // + // Type: string + // RequirementLevel: ConditionallyRequired (If other than the default + // version (`1.0`)) + // Stability: stable + // Examples: '2.0', '1.0' + RPCJsonrpcVersionKey = attribute.Key("rpc.jsonrpc.version") + + // RPCJsonrpcRequestIDKey is the attribute Key conforming to the + // "rpc.jsonrpc.request_id" semantic conventions. It represents the `id` + // property of request or response. Since protocol allows id to be int, + // string, `null` or missing (for notifications), value is expected to be + // cast to string for simplicity. Use empty string in case of `null` value. + // Omit entirely if this is a notification. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: '10', 'request-7', '' + RPCJsonrpcRequestIDKey = attribute.Key("rpc.jsonrpc.request_id") + + // RPCJsonrpcErrorCodeKey is the attribute Key conforming to the + // "rpc.jsonrpc.error_code" semantic conventions. It represents the + // `error.code` property of response if it is an error response. + // + // Type: int + // RequirementLevel: ConditionallyRequired (If response is not successful.) + // Stability: stable + // Examples: -32700, 100 + RPCJsonrpcErrorCodeKey = attribute.Key("rpc.jsonrpc.error_code") + + // RPCJsonrpcErrorMessageKey is the attribute Key conforming to the + // "rpc.jsonrpc.error_message" semantic conventions. It represents the + // `error.message` property of response if it is an error response. + // + // Type: string + // RequirementLevel: Optional + // Stability: stable + // Examples: 'Parse error', 'User already exists' + RPCJsonrpcErrorMessageKey = attribute.Key("rpc.jsonrpc.error_message") +) + +// RPCJsonrpcVersion returns an attribute KeyValue conforming to the +// "rpc.jsonrpc.version" semantic conventions. It represents the protocol +// version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 +// does not specify this, the value can be omitted. +func RPCJsonrpcVersion(val string) attribute.KeyValue { + return RPCJsonrpcVersionKey.String(val) +} + +// RPCJsonrpcRequestID returns an attribute KeyValue conforming to the +// "rpc.jsonrpc.request_id" semantic conventions. It represents the `id` +// property of request or response. Since protocol allows id to be int, string, +// `null` or missing (for notifications), value is expected to be cast to +// string for simplicity. Use empty string in case of `null` value. Omit +// entirely if this is a notification. +func RPCJsonrpcRequestID(val string) attribute.KeyValue { + return RPCJsonrpcRequestIDKey.String(val) +} + +// RPCJsonrpcErrorCode returns an attribute KeyValue conforming to the +// "rpc.jsonrpc.error_code" semantic conventions. It represents the +// `error.code` property of response if it is an error response. +func RPCJsonrpcErrorCode(val int) attribute.KeyValue { + return RPCJsonrpcErrorCodeKey.Int(val) +} + +// RPCJsonrpcErrorMessage returns an attribute KeyValue conforming to the +// "rpc.jsonrpc.error_message" semantic conventions. It represents the +// `error.message` property of response if it is an error response. +func RPCJsonrpcErrorMessage(val string) attribute.KeyValue { + return RPCJsonrpcErrorMessageKey.String(val) +} + +// Tech-specific attributes for Connect RPC. +const ( + // RPCConnectRPCErrorCodeKey is the attribute Key conforming to the + // "rpc.connect_rpc.error_code" semantic conventions. It represents the + // [error codes](https://connect.build/docs/protocol/#error-codes) of the + // Connect request. Error codes are always string values. + // + // Type: Enum + // RequirementLevel: ConditionallyRequired (If response is not successful + // and if error code available.) + // Stability: stable + RPCConnectRPCErrorCodeKey = attribute.Key("rpc.connect_rpc.error_code") +) + +var ( + // cancelled + RPCConnectRPCErrorCodeCancelled = RPCConnectRPCErrorCodeKey.String("cancelled") + // unknown + RPCConnectRPCErrorCodeUnknown = RPCConnectRPCErrorCodeKey.String("unknown") + // invalid_argument + RPCConnectRPCErrorCodeInvalidArgument = RPCConnectRPCErrorCodeKey.String("invalid_argument") + // deadline_exceeded + RPCConnectRPCErrorCodeDeadlineExceeded = RPCConnectRPCErrorCodeKey.String("deadline_exceeded") + // not_found + RPCConnectRPCErrorCodeNotFound = RPCConnectRPCErrorCodeKey.String("not_found") + // already_exists + RPCConnectRPCErrorCodeAlreadyExists = RPCConnectRPCErrorCodeKey.String("already_exists") + // permission_denied + RPCConnectRPCErrorCodePermissionDenied = RPCConnectRPCErrorCodeKey.String("permission_denied") + // resource_exhausted + RPCConnectRPCErrorCodeResourceExhausted = RPCConnectRPCErrorCodeKey.String("resource_exhausted") + // failed_precondition + RPCConnectRPCErrorCodeFailedPrecondition = RPCConnectRPCErrorCodeKey.String("failed_precondition") + // aborted + RPCConnectRPCErrorCodeAborted = RPCConnectRPCErrorCodeKey.String("aborted") + // out_of_range + RPCConnectRPCErrorCodeOutOfRange = RPCConnectRPCErrorCodeKey.String("out_of_range") + // unimplemented + RPCConnectRPCErrorCodeUnimplemented = RPCConnectRPCErrorCodeKey.String("unimplemented") + // internal + RPCConnectRPCErrorCodeInternal = RPCConnectRPCErrorCodeKey.String("internal") + // unavailable + RPCConnectRPCErrorCodeUnavailable = RPCConnectRPCErrorCodeKey.String("unavailable") + // data_loss + RPCConnectRPCErrorCodeDataLoss = RPCConnectRPCErrorCodeKey.String("data_loss") + // unauthenticated + RPCConnectRPCErrorCodeUnauthenticated = RPCConnectRPCErrorCodeKey.String("unauthenticated") +) diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/README.md b/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/README.md deleted file mode 100644 index 2de1fc3c..00000000 --- a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Semconv v1.26.0 - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/semconv/v1.26.0)](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.26.0) diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go b/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go deleted file mode 100644 index d8dc822b..00000000 --- a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go +++ /dev/null @@ -1,8996 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Code generated from semantic convention specification. DO NOT EDIT. - -package semconv // import "go.opentelemetry.io/otel/semconv/v1.26.0" - -import "go.opentelemetry.io/otel/attribute" - -// The Android platform on which the Android application is running. -const ( - // AndroidOSAPILevelKey is the attribute Key conforming to the - // "android.os.api_level" semantic conventions. It represents the uniquely - // identifies the framework API revision offered by a version - // (`os.version`) of the android operating system. More information can be - // found - // [here](https://developer.android.com/guide/topics/manifest/uses-sdk-element#APILevels). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '33', '32' - AndroidOSAPILevelKey = attribute.Key("android.os.api_level") -) - -// AndroidOSAPILevel returns an attribute KeyValue conforming to the -// "android.os.api_level" semantic conventions. It represents the uniquely -// identifies the framework API revision offered by a version (`os.version`) of -// the android operating system. More information can be found -// [here](https://developer.android.com/guide/topics/manifest/uses-sdk-element#APILevels). -func AndroidOSAPILevel(val string) attribute.KeyValue { - return AndroidOSAPILevelKey.String(val) -} - -// ASP.NET Core attributes -const ( - // AspnetcoreRateLimitingResultKey is the attribute Key conforming to the - // "aspnetcore.rate_limiting.result" semantic conventions. It represents - // the rate-limiting result, shows whether the lease was acquired or - // contains a rejection reason - // - // Type: Enum - // RequirementLevel: Required - // Stability: stable - // Examples: 'acquired', 'request_canceled' - AspnetcoreRateLimitingResultKey = attribute.Key("aspnetcore.rate_limiting.result") - - // AspnetcoreDiagnosticsHandlerTypeKey is the attribute Key conforming to - // the "aspnetcore.diagnostics.handler.type" semantic conventions. It - // represents the full type name of the - // [`IExceptionHandler`](https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.diagnostics.iexceptionhandler) - // implementation that handled the exception. - // - // Type: string - // RequirementLevel: ConditionallyRequired (if and only if the exception - // was handled by this handler.) - // Stability: stable - // Examples: 'Contoso.MyHandler' - AspnetcoreDiagnosticsHandlerTypeKey = attribute.Key("aspnetcore.diagnostics.handler.type") - - // AspnetcoreDiagnosticsExceptionResultKey is the attribute Key conforming - // to the "aspnetcore.diagnostics.exception.result" semantic conventions. - // It represents the aSP.NET Core exception middleware handling result - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'handled', 'unhandled' - AspnetcoreDiagnosticsExceptionResultKey = attribute.Key("aspnetcore.diagnostics.exception.result") - - // AspnetcoreRateLimitingPolicyKey is the attribute Key conforming to the - // "aspnetcore.rate_limiting.policy" semantic conventions. It represents - // the rate limiting policy name. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'fixed', 'sliding', 'token' - AspnetcoreRateLimitingPolicyKey = attribute.Key("aspnetcore.rate_limiting.policy") - - // AspnetcoreRequestIsUnhandledKey is the attribute Key conforming to the - // "aspnetcore.request.is_unhandled" semantic conventions. It represents - // the flag indicating if request was handled by the application pipeline. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: stable - // Examples: True - AspnetcoreRequestIsUnhandledKey = attribute.Key("aspnetcore.request.is_unhandled") - - // AspnetcoreRoutingIsFallbackKey is the attribute Key conforming to the - // "aspnetcore.routing.is_fallback" semantic conventions. It represents a - // value that indicates whether the matched route is a fallback route. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: stable - // Examples: True - AspnetcoreRoutingIsFallbackKey = attribute.Key("aspnetcore.routing.is_fallback") - - // AspnetcoreRoutingMatchStatusKey is the attribute Key conforming to the - // "aspnetcore.routing.match_status" semantic conventions. It represents - // the match result - success or failure - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'success', 'failure' - AspnetcoreRoutingMatchStatusKey = attribute.Key("aspnetcore.routing.match_status") -) - -var ( - // Lease was acquired - AspnetcoreRateLimitingResultAcquired = AspnetcoreRateLimitingResultKey.String("acquired") - // Lease request was rejected by the endpoint limiter - AspnetcoreRateLimitingResultEndpointLimiter = AspnetcoreRateLimitingResultKey.String("endpoint_limiter") - // Lease request was rejected by the global limiter - AspnetcoreRateLimitingResultGlobalLimiter = AspnetcoreRateLimitingResultKey.String("global_limiter") - // Lease request was canceled - AspnetcoreRateLimitingResultRequestCanceled = AspnetcoreRateLimitingResultKey.String("request_canceled") -) - -var ( - // Exception was handled by the exception handling middleware - AspnetcoreDiagnosticsExceptionResultHandled = AspnetcoreDiagnosticsExceptionResultKey.String("handled") - // Exception was not handled by the exception handling middleware - AspnetcoreDiagnosticsExceptionResultUnhandled = AspnetcoreDiagnosticsExceptionResultKey.String("unhandled") - // Exception handling was skipped because the response had started - AspnetcoreDiagnosticsExceptionResultSkipped = AspnetcoreDiagnosticsExceptionResultKey.String("skipped") - // Exception handling didn't run because the request was aborted - AspnetcoreDiagnosticsExceptionResultAborted = AspnetcoreDiagnosticsExceptionResultKey.String("aborted") -) - -var ( - // Match succeeded - AspnetcoreRoutingMatchStatusSuccess = AspnetcoreRoutingMatchStatusKey.String("success") - // Match failed - AspnetcoreRoutingMatchStatusFailure = AspnetcoreRoutingMatchStatusKey.String("failure") -) - -// AspnetcoreDiagnosticsHandlerType returns an attribute KeyValue conforming -// to the "aspnetcore.diagnostics.handler.type" semantic conventions. It -// represents the full type name of the -// [`IExceptionHandler`](https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.diagnostics.iexceptionhandler) -// implementation that handled the exception. -func AspnetcoreDiagnosticsHandlerType(val string) attribute.KeyValue { - return AspnetcoreDiagnosticsHandlerTypeKey.String(val) -} - -// AspnetcoreRateLimitingPolicy returns an attribute KeyValue conforming to -// the "aspnetcore.rate_limiting.policy" semantic conventions. It represents -// the rate limiting policy name. -func AspnetcoreRateLimitingPolicy(val string) attribute.KeyValue { - return AspnetcoreRateLimitingPolicyKey.String(val) -} - -// AspnetcoreRequestIsUnhandled returns an attribute KeyValue conforming to -// the "aspnetcore.request.is_unhandled" semantic conventions. It represents -// the flag indicating if request was handled by the application pipeline. -func AspnetcoreRequestIsUnhandled(val bool) attribute.KeyValue { - return AspnetcoreRequestIsUnhandledKey.Bool(val) -} - -// AspnetcoreRoutingIsFallback returns an attribute KeyValue conforming to -// the "aspnetcore.routing.is_fallback" semantic conventions. It represents a -// value that indicates whether the matched route is a fallback route. -func AspnetcoreRoutingIsFallback(val bool) attribute.KeyValue { - return AspnetcoreRoutingIsFallbackKey.Bool(val) -} - -// Generic attributes for AWS services. -const ( - // AWSRequestIDKey is the attribute Key conforming to the "aws.request_id" - // semantic conventions. It represents the AWS request ID as returned in - // the response headers `x-amz-request-id` or `x-amz-requestid`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '79b9da39-b7ae-508a-a6bc-864b2829c622', 'C9ER4AJX75574TDJ' - AWSRequestIDKey = attribute.Key("aws.request_id") -) - -// AWSRequestID returns an attribute KeyValue conforming to the -// "aws.request_id" semantic conventions. It represents the AWS request ID as -// returned in the response headers `x-amz-request-id` or `x-amz-requestid`. -func AWSRequestID(val string) attribute.KeyValue { - return AWSRequestIDKey.String(val) -} - -// Attributes for AWS DynamoDB. -const ( - // AWSDynamoDBAttributeDefinitionsKey is the attribute Key conforming to - // the "aws.dynamodb.attribute_definitions" semantic conventions. It - // represents the JSON-serialized value of each item in the - // `AttributeDefinitions` request field. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '{ "AttributeName": "string", "AttributeType": "string" }' - AWSDynamoDBAttributeDefinitionsKey = attribute.Key("aws.dynamodb.attribute_definitions") - - // AWSDynamoDBAttributesToGetKey is the attribute Key conforming to the - // "aws.dynamodb.attributes_to_get" semantic conventions. It represents the - // value of the `AttributesToGet` request parameter. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'lives', 'id' - AWSDynamoDBAttributesToGetKey = attribute.Key("aws.dynamodb.attributes_to_get") - - // AWSDynamoDBConsistentReadKey is the attribute Key conforming to the - // "aws.dynamodb.consistent_read" semantic conventions. It represents the - // value of the `ConsistentRead` request parameter. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - AWSDynamoDBConsistentReadKey = attribute.Key("aws.dynamodb.consistent_read") - - // AWSDynamoDBConsumedCapacityKey is the attribute Key conforming to the - // "aws.dynamodb.consumed_capacity" semantic conventions. It represents the - // JSON-serialized value of each item in the `ConsumedCapacity` response - // field. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '{ "CapacityUnits": number, "GlobalSecondaryIndexes": { - // "string" : { "CapacityUnits": number, "ReadCapacityUnits": number, - // "WriteCapacityUnits": number } }, "LocalSecondaryIndexes": { "string" : - // { "CapacityUnits": number, "ReadCapacityUnits": number, - // "WriteCapacityUnits": number } }, "ReadCapacityUnits": number, "Table": - // { "CapacityUnits": number, "ReadCapacityUnits": number, - // "WriteCapacityUnits": number }, "TableName": "string", - // "WriteCapacityUnits": number }' - AWSDynamoDBConsumedCapacityKey = attribute.Key("aws.dynamodb.consumed_capacity") - - // AWSDynamoDBCountKey is the attribute Key conforming to the - // "aws.dynamodb.count" semantic conventions. It represents the value of - // the `Count` response parameter. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 10 - AWSDynamoDBCountKey = attribute.Key("aws.dynamodb.count") - - // AWSDynamoDBExclusiveStartTableKey is the attribute Key conforming to the - // "aws.dynamodb.exclusive_start_table" semantic conventions. It represents - // the value of the `ExclusiveStartTableName` request parameter. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Users', 'CatsTable' - AWSDynamoDBExclusiveStartTableKey = attribute.Key("aws.dynamodb.exclusive_start_table") - - // AWSDynamoDBGlobalSecondaryIndexUpdatesKey is the attribute Key - // conforming to the "aws.dynamodb.global_secondary_index_updates" semantic - // conventions. It represents the JSON-serialized value of each item in the - // `GlobalSecondaryIndexUpdates` request field. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '{ "Create": { "IndexName": "string", "KeySchema": [ { - // "AttributeName": "string", "KeyType": "string" } ], "Projection": { - // "NonKeyAttributes": [ "string" ], "ProjectionType": "string" }, - // "ProvisionedThroughput": { "ReadCapacityUnits": number, - // "WriteCapacityUnits": number } }' - AWSDynamoDBGlobalSecondaryIndexUpdatesKey = attribute.Key("aws.dynamodb.global_secondary_index_updates") - - // AWSDynamoDBGlobalSecondaryIndexesKey is the attribute Key conforming to - // the "aws.dynamodb.global_secondary_indexes" semantic conventions. It - // represents the JSON-serialized value of each item of the - // `GlobalSecondaryIndexes` request field - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '{ "IndexName": "string", "KeySchema": [ { "AttributeName": - // "string", "KeyType": "string" } ], "Projection": { "NonKeyAttributes": [ - // "string" ], "ProjectionType": "string" }, "ProvisionedThroughput": { - // "ReadCapacityUnits": number, "WriteCapacityUnits": number } }' - AWSDynamoDBGlobalSecondaryIndexesKey = attribute.Key("aws.dynamodb.global_secondary_indexes") - - // AWSDynamoDBIndexNameKey is the attribute Key conforming to the - // "aws.dynamodb.index_name" semantic conventions. It represents the value - // of the `IndexName` request parameter. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'name_to_group' - AWSDynamoDBIndexNameKey = attribute.Key("aws.dynamodb.index_name") - - // AWSDynamoDBItemCollectionMetricsKey is the attribute Key conforming to - // the "aws.dynamodb.item_collection_metrics" semantic conventions. It - // represents the JSON-serialized value of the `ItemCollectionMetrics` - // response field. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '{ "string" : [ { "ItemCollectionKey": { "string" : { "B": - // blob, "BOOL": boolean, "BS": [ blob ], "L": [ "AttributeValue" ], "M": { - // "string" : "AttributeValue" }, "N": "string", "NS": [ "string" ], - // "NULL": boolean, "S": "string", "SS": [ "string" ] } }, - // "SizeEstimateRangeGB": [ number ] } ] }' - AWSDynamoDBItemCollectionMetricsKey = attribute.Key("aws.dynamodb.item_collection_metrics") - - // AWSDynamoDBLimitKey is the attribute Key conforming to the - // "aws.dynamodb.limit" semantic conventions. It represents the value of - // the `Limit` request parameter. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 10 - AWSDynamoDBLimitKey = attribute.Key("aws.dynamodb.limit") - - // AWSDynamoDBLocalSecondaryIndexesKey is the attribute Key conforming to - // the "aws.dynamodb.local_secondary_indexes" semantic conventions. It - // represents the JSON-serialized value of each item of the - // `LocalSecondaryIndexes` request field. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '{ "IndexARN": "string", "IndexName": "string", - // "IndexSizeBytes": number, "ItemCount": number, "KeySchema": [ { - // "AttributeName": "string", "KeyType": "string" } ], "Projection": { - // "NonKeyAttributes": [ "string" ], "ProjectionType": "string" } }' - AWSDynamoDBLocalSecondaryIndexesKey = attribute.Key("aws.dynamodb.local_secondary_indexes") - - // AWSDynamoDBProjectionKey is the attribute Key conforming to the - // "aws.dynamodb.projection" semantic conventions. It represents the value - // of the `ProjectionExpression` request parameter. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Title', 'Title, Price, Color', 'Title, Description, - // RelatedItems, ProductReviews' - AWSDynamoDBProjectionKey = attribute.Key("aws.dynamodb.projection") - - // AWSDynamoDBProvisionedReadCapacityKey is the attribute Key conforming to - // the "aws.dynamodb.provisioned_read_capacity" semantic conventions. It - // represents the value of the `ProvisionedThroughput.ReadCapacityUnits` - // request parameter. - // - // Type: double - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1.0, 2.0 - AWSDynamoDBProvisionedReadCapacityKey = attribute.Key("aws.dynamodb.provisioned_read_capacity") - - // AWSDynamoDBProvisionedWriteCapacityKey is the attribute Key conforming - // to the "aws.dynamodb.provisioned_write_capacity" semantic conventions. - // It represents the value of the - // `ProvisionedThroughput.WriteCapacityUnits` request parameter. - // - // Type: double - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1.0, 2.0 - AWSDynamoDBProvisionedWriteCapacityKey = attribute.Key("aws.dynamodb.provisioned_write_capacity") - - // AWSDynamoDBScanForwardKey is the attribute Key conforming to the - // "aws.dynamodb.scan_forward" semantic conventions. It represents the - // value of the `ScanIndexForward` request parameter. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - AWSDynamoDBScanForwardKey = attribute.Key("aws.dynamodb.scan_forward") - - // AWSDynamoDBScannedCountKey is the attribute Key conforming to the - // "aws.dynamodb.scanned_count" semantic conventions. It represents the - // value of the `ScannedCount` response parameter. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 50 - AWSDynamoDBScannedCountKey = attribute.Key("aws.dynamodb.scanned_count") - - // AWSDynamoDBSegmentKey is the attribute Key conforming to the - // "aws.dynamodb.segment" semantic conventions. It represents the value of - // the `Segment` request parameter. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 10 - AWSDynamoDBSegmentKey = attribute.Key("aws.dynamodb.segment") - - // AWSDynamoDBSelectKey is the attribute Key conforming to the - // "aws.dynamodb.select" semantic conventions. It represents the value of - // the `Select` request parameter. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'ALL_ATTRIBUTES', 'COUNT' - AWSDynamoDBSelectKey = attribute.Key("aws.dynamodb.select") - - // AWSDynamoDBTableCountKey is the attribute Key conforming to the - // "aws.dynamodb.table_count" semantic conventions. It represents the - // number of items in the `TableNames` response parameter. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 20 - AWSDynamoDBTableCountKey = attribute.Key("aws.dynamodb.table_count") - - // AWSDynamoDBTableNamesKey is the attribute Key conforming to the - // "aws.dynamodb.table_names" semantic conventions. It represents the keys - // in the `RequestItems` object field. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Users', 'Cats' - AWSDynamoDBTableNamesKey = attribute.Key("aws.dynamodb.table_names") - - // AWSDynamoDBTotalSegmentsKey is the attribute Key conforming to the - // "aws.dynamodb.total_segments" semantic conventions. It represents the - // value of the `TotalSegments` request parameter. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 100 - AWSDynamoDBTotalSegmentsKey = attribute.Key("aws.dynamodb.total_segments") -) - -// AWSDynamoDBAttributeDefinitions returns an attribute KeyValue conforming -// to the "aws.dynamodb.attribute_definitions" semantic conventions. It -// represents the JSON-serialized value of each item in the -// `AttributeDefinitions` request field. -func AWSDynamoDBAttributeDefinitions(val ...string) attribute.KeyValue { - return AWSDynamoDBAttributeDefinitionsKey.StringSlice(val) -} - -// AWSDynamoDBAttributesToGet returns an attribute KeyValue conforming to -// the "aws.dynamodb.attributes_to_get" semantic conventions. It represents the -// value of the `AttributesToGet` request parameter. -func AWSDynamoDBAttributesToGet(val ...string) attribute.KeyValue { - return AWSDynamoDBAttributesToGetKey.StringSlice(val) -} - -// AWSDynamoDBConsistentRead returns an attribute KeyValue conforming to the -// "aws.dynamodb.consistent_read" semantic conventions. It represents the value -// of the `ConsistentRead` request parameter. -func AWSDynamoDBConsistentRead(val bool) attribute.KeyValue { - return AWSDynamoDBConsistentReadKey.Bool(val) -} - -// AWSDynamoDBConsumedCapacity returns an attribute KeyValue conforming to -// the "aws.dynamodb.consumed_capacity" semantic conventions. It represents the -// JSON-serialized value of each item in the `ConsumedCapacity` response field. -func AWSDynamoDBConsumedCapacity(val ...string) attribute.KeyValue { - return AWSDynamoDBConsumedCapacityKey.StringSlice(val) -} - -// AWSDynamoDBCount returns an attribute KeyValue conforming to the -// "aws.dynamodb.count" semantic conventions. It represents the value of the -// `Count` response parameter. -func AWSDynamoDBCount(val int) attribute.KeyValue { - return AWSDynamoDBCountKey.Int(val) -} - -// AWSDynamoDBExclusiveStartTable returns an attribute KeyValue conforming -// to the "aws.dynamodb.exclusive_start_table" semantic conventions. It -// represents the value of the `ExclusiveStartTableName` request parameter. -func AWSDynamoDBExclusiveStartTable(val string) attribute.KeyValue { - return AWSDynamoDBExclusiveStartTableKey.String(val) -} - -// AWSDynamoDBGlobalSecondaryIndexUpdates returns an attribute KeyValue -// conforming to the "aws.dynamodb.global_secondary_index_updates" semantic -// conventions. It represents the JSON-serialized value of each item in the -// `GlobalSecondaryIndexUpdates` request field. -func AWSDynamoDBGlobalSecondaryIndexUpdates(val ...string) attribute.KeyValue { - return AWSDynamoDBGlobalSecondaryIndexUpdatesKey.StringSlice(val) -} - -// AWSDynamoDBGlobalSecondaryIndexes returns an attribute KeyValue -// conforming to the "aws.dynamodb.global_secondary_indexes" semantic -// conventions. It represents the JSON-serialized value of each item of the -// `GlobalSecondaryIndexes` request field -func AWSDynamoDBGlobalSecondaryIndexes(val ...string) attribute.KeyValue { - return AWSDynamoDBGlobalSecondaryIndexesKey.StringSlice(val) -} - -// AWSDynamoDBIndexName returns an attribute KeyValue conforming to the -// "aws.dynamodb.index_name" semantic conventions. It represents the value of -// the `IndexName` request parameter. -func AWSDynamoDBIndexName(val string) attribute.KeyValue { - return AWSDynamoDBIndexNameKey.String(val) -} - -// AWSDynamoDBItemCollectionMetrics returns an attribute KeyValue conforming -// to the "aws.dynamodb.item_collection_metrics" semantic conventions. It -// represents the JSON-serialized value of the `ItemCollectionMetrics` response -// field. -func AWSDynamoDBItemCollectionMetrics(val string) attribute.KeyValue { - return AWSDynamoDBItemCollectionMetricsKey.String(val) -} - -// AWSDynamoDBLimit returns an attribute KeyValue conforming to the -// "aws.dynamodb.limit" semantic conventions. It represents the value of the -// `Limit` request parameter. -func AWSDynamoDBLimit(val int) attribute.KeyValue { - return AWSDynamoDBLimitKey.Int(val) -} - -// AWSDynamoDBLocalSecondaryIndexes returns an attribute KeyValue conforming -// to the "aws.dynamodb.local_secondary_indexes" semantic conventions. It -// represents the JSON-serialized value of each item of the -// `LocalSecondaryIndexes` request field. -func AWSDynamoDBLocalSecondaryIndexes(val ...string) attribute.KeyValue { - return AWSDynamoDBLocalSecondaryIndexesKey.StringSlice(val) -} - -// AWSDynamoDBProjection returns an attribute KeyValue conforming to the -// "aws.dynamodb.projection" semantic conventions. It represents the value of -// the `ProjectionExpression` request parameter. -func AWSDynamoDBProjection(val string) attribute.KeyValue { - return AWSDynamoDBProjectionKey.String(val) -} - -// AWSDynamoDBProvisionedReadCapacity returns an attribute KeyValue -// conforming to the "aws.dynamodb.provisioned_read_capacity" semantic -// conventions. It represents the value of the -// `ProvisionedThroughput.ReadCapacityUnits` request parameter. -func AWSDynamoDBProvisionedReadCapacity(val float64) attribute.KeyValue { - return AWSDynamoDBProvisionedReadCapacityKey.Float64(val) -} - -// AWSDynamoDBProvisionedWriteCapacity returns an attribute KeyValue -// conforming to the "aws.dynamodb.provisioned_write_capacity" semantic -// conventions. It represents the value of the -// `ProvisionedThroughput.WriteCapacityUnits` request parameter. -func AWSDynamoDBProvisionedWriteCapacity(val float64) attribute.KeyValue { - return AWSDynamoDBProvisionedWriteCapacityKey.Float64(val) -} - -// AWSDynamoDBScanForward returns an attribute KeyValue conforming to the -// "aws.dynamodb.scan_forward" semantic conventions. It represents the value of -// the `ScanIndexForward` request parameter. -func AWSDynamoDBScanForward(val bool) attribute.KeyValue { - return AWSDynamoDBScanForwardKey.Bool(val) -} - -// AWSDynamoDBScannedCount returns an attribute KeyValue conforming to the -// "aws.dynamodb.scanned_count" semantic conventions. It represents the value -// of the `ScannedCount` response parameter. -func AWSDynamoDBScannedCount(val int) attribute.KeyValue { - return AWSDynamoDBScannedCountKey.Int(val) -} - -// AWSDynamoDBSegment returns an attribute KeyValue conforming to the -// "aws.dynamodb.segment" semantic conventions. It represents the value of the -// `Segment` request parameter. -func AWSDynamoDBSegment(val int) attribute.KeyValue { - return AWSDynamoDBSegmentKey.Int(val) -} - -// AWSDynamoDBSelect returns an attribute KeyValue conforming to the -// "aws.dynamodb.select" semantic conventions. It represents the value of the -// `Select` request parameter. -func AWSDynamoDBSelect(val string) attribute.KeyValue { - return AWSDynamoDBSelectKey.String(val) -} - -// AWSDynamoDBTableCount returns an attribute KeyValue conforming to the -// "aws.dynamodb.table_count" semantic conventions. It represents the number of -// items in the `TableNames` response parameter. -func AWSDynamoDBTableCount(val int) attribute.KeyValue { - return AWSDynamoDBTableCountKey.Int(val) -} - -// AWSDynamoDBTableNames returns an attribute KeyValue conforming to the -// "aws.dynamodb.table_names" semantic conventions. It represents the keys in -// the `RequestItems` object field. -func AWSDynamoDBTableNames(val ...string) attribute.KeyValue { - return AWSDynamoDBTableNamesKey.StringSlice(val) -} - -// AWSDynamoDBTotalSegments returns an attribute KeyValue conforming to the -// "aws.dynamodb.total_segments" semantic conventions. It represents the value -// of the `TotalSegments` request parameter. -func AWSDynamoDBTotalSegments(val int) attribute.KeyValue { - return AWSDynamoDBTotalSegmentsKey.Int(val) -} - -// Attributes for AWS Elastic Container Service (ECS). -const ( - // AWSECSTaskIDKey is the attribute Key conforming to the "aws.ecs.task.id" - // semantic conventions. It represents the ID of a running ECS task. The ID - // MUST be extracted from `task.arn`. - // - // Type: string - // RequirementLevel: ConditionallyRequired (If and only if `task.arn` is - // populated.) - // Stability: experimental - // Examples: '10838bed-421f-43ef-870a-f43feacbbb5b', - // '23ebb8ac-c18f-46c6-8bbe-d55d0e37cfbd' - AWSECSTaskIDKey = attribute.Key("aws.ecs.task.id") - - // AWSECSClusterARNKey is the attribute Key conforming to the - // "aws.ecs.cluster.arn" semantic conventions. It represents the ARN of an - // [ECS - // cluster](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'arn:aws:ecs:us-west-2:123456789123:cluster/my-cluster' - AWSECSClusterARNKey = attribute.Key("aws.ecs.cluster.arn") - - // AWSECSContainerARNKey is the attribute Key conforming to the - // "aws.ecs.container.arn" semantic conventions. It represents the Amazon - // Resource Name (ARN) of an [ECS container - // instance](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_instances.html). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'arn:aws:ecs:us-west-1:123456789123:container/32624152-9086-4f0e-acae-1a75b14fe4d9' - AWSECSContainerARNKey = attribute.Key("aws.ecs.container.arn") - - // AWSECSLaunchtypeKey is the attribute Key conforming to the - // "aws.ecs.launchtype" semantic conventions. It represents the [launch - // type](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_types.html) - // for an ECS task. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - AWSECSLaunchtypeKey = attribute.Key("aws.ecs.launchtype") - - // AWSECSTaskARNKey is the attribute Key conforming to the - // "aws.ecs.task.arn" semantic conventions. It represents the ARN of a - // running [ECS - // task](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'arn:aws:ecs:us-west-1:123456789123:task/10838bed-421f-43ef-870a-f43feacbbb5b', - // 'arn:aws:ecs:us-west-1:123456789123:task/my-cluster/task-id/23ebb8ac-c18f-46c6-8bbe-d55d0e37cfbd' - AWSECSTaskARNKey = attribute.Key("aws.ecs.task.arn") - - // AWSECSTaskFamilyKey is the attribute Key conforming to the - // "aws.ecs.task.family" semantic conventions. It represents the family - // name of the [ECS task - // definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html) - // used to create the ECS task. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry-family' - AWSECSTaskFamilyKey = attribute.Key("aws.ecs.task.family") - - // AWSECSTaskRevisionKey is the attribute Key conforming to the - // "aws.ecs.task.revision" semantic conventions. It represents the revision - // for the task definition used to create the ECS task. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '8', '26' - AWSECSTaskRevisionKey = attribute.Key("aws.ecs.task.revision") -) - -var ( - // ec2 - AWSECSLaunchtypeEC2 = AWSECSLaunchtypeKey.String("ec2") - // fargate - AWSECSLaunchtypeFargate = AWSECSLaunchtypeKey.String("fargate") -) - -// AWSECSTaskID returns an attribute KeyValue conforming to the -// "aws.ecs.task.id" semantic conventions. It represents the ID of a running -// ECS task. The ID MUST be extracted from `task.arn`. -func AWSECSTaskID(val string) attribute.KeyValue { - return AWSECSTaskIDKey.String(val) -} - -// AWSECSClusterARN returns an attribute KeyValue conforming to the -// "aws.ecs.cluster.arn" semantic conventions. It represents the ARN of an [ECS -// cluster](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html). -func AWSECSClusterARN(val string) attribute.KeyValue { - return AWSECSClusterARNKey.String(val) -} - -// AWSECSContainerARN returns an attribute KeyValue conforming to the -// "aws.ecs.container.arn" semantic conventions. It represents the Amazon -// Resource Name (ARN) of an [ECS container -// instance](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_instances.html). -func AWSECSContainerARN(val string) attribute.KeyValue { - return AWSECSContainerARNKey.String(val) -} - -// AWSECSTaskARN returns an attribute KeyValue conforming to the -// "aws.ecs.task.arn" semantic conventions. It represents the ARN of a running -// [ECS -// task](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids). -func AWSECSTaskARN(val string) attribute.KeyValue { - return AWSECSTaskARNKey.String(val) -} - -// AWSECSTaskFamily returns an attribute KeyValue conforming to the -// "aws.ecs.task.family" semantic conventions. It represents the family name of -// the [ECS task -// definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html) -// used to create the ECS task. -func AWSECSTaskFamily(val string) attribute.KeyValue { - return AWSECSTaskFamilyKey.String(val) -} - -// AWSECSTaskRevision returns an attribute KeyValue conforming to the -// "aws.ecs.task.revision" semantic conventions. It represents the revision for -// the task definition used to create the ECS task. -func AWSECSTaskRevision(val string) attribute.KeyValue { - return AWSECSTaskRevisionKey.String(val) -} - -// Attributes for AWS Elastic Kubernetes Service (EKS). -const ( - // AWSEKSClusterARNKey is the attribute Key conforming to the - // "aws.eks.cluster.arn" semantic conventions. It represents the ARN of an - // EKS cluster. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'arn:aws:ecs:us-west-2:123456789123:cluster/my-cluster' - AWSEKSClusterARNKey = attribute.Key("aws.eks.cluster.arn") -) - -// AWSEKSClusterARN returns an attribute KeyValue conforming to the -// "aws.eks.cluster.arn" semantic conventions. It represents the ARN of an EKS -// cluster. -func AWSEKSClusterARN(val string) attribute.KeyValue { - return AWSEKSClusterARNKey.String(val) -} - -// Attributes for AWS Logs. -const ( - // AWSLogGroupARNsKey is the attribute Key conforming to the - // "aws.log.group.arns" semantic conventions. It represents the Amazon - // Resource Name(s) (ARN) of the AWS log group(s). - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'arn:aws:logs:us-west-1:123456789012:log-group:/aws/my/group:*' - // Note: See the [log group ARN format - // documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/iam-access-control-overview-cwl.html#CWL_ARN_Format). - AWSLogGroupARNsKey = attribute.Key("aws.log.group.arns") - - // AWSLogGroupNamesKey is the attribute Key conforming to the - // "aws.log.group.names" semantic conventions. It represents the name(s) of - // the AWS log group(s) an application is writing to. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/aws/lambda/my-function', 'opentelemetry-service' - // Note: Multiple log groups must be supported for cases like - // multi-container applications, where a single application has sidecar - // containers, and each write to their own log group. - AWSLogGroupNamesKey = attribute.Key("aws.log.group.names") - - // AWSLogStreamARNsKey is the attribute Key conforming to the - // "aws.log.stream.arns" semantic conventions. It represents the ARN(s) of - // the AWS log stream(s). - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'arn:aws:logs:us-west-1:123456789012:log-group:/aws/my/group:log-stream:logs/main/10838bed-421f-43ef-870a-f43feacbbb5b' - // Note: See the [log stream ARN format - // documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/iam-access-control-overview-cwl.html#CWL_ARN_Format). - // One log group can contain several log streams, so these ARNs necessarily - // identify both a log group and a log stream. - AWSLogStreamARNsKey = attribute.Key("aws.log.stream.arns") - - // AWSLogStreamNamesKey is the attribute Key conforming to the - // "aws.log.stream.names" semantic conventions. It represents the name(s) - // of the AWS log stream(s) an application is writing to. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'logs/main/10838bed-421f-43ef-870a-f43feacbbb5b' - AWSLogStreamNamesKey = attribute.Key("aws.log.stream.names") -) - -// AWSLogGroupARNs returns an attribute KeyValue conforming to the -// "aws.log.group.arns" semantic conventions. It represents the Amazon Resource -// Name(s) (ARN) of the AWS log group(s). -func AWSLogGroupARNs(val ...string) attribute.KeyValue { - return AWSLogGroupARNsKey.StringSlice(val) -} - -// AWSLogGroupNames returns an attribute KeyValue conforming to the -// "aws.log.group.names" semantic conventions. It represents the name(s) of the -// AWS log group(s) an application is writing to. -func AWSLogGroupNames(val ...string) attribute.KeyValue { - return AWSLogGroupNamesKey.StringSlice(val) -} - -// AWSLogStreamARNs returns an attribute KeyValue conforming to the -// "aws.log.stream.arns" semantic conventions. It represents the ARN(s) of the -// AWS log stream(s). -func AWSLogStreamARNs(val ...string) attribute.KeyValue { - return AWSLogStreamARNsKey.StringSlice(val) -} - -// AWSLogStreamNames returns an attribute KeyValue conforming to the -// "aws.log.stream.names" semantic conventions. It represents the name(s) of -// the AWS log stream(s) an application is writing to. -func AWSLogStreamNames(val ...string) attribute.KeyValue { - return AWSLogStreamNamesKey.StringSlice(val) -} - -// Attributes for AWS Lambda. -const ( - // AWSLambdaInvokedARNKey is the attribute Key conforming to the - // "aws.lambda.invoked_arn" semantic conventions. It represents the full - // invoked ARN as provided on the `Context` passed to the function - // (`Lambda-Runtime-Invoked-Function-ARN` header on the - // `/runtime/invocation/next` applicable). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'arn:aws:lambda:us-east-1:123456:function:myfunction:myalias' - // Note: This may be different from `cloud.resource_id` if an alias is - // involved. - AWSLambdaInvokedARNKey = attribute.Key("aws.lambda.invoked_arn") -) - -// AWSLambdaInvokedARN returns an attribute KeyValue conforming to the -// "aws.lambda.invoked_arn" semantic conventions. It represents the full -// invoked ARN as provided on the `Context` passed to the function -// (`Lambda-Runtime-Invoked-Function-ARN` header on the -// `/runtime/invocation/next` applicable). -func AWSLambdaInvokedARN(val string) attribute.KeyValue { - return AWSLambdaInvokedARNKey.String(val) -} - -// Attributes for AWS S3. -const ( - // AWSS3BucketKey is the attribute Key conforming to the "aws.s3.bucket" - // semantic conventions. It represents the S3 bucket name the request - // refers to. Corresponds to the `--bucket` parameter of the [S3 - // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) - // operations. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'some-bucket-name' - // Note: The `bucket` attribute is applicable to all S3 operations that - // reference a bucket, i.e. that require the bucket name as a mandatory - // parameter. - // This applies to almost all S3 operations except `list-buckets`. - AWSS3BucketKey = attribute.Key("aws.s3.bucket") - - // AWSS3CopySourceKey is the attribute Key conforming to the - // "aws.s3.copy_source" semantic conventions. It represents the source - // object (in the form `bucket`/`key`) for the copy operation. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'someFile.yml' - // Note: The `copy_source` attribute applies to S3 copy operations and - // corresponds to the `--copy-source` parameter - // of the [copy-object operation within the S3 - // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html). - // This applies in particular to the following operations: - // - // - - // [copy-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html) - // - - // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) - AWSS3CopySourceKey = attribute.Key("aws.s3.copy_source") - - // AWSS3DeleteKey is the attribute Key conforming to the "aws.s3.delete" - // semantic conventions. It represents the delete request container that - // specifies the objects to be deleted. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'Objects=[{Key=string,VersionID=string},{Key=string,VersionID=string}],Quiet=boolean' - // Note: The `delete` attribute is only applicable to the - // [delete-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-object.html) - // operation. - // The `delete` attribute corresponds to the `--delete` parameter of the - // [delete-objects operation within the S3 - // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-objects.html). - AWSS3DeleteKey = attribute.Key("aws.s3.delete") - - // AWSS3KeyKey is the attribute Key conforming to the "aws.s3.key" semantic - // conventions. It represents the S3 object key the request refers to. - // Corresponds to the `--key` parameter of the [S3 - // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) - // operations. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'someFile.yml' - // Note: The `key` attribute is applicable to all object-related S3 - // operations, i.e. that require the object key as a mandatory parameter. - // This applies in particular to the following operations: - // - // - - // [copy-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html) - // - - // [delete-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-object.html) - // - - // [get-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/get-object.html) - // - - // [head-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/head-object.html) - // - - // [put-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html) - // - - // [restore-object](https://docs.aws.amazon.com/cli/latest/reference/s3api/restore-object.html) - // - - // [select-object-content](https://docs.aws.amazon.com/cli/latest/reference/s3api/select-object-content.html) - // - - // [abort-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/abort-multipart-upload.html) - // - - // [complete-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/complete-multipart-upload.html) - // - - // [create-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/create-multipart-upload.html) - // - - // [list-parts](https://docs.aws.amazon.com/cli/latest/reference/s3api/list-parts.html) - // - - // [upload-part](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html) - // - - // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) - AWSS3KeyKey = attribute.Key("aws.s3.key") - - // AWSS3PartNumberKey is the attribute Key conforming to the - // "aws.s3.part_number" semantic conventions. It represents the part number - // of the part being uploaded in a multipart-upload operation. This is a - // positive integer between 1 and 10,000. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 3456 - // Note: The `part_number` attribute is only applicable to the - // [upload-part](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html) - // and - // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) - // operations. - // The `part_number` attribute corresponds to the `--part-number` parameter - // of the - // [upload-part operation within the S3 - // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html). - AWSS3PartNumberKey = attribute.Key("aws.s3.part_number") - - // AWSS3UploadIDKey is the attribute Key conforming to the - // "aws.s3.upload_id" semantic conventions. It represents the upload ID - // that identifies the multipart upload. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'dfRtDYWFbkRONycy.Yxwh66Yjlx.cph0gtNBtJ' - // Note: The `upload_id` attribute applies to S3 multipart-upload - // operations and corresponds to the `--upload-id` parameter - // of the [S3 - // API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) - // multipart operations. - // This applies in particular to the following operations: - // - // - - // [abort-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/abort-multipart-upload.html) - // - - // [complete-multipart-upload](https://docs.aws.amazon.com/cli/latest/reference/s3api/complete-multipart-upload.html) - // - - // [list-parts](https://docs.aws.amazon.com/cli/latest/reference/s3api/list-parts.html) - // - - // [upload-part](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part.html) - // - - // [upload-part-copy](https://docs.aws.amazon.com/cli/latest/reference/s3api/upload-part-copy.html) - AWSS3UploadIDKey = attribute.Key("aws.s3.upload_id") -) - -// AWSS3Bucket returns an attribute KeyValue conforming to the -// "aws.s3.bucket" semantic conventions. It represents the S3 bucket name the -// request refers to. Corresponds to the `--bucket` parameter of the [S3 -// API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) -// operations. -func AWSS3Bucket(val string) attribute.KeyValue { - return AWSS3BucketKey.String(val) -} - -// AWSS3CopySource returns an attribute KeyValue conforming to the -// "aws.s3.copy_source" semantic conventions. It represents the source object -// (in the form `bucket`/`key`) for the copy operation. -func AWSS3CopySource(val string) attribute.KeyValue { - return AWSS3CopySourceKey.String(val) -} - -// AWSS3Delete returns an attribute KeyValue conforming to the -// "aws.s3.delete" semantic conventions. It represents the delete request -// container that specifies the objects to be deleted. -func AWSS3Delete(val string) attribute.KeyValue { - return AWSS3DeleteKey.String(val) -} - -// AWSS3Key returns an attribute KeyValue conforming to the "aws.s3.key" -// semantic conventions. It represents the S3 object key the request refers to. -// Corresponds to the `--key` parameter of the [S3 -// API](https://docs.aws.amazon.com/cli/latest/reference/s3api/index.html) -// operations. -func AWSS3Key(val string) attribute.KeyValue { - return AWSS3KeyKey.String(val) -} - -// AWSS3PartNumber returns an attribute KeyValue conforming to the -// "aws.s3.part_number" semantic conventions. It represents the part number of -// the part being uploaded in a multipart-upload operation. This is a positive -// integer between 1 and 10,000. -func AWSS3PartNumber(val int) attribute.KeyValue { - return AWSS3PartNumberKey.Int(val) -} - -// AWSS3UploadID returns an attribute KeyValue conforming to the -// "aws.s3.upload_id" semantic conventions. It represents the upload ID that -// identifies the multipart upload. -func AWSS3UploadID(val string) attribute.KeyValue { - return AWSS3UploadIDKey.String(val) -} - -// The web browser attributes -const ( - // BrowserBrandsKey is the attribute Key conforming to the "browser.brands" - // semantic conventions. It represents the array of brand name and version - // separated by a space - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: ' Not A;Brand 99', 'Chromium 99', 'Chrome 99' - // Note: This value is intended to be taken from the [UA client hints - // API](https://wicg.github.io/ua-client-hints/#interface) - // (`navigator.userAgentData.brands`). - BrowserBrandsKey = attribute.Key("browser.brands") - - // BrowserLanguageKey is the attribute Key conforming to the - // "browser.language" semantic conventions. It represents the preferred - // language of the user using the browser - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'en', 'en-US', 'fr', 'fr-FR' - // Note: This value is intended to be taken from the Navigator API - // `navigator.language`. - BrowserLanguageKey = attribute.Key("browser.language") - - // BrowserMobileKey is the attribute Key conforming to the "browser.mobile" - // semantic conventions. It represents a boolean that is true if the - // browser is running on a mobile device - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - // Note: This value is intended to be taken from the [UA client hints - // API](https://wicg.github.io/ua-client-hints/#interface) - // (`navigator.userAgentData.mobile`). If unavailable, this attribute - // SHOULD be left unset. - BrowserMobileKey = attribute.Key("browser.mobile") - - // BrowserPlatformKey is the attribute Key conforming to the - // "browser.platform" semantic conventions. It represents the platform on - // which the browser is running - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Windows', 'macOS', 'Android' - // Note: This value is intended to be taken from the [UA client hints - // API](https://wicg.github.io/ua-client-hints/#interface) - // (`navigator.userAgentData.platform`). If unavailable, the legacy - // `navigator.platform` API SHOULD NOT be used instead and this attribute - // SHOULD be left unset in order for the values to be consistent. - // The list of possible values is defined in the [W3C User-Agent Client - // Hints - // specification](https://wicg.github.io/ua-client-hints/#sec-ch-ua-platform). - // Note that some (but not all) of these values can overlap with values in - // the [`os.type` and `os.name` attributes](./os.md). However, for - // consistency, the values in the `browser.platform` attribute should - // capture the exact value that the user agent provides. - BrowserPlatformKey = attribute.Key("browser.platform") -) - -// BrowserBrands returns an attribute KeyValue conforming to the -// "browser.brands" semantic conventions. It represents the array of brand name -// and version separated by a space -func BrowserBrands(val ...string) attribute.KeyValue { - return BrowserBrandsKey.StringSlice(val) -} - -// BrowserLanguage returns an attribute KeyValue conforming to the -// "browser.language" semantic conventions. It represents the preferred -// language of the user using the browser -func BrowserLanguage(val string) attribute.KeyValue { - return BrowserLanguageKey.String(val) -} - -// BrowserMobile returns an attribute KeyValue conforming to the -// "browser.mobile" semantic conventions. It represents a boolean that is true -// if the browser is running on a mobile device -func BrowserMobile(val bool) attribute.KeyValue { - return BrowserMobileKey.Bool(val) -} - -// BrowserPlatform returns an attribute KeyValue conforming to the -// "browser.platform" semantic conventions. It represents the platform on which -// the browser is running -func BrowserPlatform(val string) attribute.KeyValue { - return BrowserPlatformKey.String(val) -} - -// These attributes may be used to describe the client in a connection-based -// network interaction where there is one side that initiates the connection -// (the client is the side that initiates the connection). This covers all TCP -// network interactions since TCP is connection-based and one side initiates -// the connection (an exception is made for peer-to-peer communication over TCP -// where the "user-facing" surface of the protocol / API doesn't expose a clear -// notion of client and server). This also covers UDP network interactions -// where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. -const ( - // ClientAddressKey is the attribute Key conforming to the "client.address" - // semantic conventions. It represents the client address - domain name if - // available without reverse DNS lookup; otherwise, IP address or Unix - // domain socket name. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'client.example.com', '10.1.2.80', '/tmp/my.sock' - // Note: When observed from the server side, and when communicating through - // an intermediary, `client.address` SHOULD represent the client address - // behind any intermediaries, for example proxies, if it's available. - ClientAddressKey = attribute.Key("client.address") - - // ClientPortKey is the attribute Key conforming to the "client.port" - // semantic conventions. It represents the client port number. - // - // Type: int - // RequirementLevel: Optional - // Stability: stable - // Examples: 65123 - // Note: When observed from the server side, and when communicating through - // an intermediary, `client.port` SHOULD represent the client port behind - // any intermediaries, for example proxies, if it's available. - ClientPortKey = attribute.Key("client.port") -) - -// ClientAddress returns an attribute KeyValue conforming to the -// "client.address" semantic conventions. It represents the client address - -// domain name if available without reverse DNS lookup; otherwise, IP address -// or Unix domain socket name. -func ClientAddress(val string) attribute.KeyValue { - return ClientAddressKey.String(val) -} - -// ClientPort returns an attribute KeyValue conforming to the "client.port" -// semantic conventions. It represents the client port number. -func ClientPort(val int) attribute.KeyValue { - return ClientPortKey.Int(val) -} - -// A cloud environment (e.g. GCP, Azure, AWS). -const ( - // CloudAccountIDKey is the attribute Key conforming to the - // "cloud.account.id" semantic conventions. It represents the cloud account - // ID the resource is assigned to. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '111111111111', 'opentelemetry' - CloudAccountIDKey = attribute.Key("cloud.account.id") - - // CloudAvailabilityZoneKey is the attribute Key conforming to the - // "cloud.availability_zone" semantic conventions. It represents the cloud - // regions often have multiple, isolated locations known as zones to - // increase availability. Availability zone represents the zone where the - // resource is running. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'us-east-1c' - // Note: Availability zones are called "zones" on Alibaba Cloud and Google - // Cloud. - CloudAvailabilityZoneKey = attribute.Key("cloud.availability_zone") - - // CloudPlatformKey is the attribute Key conforming to the "cloud.platform" - // semantic conventions. It represents the cloud platform in use. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: The prefix of the service SHOULD match the one specified in - // `cloud.provider`. - CloudPlatformKey = attribute.Key("cloud.platform") - - // CloudProviderKey is the attribute Key conforming to the "cloud.provider" - // semantic conventions. It represents the name of the cloud provider. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - CloudProviderKey = attribute.Key("cloud.provider") - - // CloudRegionKey is the attribute Key conforming to the "cloud.region" - // semantic conventions. It represents the geographical region the resource - // is running. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'us-central1', 'us-east-1' - // Note: Refer to your provider's docs to see the available regions, for - // example [Alibaba Cloud - // regions](https://www.alibabacloud.com/help/doc-detail/40654.htm), [AWS - // regions](https://aws.amazon.com/about-aws/global-infrastructure/regions_az/), - // [Azure - // regions](https://azure.microsoft.com/global-infrastructure/geographies/), - // [Google Cloud regions](https://cloud.google.com/about/locations), or - // [Tencent Cloud - // regions](https://www.tencentcloud.com/document/product/213/6091). - CloudRegionKey = attribute.Key("cloud.region") - - // CloudResourceIDKey is the attribute Key conforming to the - // "cloud.resource_id" semantic conventions. It represents the cloud - // provider-specific native identifier of the monitored cloud resource - // (e.g. an - // [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // on AWS, a [fully qualified resource - // ID](https://learn.microsoft.com/rest/api/resources/resources/get-by-id) - // on Azure, a [full resource - // name](https://cloud.google.com/apis/design/resource_names#full_resource_name) - // on GCP) - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'arn:aws:lambda:REGION:ACCOUNT_ID:function:my-function', - // '//run.googleapis.com/projects/PROJECT_ID/locations/LOCATION_ID/services/SERVICE_ID', - // '/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/' - // Note: On some cloud providers, it may not be possible to determine the - // full ID at startup, - // so it may be necessary to set `cloud.resource_id` as a span attribute - // instead. - // - // The exact value to use for `cloud.resource_id` depends on the cloud - // provider. - // The following well-known definitions MUST be used if you set this - // attribute and they apply: - // - // * **AWS Lambda:** The function - // [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). - // Take care not to use the "invoked ARN" directly but replace any - // [alias - // suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) - // with the resolved function version, as the same runtime instance may - // be invokable with - // multiple different aliases. - // * **GCP:** The [URI of the - // resource](https://cloud.google.com/iam/docs/full-resource-names) - // * **Azure:** The [Fully Qualified Resource - // ID](https://docs.microsoft.com/rest/api/resources/resources/get-by-id) - // of the invoked function, - // *not* the function app, having the form - // `/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/`. - // This means that a span attribute MUST be used, as an Azure function - // app can host multiple functions that would usually share - // a TracerProvider. - CloudResourceIDKey = attribute.Key("cloud.resource_id") -) - -var ( - // Alibaba Cloud Elastic Compute Service - CloudPlatformAlibabaCloudECS = CloudPlatformKey.String("alibaba_cloud_ecs") - // Alibaba Cloud Function Compute - CloudPlatformAlibabaCloudFc = CloudPlatformKey.String("alibaba_cloud_fc") - // Red Hat OpenShift on Alibaba Cloud - CloudPlatformAlibabaCloudOpenshift = CloudPlatformKey.String("alibaba_cloud_openshift") - // AWS Elastic Compute Cloud - CloudPlatformAWSEC2 = CloudPlatformKey.String("aws_ec2") - // AWS Elastic Container Service - CloudPlatformAWSECS = CloudPlatformKey.String("aws_ecs") - // AWS Elastic Kubernetes Service - CloudPlatformAWSEKS = CloudPlatformKey.String("aws_eks") - // AWS Lambda - CloudPlatformAWSLambda = CloudPlatformKey.String("aws_lambda") - // AWS Elastic Beanstalk - CloudPlatformAWSElasticBeanstalk = CloudPlatformKey.String("aws_elastic_beanstalk") - // AWS App Runner - CloudPlatformAWSAppRunner = CloudPlatformKey.String("aws_app_runner") - // Red Hat OpenShift on AWS (ROSA) - CloudPlatformAWSOpenshift = CloudPlatformKey.String("aws_openshift") - // Azure Virtual Machines - CloudPlatformAzureVM = CloudPlatformKey.String("azure_vm") - // Azure Container Apps - CloudPlatformAzureContainerApps = CloudPlatformKey.String("azure_container_apps") - // Azure Container Instances - CloudPlatformAzureContainerInstances = CloudPlatformKey.String("azure_container_instances") - // Azure Kubernetes Service - CloudPlatformAzureAKS = CloudPlatformKey.String("azure_aks") - // Azure Functions - CloudPlatformAzureFunctions = CloudPlatformKey.String("azure_functions") - // Azure App Service - CloudPlatformAzureAppService = CloudPlatformKey.String("azure_app_service") - // Azure Red Hat OpenShift - CloudPlatformAzureOpenshift = CloudPlatformKey.String("azure_openshift") - // Google Bare Metal Solution (BMS) - CloudPlatformGCPBareMetalSolution = CloudPlatformKey.String("gcp_bare_metal_solution") - // Google Cloud Compute Engine (GCE) - CloudPlatformGCPComputeEngine = CloudPlatformKey.String("gcp_compute_engine") - // Google Cloud Run - CloudPlatformGCPCloudRun = CloudPlatformKey.String("gcp_cloud_run") - // Google Cloud Kubernetes Engine (GKE) - CloudPlatformGCPKubernetesEngine = CloudPlatformKey.String("gcp_kubernetes_engine") - // Google Cloud Functions (GCF) - CloudPlatformGCPCloudFunctions = CloudPlatformKey.String("gcp_cloud_functions") - // Google Cloud App Engine (GAE) - CloudPlatformGCPAppEngine = CloudPlatformKey.String("gcp_app_engine") - // Red Hat OpenShift on Google Cloud - CloudPlatformGCPOpenshift = CloudPlatformKey.String("gcp_openshift") - // Red Hat OpenShift on IBM Cloud - CloudPlatformIbmCloudOpenshift = CloudPlatformKey.String("ibm_cloud_openshift") - // Tencent Cloud Cloud Virtual Machine (CVM) - CloudPlatformTencentCloudCvm = CloudPlatformKey.String("tencent_cloud_cvm") - // Tencent Cloud Elastic Kubernetes Service (EKS) - CloudPlatformTencentCloudEKS = CloudPlatformKey.String("tencent_cloud_eks") - // Tencent Cloud Serverless Cloud Function (SCF) - CloudPlatformTencentCloudScf = CloudPlatformKey.String("tencent_cloud_scf") -) - -var ( - // Alibaba Cloud - CloudProviderAlibabaCloud = CloudProviderKey.String("alibaba_cloud") - // Amazon Web Services - CloudProviderAWS = CloudProviderKey.String("aws") - // Microsoft Azure - CloudProviderAzure = CloudProviderKey.String("azure") - // Google Cloud Platform - CloudProviderGCP = CloudProviderKey.String("gcp") - // Heroku Platform as a Service - CloudProviderHeroku = CloudProviderKey.String("heroku") - // IBM Cloud - CloudProviderIbmCloud = CloudProviderKey.String("ibm_cloud") - // Tencent Cloud - CloudProviderTencentCloud = CloudProviderKey.String("tencent_cloud") -) - -// CloudAccountID returns an attribute KeyValue conforming to the -// "cloud.account.id" semantic conventions. It represents the cloud account ID -// the resource is assigned to. -func CloudAccountID(val string) attribute.KeyValue { - return CloudAccountIDKey.String(val) -} - -// CloudAvailabilityZone returns an attribute KeyValue conforming to the -// "cloud.availability_zone" semantic conventions. It represents the cloud -// regions often have multiple, isolated locations known as zones to increase -// availability. Availability zone represents the zone where the resource is -// running. -func CloudAvailabilityZone(val string) attribute.KeyValue { - return CloudAvailabilityZoneKey.String(val) -} - -// CloudRegion returns an attribute KeyValue conforming to the -// "cloud.region" semantic conventions. It represents the geographical region -// the resource is running. -func CloudRegion(val string) attribute.KeyValue { - return CloudRegionKey.String(val) -} - -// CloudResourceID returns an attribute KeyValue conforming to the -// "cloud.resource_id" semantic conventions. It represents the cloud -// provider-specific native identifier of the monitored cloud resource (e.g. an -// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) -// on AWS, a [fully qualified resource -// ID](https://learn.microsoft.com/rest/api/resources/resources/get-by-id) on -// Azure, a [full resource -// name](https://cloud.google.com/apis/design/resource_names#full_resource_name) -// on GCP) -func CloudResourceID(val string) attribute.KeyValue { - return CloudResourceIDKey.String(val) -} - -// Attributes for CloudEvents. -const ( - // CloudeventsEventIDKey is the attribute Key conforming to the - // "cloudevents.event_id" semantic conventions. It represents the - // [event_id](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#id) - // uniquely identifies the event. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '123e4567-e89b-12d3-a456-426614174000', '0001' - CloudeventsEventIDKey = attribute.Key("cloudevents.event_id") - - // CloudeventsEventSourceKey is the attribute Key conforming to the - // "cloudevents.event_source" semantic conventions. It represents the - // [source](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#source-1) - // identifies the context in which an event happened. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'https://github.com/cloudevents', - // '/cloudevents/spec/pull/123', 'my-service' - CloudeventsEventSourceKey = attribute.Key("cloudevents.event_source") - - // CloudeventsEventSpecVersionKey is the attribute Key conforming to the - // "cloudevents.event_spec_version" semantic conventions. It represents the - // [version of the CloudEvents - // specification](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#specversion) - // which the event uses. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1.0' - CloudeventsEventSpecVersionKey = attribute.Key("cloudevents.event_spec_version") - - // CloudeventsEventSubjectKey is the attribute Key conforming to the - // "cloudevents.event_subject" semantic conventions. It represents the - // [subject](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#subject) - // of the event in the context of the event producer (identified by - // source). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'mynewfile.jpg' - CloudeventsEventSubjectKey = attribute.Key("cloudevents.event_subject") - - // CloudeventsEventTypeKey is the attribute Key conforming to the - // "cloudevents.event_type" semantic conventions. It represents the - // [event_type](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#type) - // contains a value describing the type of event related to the originating - // occurrence. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'com.github.pull_request.opened', - // 'com.example.object.deleted.v2' - CloudeventsEventTypeKey = attribute.Key("cloudevents.event_type") -) - -// CloudeventsEventID returns an attribute KeyValue conforming to the -// "cloudevents.event_id" semantic conventions. It represents the -// [event_id](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#id) -// uniquely identifies the event. -func CloudeventsEventID(val string) attribute.KeyValue { - return CloudeventsEventIDKey.String(val) -} - -// CloudeventsEventSource returns an attribute KeyValue conforming to the -// "cloudevents.event_source" semantic conventions. It represents the -// [source](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#source-1) -// identifies the context in which an event happened. -func CloudeventsEventSource(val string) attribute.KeyValue { - return CloudeventsEventSourceKey.String(val) -} - -// CloudeventsEventSpecVersion returns an attribute KeyValue conforming to -// the "cloudevents.event_spec_version" semantic conventions. It represents the -// [version of the CloudEvents -// specification](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#specversion) -// which the event uses. -func CloudeventsEventSpecVersion(val string) attribute.KeyValue { - return CloudeventsEventSpecVersionKey.String(val) -} - -// CloudeventsEventSubject returns an attribute KeyValue conforming to the -// "cloudevents.event_subject" semantic conventions. It represents the -// [subject](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#subject) -// of the event in the context of the event producer (identified by source). -func CloudeventsEventSubject(val string) attribute.KeyValue { - return CloudeventsEventSubjectKey.String(val) -} - -// CloudeventsEventType returns an attribute KeyValue conforming to the -// "cloudevents.event_type" semantic conventions. It represents the -// [event_type](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#type) -// contains a value describing the type of event related to the originating -// occurrence. -func CloudeventsEventType(val string) attribute.KeyValue { - return CloudeventsEventTypeKey.String(val) -} - -// These attributes allow to report this unit of code and therefore to provide -// more context about the span. -const ( - // CodeColumnKey is the attribute Key conforming to the "code.column" - // semantic conventions. It represents the column number in `code.filepath` - // best representing the operation. It SHOULD point within the code unit - // named in `code.function`. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 16 - CodeColumnKey = attribute.Key("code.column") - - // CodeFilepathKey is the attribute Key conforming to the "code.filepath" - // semantic conventions. It represents the source code file name that - // identifies the code unit as uniquely as possible (preferably an absolute - // file path). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/usr/local/MyApplication/content_root/app/index.php' - CodeFilepathKey = attribute.Key("code.filepath") - - // CodeFunctionKey is the attribute Key conforming to the "code.function" - // semantic conventions. It represents the method or function name, or - // equivalent (usually rightmost part of the code unit's name). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'serveRequest' - CodeFunctionKey = attribute.Key("code.function") - - // CodeLineNumberKey is the attribute Key conforming to the "code.lineno" - // semantic conventions. It represents the line number in `code.filepath` - // best representing the operation. It SHOULD point within the code unit - // named in `code.function`. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 42 - CodeLineNumberKey = attribute.Key("code.lineno") - - // CodeNamespaceKey is the attribute Key conforming to the "code.namespace" - // semantic conventions. It represents the "namespace" within which - // `code.function` is defined. Usually the qualified class or module name, - // such that `code.namespace` + some separator + `code.function` form a - // unique identifier for the code unit. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'com.example.MyHTTPService' - CodeNamespaceKey = attribute.Key("code.namespace") - - // CodeStacktraceKey is the attribute Key conforming to the - // "code.stacktrace" semantic conventions. It represents a stacktrace as a - // string in the natural representation for the language runtime. The - // representation is to be determined and documented by each language SIG. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'at - // com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at ' - // 'com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at ' - // 'com.example.GenerateTrace.main(GenerateTrace.java:5)' - CodeStacktraceKey = attribute.Key("code.stacktrace") -) - -// CodeColumn returns an attribute KeyValue conforming to the "code.column" -// semantic conventions. It represents the column number in `code.filepath` -// best representing the operation. It SHOULD point within the code unit named -// in `code.function`. -func CodeColumn(val int) attribute.KeyValue { - return CodeColumnKey.Int(val) -} - -// CodeFilepath returns an attribute KeyValue conforming to the -// "code.filepath" semantic conventions. It represents the source code file -// name that identifies the code unit as uniquely as possible (preferably an -// absolute file path). -func CodeFilepath(val string) attribute.KeyValue { - return CodeFilepathKey.String(val) -} - -// CodeFunction returns an attribute KeyValue conforming to the -// "code.function" semantic conventions. It represents the method or function -// name, or equivalent (usually rightmost part of the code unit's name). -func CodeFunction(val string) attribute.KeyValue { - return CodeFunctionKey.String(val) -} - -// CodeLineNumber returns an attribute KeyValue conforming to the "code.lineno" -// semantic conventions. It represents the line number in `code.filepath` best -// representing the operation. It SHOULD point within the code unit named in -// `code.function`. -func CodeLineNumber(val int) attribute.KeyValue { - return CodeLineNumberKey.Int(val) -} - -// CodeNamespace returns an attribute KeyValue conforming to the -// "code.namespace" semantic conventions. It represents the "namespace" within -// which `code.function` is defined. Usually the qualified class or module -// name, such that `code.namespace` + some separator + `code.function` form a -// unique identifier for the code unit. -func CodeNamespace(val string) attribute.KeyValue { - return CodeNamespaceKey.String(val) -} - -// CodeStacktrace returns an attribute KeyValue conforming to the -// "code.stacktrace" semantic conventions. It represents a stacktrace as a -// string in the natural representation for the language runtime. The -// representation is to be determined and documented by each language SIG. -func CodeStacktrace(val string) attribute.KeyValue { - return CodeStacktraceKey.String(val) -} - -// A container instance. -const ( - // ContainerCommandKey is the attribute Key conforming to the - // "container.command" semantic conventions. It represents the command used - // to run the container (i.e. the command name). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'otelcontribcol' - // Note: If using embedded credentials or sensitive data, it is recommended - // to remove them to prevent potential leakage. - ContainerCommandKey = attribute.Key("container.command") - - // ContainerCommandArgsKey is the attribute Key conforming to the - // "container.command_args" semantic conventions. It represents the all the - // command arguments (including the command/executable itself) run by the - // container. [2] - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'otelcontribcol, --config, config.yaml' - ContainerCommandArgsKey = attribute.Key("container.command_args") - - // ContainerCommandLineKey is the attribute Key conforming to the - // "container.command_line" semantic conventions. It represents the full - // command run by the container as a single string representing the full - // command. [2] - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'otelcontribcol --config config.yaml' - ContainerCommandLineKey = attribute.Key("container.command_line") - - // ContainerCPUStateKey is the attribute Key conforming to the - // "container.cpu.state" semantic conventions. It represents the CPU state - // for this data point. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'user', 'kernel' - ContainerCPUStateKey = attribute.Key("container.cpu.state") - - // ContainerIDKey is the attribute Key conforming to the "container.id" - // semantic conventions. It represents the container ID. Usually a UUID, as - // for example used to [identify Docker - // containers](https://docs.docker.com/engine/reference/run/#container-identification). - // The UUID might be abbreviated. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'a3bf90e006b2' - ContainerIDKey = attribute.Key("container.id") - - // ContainerImageIDKey is the attribute Key conforming to the - // "container.image.id" semantic conventions. It represents the runtime - // specific image identifier. Usually a hash algorithm followed by a UUID. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'sha256:19c92d0a00d1b66d897bceaa7319bee0dd38a10a851c60bcec9474aa3f01e50f' - // Note: Docker defines a sha256 of the image id; `container.image.id` - // corresponds to the `Image` field from the Docker container inspect - // [API](https://docs.docker.com/engine/api/v1.43/#tag/Container/operation/ContainerInspect) - // endpoint. - // K8S defines a link to the container registry repository with digest - // `"imageID": "registry.azurecr.io - // /namespace/service/dockerfile@sha256:bdeabd40c3a8a492eaf9e8e44d0ebbb84bac7ee25ac0cf8a7159d25f62555625"`. - // The ID is assigned by the container runtime and can vary in different - // environments. Consider using `oci.manifest.digest` if it is important to - // identify the same image in different environments/runtimes. - ContainerImageIDKey = attribute.Key("container.image.id") - - // ContainerImageNameKey is the attribute Key conforming to the - // "container.image.name" semantic conventions. It represents the name of - // the image the container was built on. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'gcr.io/opentelemetry/operator' - ContainerImageNameKey = attribute.Key("container.image.name") - - // ContainerImageRepoDigestsKey is the attribute Key conforming to the - // "container.image.repo_digests" semantic conventions. It represents the - // repo digests of the container image as provided by the container - // runtime. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'example@sha256:afcc7f1ac1b49db317a7196c902e61c6c3c4607d63599ee1a82d702d249a0ccb', - // 'internal.registry.example.com:5000/example@sha256:b69959407d21e8a062e0416bf13405bb2b71ed7a84dde4158ebafacfa06f5578' - // Note: - // [Docker](https://docs.docker.com/engine/api/v1.43/#tag/Image/operation/ImageInspect) - // and - // [CRI](https://github.com/kubernetes/cri-api/blob/c75ef5b473bbe2d0a4fc92f82235efd665ea8e9f/pkg/apis/runtime/v1/api.proto#L1237-L1238) - // report those under the `RepoDigests` field. - ContainerImageRepoDigestsKey = attribute.Key("container.image.repo_digests") - - // ContainerImageTagsKey is the attribute Key conforming to the - // "container.image.tags" semantic conventions. It represents the container - // image tags. An example can be found in [Docker Image - // Inspect](https://docs.docker.com/engine/api/v1.43/#tag/Image/operation/ImageInspect). - // Should be only the `` section of the full name for example from - // `registry.example.com/my-org/my-image:`. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'v1.27.1', '3.5.7-0' - ContainerImageTagsKey = attribute.Key("container.image.tags") - - // ContainerNameKey is the attribute Key conforming to the "container.name" - // semantic conventions. It represents the container name used by container - // runtime. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry-autoconf' - ContainerNameKey = attribute.Key("container.name") - - // ContainerRuntimeKey is the attribute Key conforming to the - // "container.runtime" semantic conventions. It represents the container - // runtime managing this container. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'docker', 'containerd', 'rkt' - ContainerRuntimeKey = attribute.Key("container.runtime") -) - -var ( - // When tasks of the cgroup are in user mode (Linux). When all container processes are in user mode (Windows) - ContainerCPUStateUser = ContainerCPUStateKey.String("user") - // When CPU is used by the system (host OS) - ContainerCPUStateSystem = ContainerCPUStateKey.String("system") - // When tasks of the cgroup are in kernel mode (Linux). When all container processes are in kernel mode (Windows) - ContainerCPUStateKernel = ContainerCPUStateKey.String("kernel") -) - -// ContainerCommand returns an attribute KeyValue conforming to the -// "container.command" semantic conventions. It represents the command used to -// run the container (i.e. the command name). -func ContainerCommand(val string) attribute.KeyValue { - return ContainerCommandKey.String(val) -} - -// ContainerCommandArgs returns an attribute KeyValue conforming to the -// "container.command_args" semantic conventions. It represents the all the -// command arguments (including the command/executable itself) run by the -// container. [2] -func ContainerCommandArgs(val ...string) attribute.KeyValue { - return ContainerCommandArgsKey.StringSlice(val) -} - -// ContainerCommandLine returns an attribute KeyValue conforming to the -// "container.command_line" semantic conventions. It represents the full -// command run by the container as a single string representing the full -// command. [2] -func ContainerCommandLine(val string) attribute.KeyValue { - return ContainerCommandLineKey.String(val) -} - -// ContainerID returns an attribute KeyValue conforming to the -// "container.id" semantic conventions. It represents the container ID. Usually -// a UUID, as for example used to [identify Docker -// containers](https://docs.docker.com/engine/reference/run/#container-identification). -// The UUID might be abbreviated. -func ContainerID(val string) attribute.KeyValue { - return ContainerIDKey.String(val) -} - -// ContainerImageID returns an attribute KeyValue conforming to the -// "container.image.id" semantic conventions. It represents the runtime -// specific image identifier. Usually a hash algorithm followed by a UUID. -func ContainerImageID(val string) attribute.KeyValue { - return ContainerImageIDKey.String(val) -} - -// ContainerImageName returns an attribute KeyValue conforming to the -// "container.image.name" semantic conventions. It represents the name of the -// image the container was built on. -func ContainerImageName(val string) attribute.KeyValue { - return ContainerImageNameKey.String(val) -} - -// ContainerImageRepoDigests returns an attribute KeyValue conforming to the -// "container.image.repo_digests" semantic conventions. It represents the repo -// digests of the container image as provided by the container runtime. -func ContainerImageRepoDigests(val ...string) attribute.KeyValue { - return ContainerImageRepoDigestsKey.StringSlice(val) -} - -// ContainerImageTags returns an attribute KeyValue conforming to the -// "container.image.tags" semantic conventions. It represents the container -// image tags. An example can be found in [Docker Image -// Inspect](https://docs.docker.com/engine/api/v1.43/#tag/Image/operation/ImageInspect). -// Should be only the `` section of the full name for example from -// `registry.example.com/my-org/my-image:`. -func ContainerImageTags(val ...string) attribute.KeyValue { - return ContainerImageTagsKey.StringSlice(val) -} - -// ContainerName returns an attribute KeyValue conforming to the -// "container.name" semantic conventions. It represents the container name used -// by container runtime. -func ContainerName(val string) attribute.KeyValue { - return ContainerNameKey.String(val) -} - -// ContainerRuntime returns an attribute KeyValue conforming to the -// "container.runtime" semantic conventions. It represents the container -// runtime managing this container. -func ContainerRuntime(val string) attribute.KeyValue { - return ContainerRuntimeKey.String(val) -} - -// This group defines the attributes used to describe telemetry in the context -// of databases. -const ( - // DBClientConnectionsPoolNameKey is the attribute Key conforming to the - // "db.client.connections.pool.name" semantic conventions. It represents - // the name of the connection pool; unique within the instrumented - // application. In case the connection pool implementation doesn't provide - // a name, instrumentation should use a combination of `server.address` and - // `server.port` attributes formatted as `server.address:server.port`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myDataSource' - DBClientConnectionsPoolNameKey = attribute.Key("db.client.connections.pool.name") - - // DBClientConnectionsStateKey is the attribute Key conforming to the - // "db.client.connections.state" semantic conventions. It represents the - // state of a connection in the pool - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'idle' - DBClientConnectionsStateKey = attribute.Key("db.client.connections.state") - - // DBCollectionNameKey is the attribute Key conforming to the - // "db.collection.name" semantic conventions. It represents the name of a - // collection (table, container) within the database. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'public.users', 'customers' - // Note: If the collection name is parsed from the query, it SHOULD match - // the value provided in the query and may be qualified with the schema and - // database name. - // It is RECOMMENDED to capture the value as provided by the application - // without attempting to do any case normalization. - DBCollectionNameKey = attribute.Key("db.collection.name") - - // DBNamespaceKey is the attribute Key conforming to the "db.namespace" - // semantic conventions. It represents the name of the database, fully - // qualified within the server address and port. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'customers', 'test.users' - // Note: If a database system has multiple namespace components, they - // SHOULD be concatenated (potentially using database system specific - // conventions) from most general to most specific namespace component, and - // more specific namespaces SHOULD NOT be captured without the more general - // namespaces, to ensure that "startswith" queries for the more general - // namespaces will be valid. - // Semantic conventions for individual database systems SHOULD document - // what `db.namespace` means in the context of that system. - // It is RECOMMENDED to capture the value as provided by the application - // without attempting to do any case normalization. - DBNamespaceKey = attribute.Key("db.namespace") - - // DBOperationNameKey is the attribute Key conforming to the - // "db.operation.name" semantic conventions. It represents the name of the - // operation or command being executed. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'findAndModify', 'HMSET', 'SELECT' - // Note: It is RECOMMENDED to capture the value as provided by the - // application without attempting to do any case normalization. - DBOperationNameKey = attribute.Key("db.operation.name") - - // DBQueryTextKey is the attribute Key conforming to the "db.query.text" - // semantic conventions. It represents the database query being executed. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'SELECT * FROM wuser_table where username = ?', 'SET mykey - // "WuValue"' - DBQueryTextKey = attribute.Key("db.query.text") - - // DBSystemKey is the attribute Key conforming to the "db.system" semantic - // conventions. It represents the database management system (DBMS) product - // as identified by the client instrumentation. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: The actual DBMS may differ from the one identified by the client. - // For example, when using PostgreSQL client libraries to connect to a - // CockroachDB, the `db.system` is set to `postgresql` based on the - // instrumentation's best knowledge. - DBSystemKey = attribute.Key("db.system") -) - -var ( - // idle - DBClientConnectionsStateIdle = DBClientConnectionsStateKey.String("idle") - // used - DBClientConnectionsStateUsed = DBClientConnectionsStateKey.String("used") -) - -var ( - // Some other SQL database. Fallback only. See notes - DBSystemOtherSQL = DBSystemKey.String("other_sql") - // Microsoft SQL Server - DBSystemMSSQL = DBSystemKey.String("mssql") - // Microsoft SQL Server Compact - DBSystemMssqlcompact = DBSystemKey.String("mssqlcompact") - // MySQL - DBSystemMySQL = DBSystemKey.String("mysql") - // Oracle Database - DBSystemOracle = DBSystemKey.String("oracle") - // IBM DB2 - DBSystemDB2 = DBSystemKey.String("db2") - // PostgreSQL - DBSystemPostgreSQL = DBSystemKey.String("postgresql") - // Amazon Redshift - DBSystemRedshift = DBSystemKey.String("redshift") - // Apache Hive - DBSystemHive = DBSystemKey.String("hive") - // Cloudscape - DBSystemCloudscape = DBSystemKey.String("cloudscape") - // HyperSQL DataBase - DBSystemHSQLDB = DBSystemKey.String("hsqldb") - // Progress Database - DBSystemProgress = DBSystemKey.String("progress") - // SAP MaxDB - DBSystemMaxDB = DBSystemKey.String("maxdb") - // SAP HANA - DBSystemHanaDB = DBSystemKey.String("hanadb") - // Ingres - DBSystemIngres = DBSystemKey.String("ingres") - // FirstSQL - DBSystemFirstSQL = DBSystemKey.String("firstsql") - // EnterpriseDB - DBSystemEDB = DBSystemKey.String("edb") - // InterSystems Caché - DBSystemCache = DBSystemKey.String("cache") - // Adabas (Adaptable Database System) - DBSystemAdabas = DBSystemKey.String("adabas") - // Firebird - DBSystemFirebird = DBSystemKey.String("firebird") - // Apache Derby - DBSystemDerby = DBSystemKey.String("derby") - // FileMaker - DBSystemFilemaker = DBSystemKey.String("filemaker") - // Informix - DBSystemInformix = DBSystemKey.String("informix") - // InstantDB - DBSystemInstantDB = DBSystemKey.String("instantdb") - // InterBase - DBSystemInterbase = DBSystemKey.String("interbase") - // MariaDB - DBSystemMariaDB = DBSystemKey.String("mariadb") - // Netezza - DBSystemNetezza = DBSystemKey.String("netezza") - // Pervasive PSQL - DBSystemPervasive = DBSystemKey.String("pervasive") - // PointBase - DBSystemPointbase = DBSystemKey.String("pointbase") - // SQLite - DBSystemSqlite = DBSystemKey.String("sqlite") - // Sybase - DBSystemSybase = DBSystemKey.String("sybase") - // Teradata - DBSystemTeradata = DBSystemKey.String("teradata") - // Vertica - DBSystemVertica = DBSystemKey.String("vertica") - // H2 - DBSystemH2 = DBSystemKey.String("h2") - // ColdFusion IMQ - DBSystemColdfusion = DBSystemKey.String("coldfusion") - // Apache Cassandra - DBSystemCassandra = DBSystemKey.String("cassandra") - // Apache HBase - DBSystemHBase = DBSystemKey.String("hbase") - // MongoDB - DBSystemMongoDB = DBSystemKey.String("mongodb") - // Redis - DBSystemRedis = DBSystemKey.String("redis") - // Couchbase - DBSystemCouchbase = DBSystemKey.String("couchbase") - // CouchDB - DBSystemCouchDB = DBSystemKey.String("couchdb") - // Microsoft Azure Cosmos DB - DBSystemCosmosDB = DBSystemKey.String("cosmosdb") - // Amazon DynamoDB - DBSystemDynamoDB = DBSystemKey.String("dynamodb") - // Neo4j - DBSystemNeo4j = DBSystemKey.String("neo4j") - // Apache Geode - DBSystemGeode = DBSystemKey.String("geode") - // Elasticsearch - DBSystemElasticsearch = DBSystemKey.String("elasticsearch") - // Memcached - DBSystemMemcached = DBSystemKey.String("memcached") - // CockroachDB - DBSystemCockroachdb = DBSystemKey.String("cockroachdb") - // OpenSearch - DBSystemOpensearch = DBSystemKey.String("opensearch") - // ClickHouse - DBSystemClickhouse = DBSystemKey.String("clickhouse") - // Cloud Spanner - DBSystemSpanner = DBSystemKey.String("spanner") - // Trino - DBSystemTrino = DBSystemKey.String("trino") -) - -// DBClientConnectionsPoolName returns an attribute KeyValue conforming to -// the "db.client.connections.pool.name" semantic conventions. It represents -// the name of the connection pool; unique within the instrumented application. -// In case the connection pool implementation doesn't provide a name, -// instrumentation should use a combination of `server.address` and -// `server.port` attributes formatted as `server.address:server.port`. -func DBClientConnectionsPoolName(val string) attribute.KeyValue { - return DBClientConnectionsPoolNameKey.String(val) -} - -// DBCollectionName returns an attribute KeyValue conforming to the -// "db.collection.name" semantic conventions. It represents the name of a -// collection (table, container) within the database. -func DBCollectionName(val string) attribute.KeyValue { - return DBCollectionNameKey.String(val) -} - -// DBNamespace returns an attribute KeyValue conforming to the -// "db.namespace" semantic conventions. It represents the name of the database, -// fully qualified within the server address and port. -func DBNamespace(val string) attribute.KeyValue { - return DBNamespaceKey.String(val) -} - -// DBOperationName returns an attribute KeyValue conforming to the -// "db.operation.name" semantic conventions. It represents the name of the -// operation or command being executed. -func DBOperationName(val string) attribute.KeyValue { - return DBOperationNameKey.String(val) -} - -// DBQueryText returns an attribute KeyValue conforming to the -// "db.query.text" semantic conventions. It represents the database query being -// executed. -func DBQueryText(val string) attribute.KeyValue { - return DBQueryTextKey.String(val) -} - -// This group defines attributes for Cassandra. -const ( - // DBCassandraConsistencyLevelKey is the attribute Key conforming to the - // "db.cassandra.consistency_level" semantic conventions. It represents the - // consistency level of the query. Based on consistency values from - // [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html). - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - DBCassandraConsistencyLevelKey = attribute.Key("db.cassandra.consistency_level") - - // DBCassandraCoordinatorDCKey is the attribute Key conforming to the - // "db.cassandra.coordinator.dc" semantic conventions. It represents the - // data center of the coordinating node for a query. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'us-west-2' - DBCassandraCoordinatorDCKey = attribute.Key("db.cassandra.coordinator.dc") - - // DBCassandraCoordinatorIDKey is the attribute Key conforming to the - // "db.cassandra.coordinator.id" semantic conventions. It represents the ID - // of the coordinating node for a query. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'be13faa2-8574-4d71-926d-27f16cf8a7af' - DBCassandraCoordinatorIDKey = attribute.Key("db.cassandra.coordinator.id") - - // DBCassandraIdempotenceKey is the attribute Key conforming to the - // "db.cassandra.idempotence" semantic conventions. It represents the - // whether or not the query is idempotent. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - DBCassandraIdempotenceKey = attribute.Key("db.cassandra.idempotence") - - // DBCassandraPageSizeKey is the attribute Key conforming to the - // "db.cassandra.page_size" semantic conventions. It represents the fetch - // size used for paging, i.e. how many rows will be returned at once. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 5000 - DBCassandraPageSizeKey = attribute.Key("db.cassandra.page_size") - - // DBCassandraSpeculativeExecutionCountKey is the attribute Key conforming - // to the "db.cassandra.speculative_execution_count" semantic conventions. - // It represents the number of times a query was speculatively executed. - // Not set or `0` if the query was not executed speculatively. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 0, 2 - DBCassandraSpeculativeExecutionCountKey = attribute.Key("db.cassandra.speculative_execution_count") -) - -var ( - // all - DBCassandraConsistencyLevelAll = DBCassandraConsistencyLevelKey.String("all") - // each_quorum - DBCassandraConsistencyLevelEachQuorum = DBCassandraConsistencyLevelKey.String("each_quorum") - // quorum - DBCassandraConsistencyLevelQuorum = DBCassandraConsistencyLevelKey.String("quorum") - // local_quorum - DBCassandraConsistencyLevelLocalQuorum = DBCassandraConsistencyLevelKey.String("local_quorum") - // one - DBCassandraConsistencyLevelOne = DBCassandraConsistencyLevelKey.String("one") - // two - DBCassandraConsistencyLevelTwo = DBCassandraConsistencyLevelKey.String("two") - // three - DBCassandraConsistencyLevelThree = DBCassandraConsistencyLevelKey.String("three") - // local_one - DBCassandraConsistencyLevelLocalOne = DBCassandraConsistencyLevelKey.String("local_one") - // any - DBCassandraConsistencyLevelAny = DBCassandraConsistencyLevelKey.String("any") - // serial - DBCassandraConsistencyLevelSerial = DBCassandraConsistencyLevelKey.String("serial") - // local_serial - DBCassandraConsistencyLevelLocalSerial = DBCassandraConsistencyLevelKey.String("local_serial") -) - -// DBCassandraCoordinatorDC returns an attribute KeyValue conforming to the -// "db.cassandra.coordinator.dc" semantic conventions. It represents the data -// center of the coordinating node for a query. -func DBCassandraCoordinatorDC(val string) attribute.KeyValue { - return DBCassandraCoordinatorDCKey.String(val) -} - -// DBCassandraCoordinatorID returns an attribute KeyValue conforming to the -// "db.cassandra.coordinator.id" semantic conventions. It represents the ID of -// the coordinating node for a query. -func DBCassandraCoordinatorID(val string) attribute.KeyValue { - return DBCassandraCoordinatorIDKey.String(val) -} - -// DBCassandraIdempotence returns an attribute KeyValue conforming to the -// "db.cassandra.idempotence" semantic conventions. It represents the whether -// or not the query is idempotent. -func DBCassandraIdempotence(val bool) attribute.KeyValue { - return DBCassandraIdempotenceKey.Bool(val) -} - -// DBCassandraPageSize returns an attribute KeyValue conforming to the -// "db.cassandra.page_size" semantic conventions. It represents the fetch size -// used for paging, i.e. how many rows will be returned at once. -func DBCassandraPageSize(val int) attribute.KeyValue { - return DBCassandraPageSizeKey.Int(val) -} - -// DBCassandraSpeculativeExecutionCount returns an attribute KeyValue -// conforming to the "db.cassandra.speculative_execution_count" semantic -// conventions. It represents the number of times a query was speculatively -// executed. Not set or `0` if the query was not executed speculatively. -func DBCassandraSpeculativeExecutionCount(val int) attribute.KeyValue { - return DBCassandraSpeculativeExecutionCountKey.Int(val) -} - -// This group defines attributes for Azure Cosmos DB. -const ( - // DBCosmosDBClientIDKey is the attribute Key conforming to the - // "db.cosmosdb.client_id" semantic conventions. It represents the unique - // Cosmos client instance id. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '3ba4827d-4422-483f-b59f-85b74211c11d' - DBCosmosDBClientIDKey = attribute.Key("db.cosmosdb.client_id") - - // DBCosmosDBConnectionModeKey is the attribute Key conforming to the - // "db.cosmosdb.connection_mode" semantic conventions. It represents the - // cosmos client connection mode. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - DBCosmosDBConnectionModeKey = attribute.Key("db.cosmosdb.connection_mode") - - // DBCosmosDBOperationTypeKey is the attribute Key conforming to the - // "db.cosmosdb.operation_type" semantic conventions. It represents the - // cosmosDB Operation Type. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - DBCosmosDBOperationTypeKey = attribute.Key("db.cosmosdb.operation_type") - - // DBCosmosDBRequestChargeKey is the attribute Key conforming to the - // "db.cosmosdb.request_charge" semantic conventions. It represents the rU - // consumed for that operation - // - // Type: double - // RequirementLevel: Optional - // Stability: experimental - // Examples: 46.18, 1.0 - DBCosmosDBRequestChargeKey = attribute.Key("db.cosmosdb.request_charge") - - // DBCosmosDBRequestContentLengthKey is the attribute Key conforming to the - // "db.cosmosdb.request_content_length" semantic conventions. It represents - // the request payload size in bytes - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - DBCosmosDBRequestContentLengthKey = attribute.Key("db.cosmosdb.request_content_length") - - // DBCosmosDBStatusCodeKey is the attribute Key conforming to the - // "db.cosmosdb.status_code" semantic conventions. It represents the cosmos - // DB status code. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 200, 201 - DBCosmosDBStatusCodeKey = attribute.Key("db.cosmosdb.status_code") - - // DBCosmosDBSubStatusCodeKey is the attribute Key conforming to the - // "db.cosmosdb.sub_status_code" semantic conventions. It represents the - // cosmos DB sub status code. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1000, 1002 - DBCosmosDBSubStatusCodeKey = attribute.Key("db.cosmosdb.sub_status_code") -) - -var ( - // Gateway (HTTP) connections mode - DBCosmosDBConnectionModeGateway = DBCosmosDBConnectionModeKey.String("gateway") - // Direct connection - DBCosmosDBConnectionModeDirect = DBCosmosDBConnectionModeKey.String("direct") -) - -var ( - // invalid - DBCosmosDBOperationTypeInvalid = DBCosmosDBOperationTypeKey.String("Invalid") - // create - DBCosmosDBOperationTypeCreate = DBCosmosDBOperationTypeKey.String("Create") - // patch - DBCosmosDBOperationTypePatch = DBCosmosDBOperationTypeKey.String("Patch") - // read - DBCosmosDBOperationTypeRead = DBCosmosDBOperationTypeKey.String("Read") - // read_feed - DBCosmosDBOperationTypeReadFeed = DBCosmosDBOperationTypeKey.String("ReadFeed") - // delete - DBCosmosDBOperationTypeDelete = DBCosmosDBOperationTypeKey.String("Delete") - // replace - DBCosmosDBOperationTypeReplace = DBCosmosDBOperationTypeKey.String("Replace") - // execute - DBCosmosDBOperationTypeExecute = DBCosmosDBOperationTypeKey.String("Execute") - // query - DBCosmosDBOperationTypeQuery = DBCosmosDBOperationTypeKey.String("Query") - // head - DBCosmosDBOperationTypeHead = DBCosmosDBOperationTypeKey.String("Head") - // head_feed - DBCosmosDBOperationTypeHeadFeed = DBCosmosDBOperationTypeKey.String("HeadFeed") - // upsert - DBCosmosDBOperationTypeUpsert = DBCosmosDBOperationTypeKey.String("Upsert") - // batch - DBCosmosDBOperationTypeBatch = DBCosmosDBOperationTypeKey.String("Batch") - // query_plan - DBCosmosDBOperationTypeQueryPlan = DBCosmosDBOperationTypeKey.String("QueryPlan") - // execute_javascript - DBCosmosDBOperationTypeExecuteJavascript = DBCosmosDBOperationTypeKey.String("ExecuteJavaScript") -) - -// DBCosmosDBClientID returns an attribute KeyValue conforming to the -// "db.cosmosdb.client_id" semantic conventions. It represents the unique -// Cosmos client instance id. -func DBCosmosDBClientID(val string) attribute.KeyValue { - return DBCosmosDBClientIDKey.String(val) -} - -// DBCosmosDBRequestCharge returns an attribute KeyValue conforming to the -// "db.cosmosdb.request_charge" semantic conventions. It represents the rU -// consumed for that operation -func DBCosmosDBRequestCharge(val float64) attribute.KeyValue { - return DBCosmosDBRequestChargeKey.Float64(val) -} - -// DBCosmosDBRequestContentLength returns an attribute KeyValue conforming -// to the "db.cosmosdb.request_content_length" semantic conventions. It -// represents the request payload size in bytes -func DBCosmosDBRequestContentLength(val int) attribute.KeyValue { - return DBCosmosDBRequestContentLengthKey.Int(val) -} - -// DBCosmosDBStatusCode returns an attribute KeyValue conforming to the -// "db.cosmosdb.status_code" semantic conventions. It represents the cosmos DB -// status code. -func DBCosmosDBStatusCode(val int) attribute.KeyValue { - return DBCosmosDBStatusCodeKey.Int(val) -} - -// DBCosmosDBSubStatusCode returns an attribute KeyValue conforming to the -// "db.cosmosdb.sub_status_code" semantic conventions. It represents the cosmos -// DB sub status code. -func DBCosmosDBSubStatusCode(val int) attribute.KeyValue { - return DBCosmosDBSubStatusCodeKey.Int(val) -} - -// This group defines attributes for Elasticsearch. -const ( - // DBElasticsearchClusterNameKey is the attribute Key conforming to the - // "db.elasticsearch.cluster.name" semantic conventions. It represents the - // represents the identifier of an Elasticsearch cluster. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'e9106fc68e3044f0b1475b04bf4ffd5f' - DBElasticsearchClusterNameKey = attribute.Key("db.elasticsearch.cluster.name") - - // DBElasticsearchNodeNameKey is the attribute Key conforming to the - // "db.elasticsearch.node.name" semantic conventions. It represents the - // represents the human-readable identifier of the node/instance to which a - // request was routed. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'instance-0000000001' - DBElasticsearchNodeNameKey = attribute.Key("db.elasticsearch.node.name") -) - -// DBElasticsearchClusterName returns an attribute KeyValue conforming to -// the "db.elasticsearch.cluster.name" semantic conventions. It represents the -// represents the identifier of an Elasticsearch cluster. -func DBElasticsearchClusterName(val string) attribute.KeyValue { - return DBElasticsearchClusterNameKey.String(val) -} - -// DBElasticsearchNodeName returns an attribute KeyValue conforming to the -// "db.elasticsearch.node.name" semantic conventions. It represents the -// represents the human-readable identifier of the node/instance to which a -// request was routed. -func DBElasticsearchNodeName(val string) attribute.KeyValue { - return DBElasticsearchNodeNameKey.String(val) -} - -// Attributes for software deployments. -const ( - // DeploymentEnvironmentKey is the attribute Key conforming to the - // "deployment.environment" semantic conventions. It represents the name of - // the [deployment - // environment](https://wikipedia.org/wiki/Deployment_environment) (aka - // deployment tier). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'staging', 'production' - // Note: `deployment.environment` does not affect the uniqueness - // constraints defined through - // the `service.namespace`, `service.name` and `service.instance.id` - // resource attributes. - // This implies that resources carrying the following attribute - // combinations MUST be - // considered to be identifying the same service: - // - // * `service.name=frontend`, `deployment.environment=production` - // * `service.name=frontend`, `deployment.environment=staging`. - DeploymentEnvironmentKey = attribute.Key("deployment.environment") -) - -// DeploymentEnvironment returns an attribute KeyValue conforming to the -// "deployment.environment" semantic conventions. It represents the name of the -// [deployment environment](https://wikipedia.org/wiki/Deployment_environment) -// (aka deployment tier). -func DeploymentEnvironment(val string) attribute.KeyValue { - return DeploymentEnvironmentKey.String(val) -} - -// Attributes that represents an occurrence of a lifecycle transition on the -// Android platform. -const ( - // AndroidStateKey is the attribute Key conforming to the "android.state" - // semantic conventions. It represents the deprecated use the - // `device.app.lifecycle` event definition including `android.state` as a - // payload field instead. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: The Android lifecycle states are defined in [Activity lifecycle - // callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), - // and from which the `OS identifiers` are derived. - AndroidStateKey = attribute.Key("android.state") -) - -var ( - // Any time before Activity.onResume() or, if the app has no Activity, Context.startService() has been called in the app for the first time - AndroidStateCreated = AndroidStateKey.String("created") - // Any time after Activity.onPause() or, if the app has no Activity, Context.stopService() has been called when the app was in the foreground state - AndroidStateBackground = AndroidStateKey.String("background") - // Any time after Activity.onResume() or, if the app has no Activity, Context.startService() has been called when the app was in either the created or background states - AndroidStateForeground = AndroidStateKey.String("foreground") -) - -// These attributes may be used to describe the receiver of a network -// exchange/packet. These should be used when there is no client/server -// relationship between the two sides, or when that relationship is unknown. -// This covers low-level network interactions (e.g. packet tracing) where you -// don't know if there was a connection or which side initiated it. This also -// covers unidirectional UDP flows and peer-to-peer communication where the -// "user-facing" surface of the protocol / API doesn't expose a clear notion of -// client and server. -const ( - // DestinationAddressKey is the attribute Key conforming to the - // "destination.address" semantic conventions. It represents the - // destination address - domain name if available without reverse DNS - // lookup; otherwise, IP address or Unix domain socket name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'destination.example.com', '10.1.2.80', '/tmp/my.sock' - // Note: When observed from the source side, and when communicating through - // an intermediary, `destination.address` SHOULD represent the destination - // address behind any intermediaries, for example proxies, if it's - // available. - DestinationAddressKey = attribute.Key("destination.address") - - // DestinationPortKey is the attribute Key conforming to the - // "destination.port" semantic conventions. It represents the destination - // port number - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 3389, 2888 - DestinationPortKey = attribute.Key("destination.port") -) - -// DestinationAddress returns an attribute KeyValue conforming to the -// "destination.address" semantic conventions. It represents the destination -// address - domain name if available without reverse DNS lookup; otherwise, IP -// address or Unix domain socket name. -func DestinationAddress(val string) attribute.KeyValue { - return DestinationAddressKey.String(val) -} - -// DestinationPort returns an attribute KeyValue conforming to the -// "destination.port" semantic conventions. It represents the destination port -// number -func DestinationPort(val int) attribute.KeyValue { - return DestinationPortKey.Int(val) -} - -// Describes device attributes. -const ( - // DeviceIDKey is the attribute Key conforming to the "device.id" semantic - // conventions. It represents a unique identifier representing the device - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2ab2916d-a51f-4ac8-80ee-45ac31a28092' - // Note: The device identifier MUST only be defined using the values - // outlined below. This value is not an advertising identifier and MUST NOT - // be used as such. On iOS (Swift or Objective-C), this value MUST be equal - // to the [vendor - // identifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor). - // On Android (Java or Kotlin), this value MUST be equal to the Firebase - // Installation ID or a globally unique UUID which is persisted across - // sessions in your application. More information can be found - // [here](https://developer.android.com/training/articles/user-data-ids) on - // best practices and exact implementation details. Caution should be taken - // when storing personal data or anything which can identify a user. GDPR - // and data protection laws may apply, ensure you do your own due - // diligence. - DeviceIDKey = attribute.Key("device.id") - - // DeviceManufacturerKey is the attribute Key conforming to the - // "device.manufacturer" semantic conventions. It represents the name of - // the device manufacturer - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Apple', 'Samsung' - // Note: The Android OS provides this field via - // [Build](https://developer.android.com/reference/android/os/Build#MANUFACTURER). - // iOS apps SHOULD hardcode the value `Apple`. - DeviceManufacturerKey = attribute.Key("device.manufacturer") - - // DeviceModelIdentifierKey is the attribute Key conforming to the - // "device.model.identifier" semantic conventions. It represents the model - // identifier for the device - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'iPhone3,4', 'SM-G920F' - // Note: It's recommended this value represents a machine-readable version - // of the model identifier rather than the market or consumer-friendly name - // of the device. - DeviceModelIdentifierKey = attribute.Key("device.model.identifier") - - // DeviceModelNameKey is the attribute Key conforming to the - // "device.model.name" semantic conventions. It represents the marketing - // name for the device model - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'iPhone 6s Plus', 'Samsung Galaxy S6' - // Note: It's recommended this value represents a human-readable version of - // the device model rather than a machine-readable alternative. - DeviceModelNameKey = attribute.Key("device.model.name") -) - -// DeviceID returns an attribute KeyValue conforming to the "device.id" -// semantic conventions. It represents a unique identifier representing the -// device -func DeviceID(val string) attribute.KeyValue { - return DeviceIDKey.String(val) -} - -// DeviceManufacturer returns an attribute KeyValue conforming to the -// "device.manufacturer" semantic conventions. It represents the name of the -// device manufacturer -func DeviceManufacturer(val string) attribute.KeyValue { - return DeviceManufacturerKey.String(val) -} - -// DeviceModelIdentifier returns an attribute KeyValue conforming to the -// "device.model.identifier" semantic conventions. It represents the model -// identifier for the device -func DeviceModelIdentifier(val string) attribute.KeyValue { - return DeviceModelIdentifierKey.String(val) -} - -// DeviceModelName returns an attribute KeyValue conforming to the -// "device.model.name" semantic conventions. It represents the marketing name -// for the device model -func DeviceModelName(val string) attribute.KeyValue { - return DeviceModelNameKey.String(val) -} - -// These attributes may be used for any disk related operation. -const ( - // DiskIoDirectionKey is the attribute Key conforming to the - // "disk.io.direction" semantic conventions. It represents the disk IO - // operation direction. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'read' - DiskIoDirectionKey = attribute.Key("disk.io.direction") -) - -var ( - // read - DiskIoDirectionRead = DiskIoDirectionKey.String("read") - // write - DiskIoDirectionWrite = DiskIoDirectionKey.String("write") -) - -// The shared attributes used to report a DNS query. -const ( - // DNSQuestionNameKey is the attribute Key conforming to the - // "dns.question.name" semantic conventions. It represents the name being - // queried. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'www.example.com', 'opentelemetry.io' - // Note: If the name field contains non-printable characters (below 32 or - // above 126), those characters should be represented as escaped base 10 - // integers (\DDD). Back slashes and quotes should be escaped. Tabs, - // carriage returns, and line feeds should be converted to \t, \r, and \n - // respectively. - DNSQuestionNameKey = attribute.Key("dns.question.name") -) - -// DNSQuestionName returns an attribute KeyValue conforming to the -// "dns.question.name" semantic conventions. It represents the name being -// queried. -func DNSQuestionName(val string) attribute.KeyValue { - return DNSQuestionNameKey.String(val) -} - -// Attributes for operations with an authenticated and/or authorized enduser. -const ( - // EnduserIDKey is the attribute Key conforming to the "enduser.id" - // semantic conventions. It represents the username or client_id extracted - // from the access token or - // [Authorization](https://tools.ietf.org/html/rfc7235#section-4.2) header - // in the inbound request from outside the system. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'username' - EnduserIDKey = attribute.Key("enduser.id") - - // EnduserRoleKey is the attribute Key conforming to the "enduser.role" - // semantic conventions. It represents the actual/assumed role the client - // is making the request under extracted from token or application security - // context. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'admin' - EnduserRoleKey = attribute.Key("enduser.role") - - // EnduserScopeKey is the attribute Key conforming to the "enduser.scope" - // semantic conventions. It represents the scopes or granted authorities - // the client currently possesses extracted from token or application - // security context. The value would come from the scope associated with an - // [OAuth 2.0 Access - // Token](https://tools.ietf.org/html/rfc6749#section-3.3) or an attribute - // value in a [SAML 2.0 - // Assertion](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'read:message, write:files' - EnduserScopeKey = attribute.Key("enduser.scope") -) - -// EnduserID returns an attribute KeyValue conforming to the "enduser.id" -// semantic conventions. It represents the username or client_id extracted from -// the access token or -// [Authorization](https://tools.ietf.org/html/rfc7235#section-4.2) header in -// the inbound request from outside the system. -func EnduserID(val string) attribute.KeyValue { - return EnduserIDKey.String(val) -} - -// EnduserRole returns an attribute KeyValue conforming to the -// "enduser.role" semantic conventions. It represents the actual/assumed role -// the client is making the request under extracted from token or application -// security context. -func EnduserRole(val string) attribute.KeyValue { - return EnduserRoleKey.String(val) -} - -// EnduserScope returns an attribute KeyValue conforming to the -// "enduser.scope" semantic conventions. It represents the scopes or granted -// authorities the client currently possesses extracted from token or -// application security context. The value would come from the scope associated -// with an [OAuth 2.0 Access -// Token](https://tools.ietf.org/html/rfc6749#section-3.3) or an attribute -// value in a [SAML 2.0 -// Assertion](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html). -func EnduserScope(val string) attribute.KeyValue { - return EnduserScopeKey.String(val) -} - -// The shared attributes used to report an error. -const ( - // ErrorTypeKey is the attribute Key conforming to the "error.type" - // semantic conventions. It represents the describes a class of error the - // operation ended with. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'timeout', 'java.net.UnknownHostException', - // 'server_certificate_invalid', '500' - // Note: The `error.type` SHOULD be predictable, and SHOULD have low - // cardinality. - // - // When `error.type` is set to a type (e.g., an exception type), its - // canonical class name identifying the type within the artifact SHOULD be - // used. - // - // Instrumentations SHOULD document the list of errors they report. - // - // The cardinality of `error.type` within one instrumentation library - // SHOULD be low. - // Telemetry consumers that aggregate data from multiple instrumentation - // libraries and applications - // should be prepared for `error.type` to have high cardinality at query - // time when no - // additional filters are applied. - // - // If the operation has completed successfully, instrumentations SHOULD NOT - // set `error.type`. - // - // If a specific domain defines its own set of error identifiers (such as - // HTTP or gRPC status codes), - // it's RECOMMENDED to: - // - // * Use a domain-specific attribute - // * Set `error.type` to capture all errors, regardless of whether they are - // defined within the domain-specific set or not. - ErrorTypeKey = attribute.Key("error.type") -) - -var ( - // A fallback error value to be used when the instrumentation doesn't define a custom value - ErrorTypeOther = ErrorTypeKey.String("_OTHER") -) - -// Attributes for Events represented using Log Records. -const ( - // EventNameKey is the attribute Key conforming to the "event.name" - // semantic conventions. It represents the identifies the class / type of - // event. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'browser.mouse.click', 'device.app.lifecycle' - // Note: Event names are subject to the same rules as [attribute - // names](https://github.com/open-telemetry/opentelemetry-specification/tree/v1.33.0/specification/common/attribute-naming.md). - // Notably, event names are namespaced to avoid collisions and provide a - // clean separation of semantics for events in separate domains like - // browser, mobile, and kubernetes. - EventNameKey = attribute.Key("event.name") -) - -// EventName returns an attribute KeyValue conforming to the "event.name" -// semantic conventions. It represents the identifies the class / type of -// event. -func EventName(val string) attribute.KeyValue { - return EventNameKey.String(val) -} - -// The shared attributes used to report a single exception associated with a -// span or log. -const ( - // ExceptionEscapedKey is the attribute Key conforming to the - // "exception.escaped" semantic conventions. It represents the sHOULD be - // set to true if the exception event is recorded at a point where it is - // known that the exception is escaping the scope of the span. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: stable - // Note: An exception is considered to have escaped (or left) the scope of - // a span, - // if that span is ended while the exception is still logically "in - // flight". - // This may be actually "in flight" in some languages (e.g. if the - // exception - // is passed to a Context manager's `__exit__` method in Python) but will - // usually be caught at the point of recording the exception in most - // languages. - // - // It is usually not possible to determine at the point where an exception - // is thrown - // whether it will escape the scope of a span. - // However, it is trivial to know that an exception - // will escape, if one checks for an active exception just before ending - // the span, - // as done in the [example for recording span - // exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). - // - // It follows that an exception may still escape the scope of the span - // even if the `exception.escaped` attribute was not set or set to false, - // since the event might have been recorded at a time where it was not - // clear whether the exception will escape. - ExceptionEscapedKey = attribute.Key("exception.escaped") - - // ExceptionMessageKey is the attribute Key conforming to the - // "exception.message" semantic conventions. It represents the exception - // message. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'Division by zero', "Can't convert 'int' object to str - // implicitly" - ExceptionMessageKey = attribute.Key("exception.message") - - // ExceptionStacktraceKey is the attribute Key conforming to the - // "exception.stacktrace" semantic conventions. It represents a stacktrace - // as a string in the natural representation for the language runtime. The - // representation is to be determined and documented by each language SIG. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'Exception in thread "main" java.lang.RuntimeException: Test - // exception\\n at ' - // 'com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at ' - // 'com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at ' - // 'com.example.GenerateTrace.main(GenerateTrace.java:5)' - ExceptionStacktraceKey = attribute.Key("exception.stacktrace") - - // ExceptionTypeKey is the attribute Key conforming to the "exception.type" - // semantic conventions. It represents the type of the exception (its - // fully-qualified class name, if applicable). The dynamic type of the - // exception should be preferred over the static type in languages that - // support it. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'java.net.ConnectException', 'OSError' - ExceptionTypeKey = attribute.Key("exception.type") -) - -// ExceptionEscaped returns an attribute KeyValue conforming to the -// "exception.escaped" semantic conventions. It represents the sHOULD be set to -// true if the exception event is recorded at a point where it is known that -// the exception is escaping the scope of the span. -func ExceptionEscaped(val bool) attribute.KeyValue { - return ExceptionEscapedKey.Bool(val) -} - -// ExceptionMessage returns an attribute KeyValue conforming to the -// "exception.message" semantic conventions. It represents the exception -// message. -func ExceptionMessage(val string) attribute.KeyValue { - return ExceptionMessageKey.String(val) -} - -// ExceptionStacktrace returns an attribute KeyValue conforming to the -// "exception.stacktrace" semantic conventions. It represents a stacktrace as a -// string in the natural representation for the language runtime. The -// representation is to be determined and documented by each language SIG. -func ExceptionStacktrace(val string) attribute.KeyValue { - return ExceptionStacktraceKey.String(val) -} - -// ExceptionType returns an attribute KeyValue conforming to the -// "exception.type" semantic conventions. It represents the type of the -// exception (its fully-qualified class name, if applicable). The dynamic type -// of the exception should be preferred over the static type in languages that -// support it. -func ExceptionType(val string) attribute.KeyValue { - return ExceptionTypeKey.String(val) -} - -// FaaS attributes -const ( - // FaaSColdstartKey is the attribute Key conforming to the "faas.coldstart" - // semantic conventions. It represents a boolean that is true if the - // serverless function is executed for the first time (aka cold-start). - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - FaaSColdstartKey = attribute.Key("faas.coldstart") - - // FaaSCronKey is the attribute Key conforming to the "faas.cron" semantic - // conventions. It represents a string containing the schedule period as - // [Cron - // Expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '0/5 * * * ? *' - FaaSCronKey = attribute.Key("faas.cron") - - // FaaSDocumentCollectionKey is the attribute Key conforming to the - // "faas.document.collection" semantic conventions. It represents the name - // of the source on which the triggering operation was performed. For - // example, in Cloud Storage or S3 corresponds to the bucket name, and in - // Cosmos DB to the database name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myBucketName', 'myDBName' - FaaSDocumentCollectionKey = attribute.Key("faas.document.collection") - - // FaaSDocumentNameKey is the attribute Key conforming to the - // "faas.document.name" semantic conventions. It represents the document - // name/table subjected to the operation. For example, in Cloud Storage or - // S3 is the name of the file, and in Cosmos DB the table name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myFile.txt', 'myTableName' - FaaSDocumentNameKey = attribute.Key("faas.document.name") - - // FaaSDocumentOperationKey is the attribute Key conforming to the - // "faas.document.operation" semantic conventions. It represents the - // describes the type of the operation that was performed on the data. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - FaaSDocumentOperationKey = attribute.Key("faas.document.operation") - - // FaaSDocumentTimeKey is the attribute Key conforming to the - // "faas.document.time" semantic conventions. It represents a string - // containing the time when the data was accessed in the [ISO - // 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format - // expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2020-01-23T13:47:06Z' - FaaSDocumentTimeKey = attribute.Key("faas.document.time") - - // FaaSInstanceKey is the attribute Key conforming to the "faas.instance" - // semantic conventions. It represents the execution environment ID as a - // string, that will be potentially reused for other invocations to the - // same function/function version. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2021/06/28/[$LATEST]2f399eb14537447da05ab2a2e39309de' - // Note: * **AWS Lambda:** Use the (full) log stream name. - FaaSInstanceKey = attribute.Key("faas.instance") - - // FaaSInvocationIDKey is the attribute Key conforming to the - // "faas.invocation_id" semantic conventions. It represents the invocation - // ID of the current function invocation. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'af9d5aa4-a685-4c5f-a22b-444f80b3cc28' - FaaSInvocationIDKey = attribute.Key("faas.invocation_id") - - // FaaSInvokedNameKey is the attribute Key conforming to the - // "faas.invoked_name" semantic conventions. It represents the name of the - // invoked function. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'my-function' - // Note: SHOULD be equal to the `faas.name` resource attribute of the - // invoked function. - FaaSInvokedNameKey = attribute.Key("faas.invoked_name") - - // FaaSInvokedProviderKey is the attribute Key conforming to the - // "faas.invoked_provider" semantic conventions. It represents the cloud - // provider of the invoked function. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: SHOULD be equal to the `cloud.provider` resource attribute of the - // invoked function. - FaaSInvokedProviderKey = attribute.Key("faas.invoked_provider") - - // FaaSInvokedRegionKey is the attribute Key conforming to the - // "faas.invoked_region" semantic conventions. It represents the cloud - // region of the invoked function. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'eu-central-1' - // Note: SHOULD be equal to the `cloud.region` resource attribute of the - // invoked function. - FaaSInvokedRegionKey = attribute.Key("faas.invoked_region") - - // FaaSMaxMemoryKey is the attribute Key conforming to the - // "faas.max_memory" semantic conventions. It represents the amount of - // memory available to the serverless function converted to Bytes. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 134217728 - // Note: It's recommended to set this attribute since e.g. too little - // memory can easily stop a Java AWS Lambda function from working - // correctly. On AWS Lambda, the environment variable - // `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information (which must - // be multiplied by 1,048,576). - FaaSMaxMemoryKey = attribute.Key("faas.max_memory") - - // FaaSNameKey is the attribute Key conforming to the "faas.name" semantic - // conventions. It represents the name of the single function that this - // runtime instance executes. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'my-function', 'myazurefunctionapp/some-function-name' - // Note: This is the name of the function as configured/deployed on the - // FaaS - // platform and is usually different from the name of the callback - // function (which may be stored in the - // [`code.namespace`/`code.function`](/docs/general/attributes.md#source-code-attributes) - // span attributes). - // - // For some cloud providers, the above definition is ambiguous. The - // following - // definition of function name MUST be used for this attribute - // (and consequently the span name) for the listed cloud - // providers/products: - // - // * **Azure:** The full name `/`, i.e., function app name - // followed by a forward slash followed by the function name (this form - // can also be seen in the resource JSON for the function). - // This means that a span attribute MUST be used, as an Azure function - // app can host multiple functions that would usually share - // a TracerProvider (see also the `cloud.resource_id` attribute). - FaaSNameKey = attribute.Key("faas.name") - - // FaaSTimeKey is the attribute Key conforming to the "faas.time" semantic - // conventions. It represents a string containing the function invocation - // time in the [ISO - // 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format - // expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2020-01-23T13:47:06Z' - FaaSTimeKey = attribute.Key("faas.time") - - // FaaSTriggerKey is the attribute Key conforming to the "faas.trigger" - // semantic conventions. It represents the type of the trigger which caused - // this function invocation. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - FaaSTriggerKey = attribute.Key("faas.trigger") - - // FaaSVersionKey is the attribute Key conforming to the "faas.version" - // semantic conventions. It represents the immutable version of the - // function being executed. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '26', 'pinkfroid-00002' - // Note: Depending on the cloud provider and platform, use: - // - // * **AWS Lambda:** The [function - // version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html) - // (an integer represented as a decimal string). - // * **Google Cloud Run (Services):** The - // [revision](https://cloud.google.com/run/docs/managing/revisions) - // (i.e., the function name plus the revision suffix). - // * **Google Cloud Functions:** The value of the - // [`K_REVISION` environment - // variable](https://cloud.google.com/functions/docs/env-var#runtime_environment_variables_set_automatically). - // * **Azure Functions:** Not applicable. Do not set this attribute. - FaaSVersionKey = attribute.Key("faas.version") -) - -var ( - // When a new object is created - FaaSDocumentOperationInsert = FaaSDocumentOperationKey.String("insert") - // When an object is modified - FaaSDocumentOperationEdit = FaaSDocumentOperationKey.String("edit") - // When an object is deleted - FaaSDocumentOperationDelete = FaaSDocumentOperationKey.String("delete") -) - -var ( - // Alibaba Cloud - FaaSInvokedProviderAlibabaCloud = FaaSInvokedProviderKey.String("alibaba_cloud") - // Amazon Web Services - FaaSInvokedProviderAWS = FaaSInvokedProviderKey.String("aws") - // Microsoft Azure - FaaSInvokedProviderAzure = FaaSInvokedProviderKey.String("azure") - // Google Cloud Platform - FaaSInvokedProviderGCP = FaaSInvokedProviderKey.String("gcp") - // Tencent Cloud - FaaSInvokedProviderTencentCloud = FaaSInvokedProviderKey.String("tencent_cloud") -) - -var ( - // A response to some data source operation such as a database or filesystem read/write - FaaSTriggerDatasource = FaaSTriggerKey.String("datasource") - // To provide an answer to an inbound HTTP request - FaaSTriggerHTTP = FaaSTriggerKey.String("http") - // A function is set to be executed when messages are sent to a messaging system - FaaSTriggerPubsub = FaaSTriggerKey.String("pubsub") - // A function is scheduled to be executed regularly - FaaSTriggerTimer = FaaSTriggerKey.String("timer") - // If none of the others apply - FaaSTriggerOther = FaaSTriggerKey.String("other") -) - -// FaaSColdstart returns an attribute KeyValue conforming to the -// "faas.coldstart" semantic conventions. It represents a boolean that is true -// if the serverless function is executed for the first time (aka cold-start). -func FaaSColdstart(val bool) attribute.KeyValue { - return FaaSColdstartKey.Bool(val) -} - -// FaaSCron returns an attribute KeyValue conforming to the "faas.cron" -// semantic conventions. It represents a string containing the schedule period -// as [Cron -// Expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm). -func FaaSCron(val string) attribute.KeyValue { - return FaaSCronKey.String(val) -} - -// FaaSDocumentCollection returns an attribute KeyValue conforming to the -// "faas.document.collection" semantic conventions. It represents the name of -// the source on which the triggering operation was performed. For example, in -// Cloud Storage or S3 corresponds to the bucket name, and in Cosmos DB to the -// database name. -func FaaSDocumentCollection(val string) attribute.KeyValue { - return FaaSDocumentCollectionKey.String(val) -} - -// FaaSDocumentName returns an attribute KeyValue conforming to the -// "faas.document.name" semantic conventions. It represents the document -// name/table subjected to the operation. For example, in Cloud Storage or S3 -// is the name of the file, and in Cosmos DB the table name. -func FaaSDocumentName(val string) attribute.KeyValue { - return FaaSDocumentNameKey.String(val) -} - -// FaaSDocumentTime returns an attribute KeyValue conforming to the -// "faas.document.time" semantic conventions. It represents a string containing -// the time when the data was accessed in the [ISO -// 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format -// expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). -func FaaSDocumentTime(val string) attribute.KeyValue { - return FaaSDocumentTimeKey.String(val) -} - -// FaaSInstance returns an attribute KeyValue conforming to the -// "faas.instance" semantic conventions. It represents the execution -// environment ID as a string, that will be potentially reused for other -// invocations to the same function/function version. -func FaaSInstance(val string) attribute.KeyValue { - return FaaSInstanceKey.String(val) -} - -// FaaSInvocationID returns an attribute KeyValue conforming to the -// "faas.invocation_id" semantic conventions. It represents the invocation ID -// of the current function invocation. -func FaaSInvocationID(val string) attribute.KeyValue { - return FaaSInvocationIDKey.String(val) -} - -// FaaSInvokedName returns an attribute KeyValue conforming to the -// "faas.invoked_name" semantic conventions. It represents the name of the -// invoked function. -func FaaSInvokedName(val string) attribute.KeyValue { - return FaaSInvokedNameKey.String(val) -} - -// FaaSInvokedRegion returns an attribute KeyValue conforming to the -// "faas.invoked_region" semantic conventions. It represents the cloud region -// of the invoked function. -func FaaSInvokedRegion(val string) attribute.KeyValue { - return FaaSInvokedRegionKey.String(val) -} - -// FaaSMaxMemory returns an attribute KeyValue conforming to the -// "faas.max_memory" semantic conventions. It represents the amount of memory -// available to the serverless function converted to Bytes. -func FaaSMaxMemory(val int) attribute.KeyValue { - return FaaSMaxMemoryKey.Int(val) -} - -// FaaSName returns an attribute KeyValue conforming to the "faas.name" -// semantic conventions. It represents the name of the single function that -// this runtime instance executes. -func FaaSName(val string) attribute.KeyValue { - return FaaSNameKey.String(val) -} - -// FaaSTime returns an attribute KeyValue conforming to the "faas.time" -// semantic conventions. It represents a string containing the function -// invocation time in the [ISO -// 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format -// expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). -func FaaSTime(val string) attribute.KeyValue { - return FaaSTimeKey.String(val) -} - -// FaaSVersion returns an attribute KeyValue conforming to the -// "faas.version" semantic conventions. It represents the immutable version of -// the function being executed. -func FaaSVersion(val string) attribute.KeyValue { - return FaaSVersionKey.String(val) -} - -// Attributes for Feature Flags. -const ( - // FeatureFlagKeyKey is the attribute Key conforming to the - // "feature_flag.key" semantic conventions. It represents the unique - // identifier of the feature flag. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'logo-color' - FeatureFlagKeyKey = attribute.Key("feature_flag.key") - - // FeatureFlagProviderNameKey is the attribute Key conforming to the - // "feature_flag.provider_name" semantic conventions. It represents the - // name of the service provider that performs the flag evaluation. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Flag Manager' - FeatureFlagProviderNameKey = attribute.Key("feature_flag.provider_name") - - // FeatureFlagVariantKey is the attribute Key conforming to the - // "feature_flag.variant" semantic conventions. It represents the sHOULD be - // a semantic identifier for a value. If one is unavailable, a stringified - // version of the value can be used. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'red', 'true', 'on' - // Note: A semantic identifier, commonly referred to as a variant, provides - // a means - // for referring to a value without including the value itself. This can - // provide additional context for understanding the meaning behind a value. - // For example, the variant `red` maybe be used for the value `#c05543`. - // - // A stringified version of the value can be used in situations where a - // semantic identifier is unavailable. String representation of the value - // should be determined by the implementer. - FeatureFlagVariantKey = attribute.Key("feature_flag.variant") -) - -// FeatureFlagKey returns an attribute KeyValue conforming to the -// "feature_flag.key" semantic conventions. It represents the unique identifier -// of the feature flag. -func FeatureFlagKey(val string) attribute.KeyValue { - return FeatureFlagKeyKey.String(val) -} - -// FeatureFlagProviderName returns an attribute KeyValue conforming to the -// "feature_flag.provider_name" semantic conventions. It represents the name of -// the service provider that performs the flag evaluation. -func FeatureFlagProviderName(val string) attribute.KeyValue { - return FeatureFlagProviderNameKey.String(val) -} - -// FeatureFlagVariant returns an attribute KeyValue conforming to the -// "feature_flag.variant" semantic conventions. It represents the sHOULD be a -// semantic identifier for a value. If one is unavailable, a stringified -// version of the value can be used. -func FeatureFlagVariant(val string) attribute.KeyValue { - return FeatureFlagVariantKey.String(val) -} - -// Describes file attributes. -const ( - // FileDirectoryKey is the attribute Key conforming to the "file.directory" - // semantic conventions. It represents the directory where the file is - // located. It should include the drive letter, when appropriate. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/home/user', 'C:\\Program Files\\MyApp' - FileDirectoryKey = attribute.Key("file.directory") - - // FileExtensionKey is the attribute Key conforming to the "file.extension" - // semantic conventions. It represents the file extension, excluding the - // leading dot. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'png', 'gz' - // Note: When the file name has multiple extensions (example.tar.gz), only - // the last one should be captured ("gz", not "tar.gz"). - FileExtensionKey = attribute.Key("file.extension") - - // FileNameKey is the attribute Key conforming to the "file.name" semantic - // conventions. It represents the name of the file including the extension, - // without the directory. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'example.png' - FileNameKey = attribute.Key("file.name") - - // FilePathKey is the attribute Key conforming to the "file.path" semantic - // conventions. It represents the full path to the file, including the file - // name. It should include the drive letter, when appropriate. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/home/alice/example.png', 'C:\\Program - // Files\\MyApp\\myapp.exe' - FilePathKey = attribute.Key("file.path") - - // FileSizeKey is the attribute Key conforming to the "file.size" semantic - // conventions. It represents the file size in bytes. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - FileSizeKey = attribute.Key("file.size") -) - -// FileDirectory returns an attribute KeyValue conforming to the -// "file.directory" semantic conventions. It represents the directory where the -// file is located. It should include the drive letter, when appropriate. -func FileDirectory(val string) attribute.KeyValue { - return FileDirectoryKey.String(val) -} - -// FileExtension returns an attribute KeyValue conforming to the -// "file.extension" semantic conventions. It represents the file extension, -// excluding the leading dot. -func FileExtension(val string) attribute.KeyValue { - return FileExtensionKey.String(val) -} - -// FileName returns an attribute KeyValue conforming to the "file.name" -// semantic conventions. It represents the name of the file including the -// extension, without the directory. -func FileName(val string) attribute.KeyValue { - return FileNameKey.String(val) -} - -// FilePath returns an attribute KeyValue conforming to the "file.path" -// semantic conventions. It represents the full path to the file, including the -// file name. It should include the drive letter, when appropriate. -func FilePath(val string) attribute.KeyValue { - return FilePathKey.String(val) -} - -// FileSize returns an attribute KeyValue conforming to the "file.size" -// semantic conventions. It represents the file size in bytes. -func FileSize(val int) attribute.KeyValue { - return FileSizeKey.Int(val) -} - -// Attributes for Google Cloud Run. -const ( - // GCPCloudRunJobExecutionKey is the attribute Key conforming to the - // "gcp.cloud_run.job.execution" semantic conventions. It represents the - // name of the Cloud Run - // [execution](https://cloud.google.com/run/docs/managing/job-executions) - // being run for the Job, as set by the - // [`CLOUD_RUN_EXECUTION`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) - // environment variable. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'job-name-xxxx', 'sample-job-mdw84' - GCPCloudRunJobExecutionKey = attribute.Key("gcp.cloud_run.job.execution") - - // GCPCloudRunJobTaskIndexKey is the attribute Key conforming to the - // "gcp.cloud_run.job.task_index" semantic conventions. It represents the - // index for a task within an execution as provided by the - // [`CLOUD_RUN_TASK_INDEX`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) - // environment variable. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 0, 1 - GCPCloudRunJobTaskIndexKey = attribute.Key("gcp.cloud_run.job.task_index") -) - -// GCPCloudRunJobExecution returns an attribute KeyValue conforming to the -// "gcp.cloud_run.job.execution" semantic conventions. It represents the name -// of the Cloud Run -// [execution](https://cloud.google.com/run/docs/managing/job-executions) being -// run for the Job, as set by the -// [`CLOUD_RUN_EXECUTION`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) -// environment variable. -func GCPCloudRunJobExecution(val string) attribute.KeyValue { - return GCPCloudRunJobExecutionKey.String(val) -} - -// GCPCloudRunJobTaskIndex returns an attribute KeyValue conforming to the -// "gcp.cloud_run.job.task_index" semantic conventions. It represents the index -// for a task within an execution as provided by the -// [`CLOUD_RUN_TASK_INDEX`](https://cloud.google.com/run/docs/container-contract#jobs-env-vars) -// environment variable. -func GCPCloudRunJobTaskIndex(val int) attribute.KeyValue { - return GCPCloudRunJobTaskIndexKey.Int(val) -} - -// Attributes for Google Compute Engine (GCE). -const ( - // GCPGceInstanceHostnameKey is the attribute Key conforming to the - // "gcp.gce.instance.hostname" semantic conventions. It represents the - // hostname of a GCE instance. This is the full value of the default or - // [custom - // hostname](https://cloud.google.com/compute/docs/instances/custom-hostname-vm). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'my-host1234.example.com', - // 'sample-vm.us-west1-b.c.my-project.internal' - GCPGceInstanceHostnameKey = attribute.Key("gcp.gce.instance.hostname") - - // GCPGceInstanceNameKey is the attribute Key conforming to the - // "gcp.gce.instance.name" semantic conventions. It represents the instance - // name of a GCE instance. This is the value provided by `host.name`, the - // visible name of the instance in the Cloud Console UI, and the prefix for - // the default hostname of the instance as defined by the [default internal - // DNS - // name](https://cloud.google.com/compute/docs/internal-dns#instance-fully-qualified-domain-names). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'instance-1', 'my-vm-name' - GCPGceInstanceNameKey = attribute.Key("gcp.gce.instance.name") -) - -// GCPGceInstanceHostname returns an attribute KeyValue conforming to the -// "gcp.gce.instance.hostname" semantic conventions. It represents the hostname -// of a GCE instance. This is the full value of the default or [custom -// hostname](https://cloud.google.com/compute/docs/instances/custom-hostname-vm). -func GCPGceInstanceHostname(val string) attribute.KeyValue { - return GCPGceInstanceHostnameKey.String(val) -} - -// GCPGceInstanceName returns an attribute KeyValue conforming to the -// "gcp.gce.instance.name" semantic conventions. It represents the instance -// name of a GCE instance. This is the value provided by `host.name`, the -// visible name of the instance in the Cloud Console UI, and the prefix for the -// default hostname of the instance as defined by the [default internal DNS -// name](https://cloud.google.com/compute/docs/internal-dns#instance-fully-qualified-domain-names). -func GCPGceInstanceName(val string) attribute.KeyValue { - return GCPGceInstanceNameKey.String(val) -} - -// The attributes used to describe telemetry in the context of LLM (Large -// Language Models) requests and responses. -const ( - // GenAiCompletionKey is the attribute Key conforming to the - // "gen_ai.completion" semantic conventions. It represents the full - // response received from the LLM. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: "[{'role': 'assistant', 'content': 'The capital of France is - // Paris.'}]" - // Note: It's RECOMMENDED to format completions as JSON string matching - // [OpenAI messages - // format](https://platform.openai.com/docs/guides/text-generation) - GenAiCompletionKey = attribute.Key("gen_ai.completion") - - // GenAiPromptKey is the attribute Key conforming to the "gen_ai.prompt" - // semantic conventions. It represents the full prompt sent to an LLM. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: "[{'role': 'user', 'content': 'What is the capital of - // France?'}]" - // Note: It's RECOMMENDED to format prompts as JSON string matching [OpenAI - // messages - // format](https://platform.openai.com/docs/guides/text-generation) - GenAiPromptKey = attribute.Key("gen_ai.prompt") - - // GenAiRequestMaxTokensKey is the attribute Key conforming to the - // "gen_ai.request.max_tokens" semantic conventions. It represents the - // maximum number of tokens the LLM generates for a request. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 100 - GenAiRequestMaxTokensKey = attribute.Key("gen_ai.request.max_tokens") - - // GenAiRequestModelKey is the attribute Key conforming to the - // "gen_ai.request.model" semantic conventions. It represents the name of - // the LLM a request is being made to. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'gpt-4' - GenAiRequestModelKey = attribute.Key("gen_ai.request.model") - - // GenAiRequestTemperatureKey is the attribute Key conforming to the - // "gen_ai.request.temperature" semantic conventions. It represents the - // temperature setting for the LLM request. - // - // Type: double - // RequirementLevel: Optional - // Stability: experimental - // Examples: 0.0 - GenAiRequestTemperatureKey = attribute.Key("gen_ai.request.temperature") - - // GenAiRequestTopPKey is the attribute Key conforming to the - // "gen_ai.request.top_p" semantic conventions. It represents the top_p - // sampling setting for the LLM request. - // - // Type: double - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1.0 - GenAiRequestTopPKey = attribute.Key("gen_ai.request.top_p") - - // GenAiResponseFinishReasonsKey is the attribute Key conforming to the - // "gen_ai.response.finish_reasons" semantic conventions. It represents the - // array of reasons the model stopped generating tokens, corresponding to - // each generation received. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'stop' - GenAiResponseFinishReasonsKey = attribute.Key("gen_ai.response.finish_reasons") - - // GenAiResponseIDKey is the attribute Key conforming to the - // "gen_ai.response.id" semantic conventions. It represents the unique - // identifier for the completion. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'chatcmpl-123' - GenAiResponseIDKey = attribute.Key("gen_ai.response.id") - - // GenAiResponseModelKey is the attribute Key conforming to the - // "gen_ai.response.model" semantic conventions. It represents the name of - // the LLM a response was generated from. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'gpt-4-0613' - GenAiResponseModelKey = attribute.Key("gen_ai.response.model") - - // GenAiSystemKey is the attribute Key conforming to the "gen_ai.system" - // semantic conventions. It represents the Generative AI product as - // identified by the client instrumentation. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'openai' - // Note: The actual GenAI product may differ from the one identified by the - // client. For example, when using OpenAI client libraries to communicate - // with Mistral, the `gen_ai.system` is set to `openai` based on the - // instrumentation's best knowledge. - GenAiSystemKey = attribute.Key("gen_ai.system") - - // GenAiUsageCompletionTokensKey is the attribute Key conforming to the - // "gen_ai.usage.completion_tokens" semantic conventions. It represents the - // number of tokens used in the LLM response (completion). - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 180 - GenAiUsageCompletionTokensKey = attribute.Key("gen_ai.usage.completion_tokens") - - // GenAiUsagePromptTokensKey is the attribute Key conforming to the - // "gen_ai.usage.prompt_tokens" semantic conventions. It represents the - // number of tokens used in the LLM prompt. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 100 - GenAiUsagePromptTokensKey = attribute.Key("gen_ai.usage.prompt_tokens") -) - -var ( - // OpenAI - GenAiSystemOpenai = GenAiSystemKey.String("openai") -) - -// GenAiCompletion returns an attribute KeyValue conforming to the -// "gen_ai.completion" semantic conventions. It represents the full response -// received from the LLM. -func GenAiCompletion(val string) attribute.KeyValue { - return GenAiCompletionKey.String(val) -} - -// GenAiPrompt returns an attribute KeyValue conforming to the -// "gen_ai.prompt" semantic conventions. It represents the full prompt sent to -// an LLM. -func GenAiPrompt(val string) attribute.KeyValue { - return GenAiPromptKey.String(val) -} - -// GenAiRequestMaxTokens returns an attribute KeyValue conforming to the -// "gen_ai.request.max_tokens" semantic conventions. It represents the maximum -// number of tokens the LLM generates for a request. -func GenAiRequestMaxTokens(val int) attribute.KeyValue { - return GenAiRequestMaxTokensKey.Int(val) -} - -// GenAiRequestModel returns an attribute KeyValue conforming to the -// "gen_ai.request.model" semantic conventions. It represents the name of the -// LLM a request is being made to. -func GenAiRequestModel(val string) attribute.KeyValue { - return GenAiRequestModelKey.String(val) -} - -// GenAiRequestTemperature returns an attribute KeyValue conforming to the -// "gen_ai.request.temperature" semantic conventions. It represents the -// temperature setting for the LLM request. -func GenAiRequestTemperature(val float64) attribute.KeyValue { - return GenAiRequestTemperatureKey.Float64(val) -} - -// GenAiRequestTopP returns an attribute KeyValue conforming to the -// "gen_ai.request.top_p" semantic conventions. It represents the top_p -// sampling setting for the LLM request. -func GenAiRequestTopP(val float64) attribute.KeyValue { - return GenAiRequestTopPKey.Float64(val) -} - -// GenAiResponseFinishReasons returns an attribute KeyValue conforming to -// the "gen_ai.response.finish_reasons" semantic conventions. It represents the -// array of reasons the model stopped generating tokens, corresponding to each -// generation received. -func GenAiResponseFinishReasons(val ...string) attribute.KeyValue { - return GenAiResponseFinishReasonsKey.StringSlice(val) -} - -// GenAiResponseID returns an attribute KeyValue conforming to the -// "gen_ai.response.id" semantic conventions. It represents the unique -// identifier for the completion. -func GenAiResponseID(val string) attribute.KeyValue { - return GenAiResponseIDKey.String(val) -} - -// GenAiResponseModel returns an attribute KeyValue conforming to the -// "gen_ai.response.model" semantic conventions. It represents the name of the -// LLM a response was generated from. -func GenAiResponseModel(val string) attribute.KeyValue { - return GenAiResponseModelKey.String(val) -} - -// GenAiUsageCompletionTokens returns an attribute KeyValue conforming to -// the "gen_ai.usage.completion_tokens" semantic conventions. It represents the -// number of tokens used in the LLM response (completion). -func GenAiUsageCompletionTokens(val int) attribute.KeyValue { - return GenAiUsageCompletionTokensKey.Int(val) -} - -// GenAiUsagePromptTokens returns an attribute KeyValue conforming to the -// "gen_ai.usage.prompt_tokens" semantic conventions. It represents the number -// of tokens used in the LLM prompt. -func GenAiUsagePromptTokens(val int) attribute.KeyValue { - return GenAiUsagePromptTokensKey.Int(val) -} - -// Attributes for GraphQL. -const ( - // GraphqlDocumentKey is the attribute Key conforming to the - // "graphql.document" semantic conventions. It represents the GraphQL - // document being executed. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'query findBookByID { bookByID(id: ?) { name } }' - // Note: The value may be sanitized to exclude sensitive information. - GraphqlDocumentKey = attribute.Key("graphql.document") - - // GraphqlOperationNameKey is the attribute Key conforming to the - // "graphql.operation.name" semantic conventions. It represents the name of - // the operation being executed. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'findBookByID' - GraphqlOperationNameKey = attribute.Key("graphql.operation.name") - - // GraphqlOperationTypeKey is the attribute Key conforming to the - // "graphql.operation.type" semantic conventions. It represents the type of - // the operation being executed. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'query', 'mutation', 'subscription' - GraphqlOperationTypeKey = attribute.Key("graphql.operation.type") -) - -var ( - // GraphQL query - GraphqlOperationTypeQuery = GraphqlOperationTypeKey.String("query") - // GraphQL mutation - GraphqlOperationTypeMutation = GraphqlOperationTypeKey.String("mutation") - // GraphQL subscription - GraphqlOperationTypeSubscription = GraphqlOperationTypeKey.String("subscription") -) - -// GraphqlDocument returns an attribute KeyValue conforming to the -// "graphql.document" semantic conventions. It represents the GraphQL document -// being executed. -func GraphqlDocument(val string) attribute.KeyValue { - return GraphqlDocumentKey.String(val) -} - -// GraphqlOperationName returns an attribute KeyValue conforming to the -// "graphql.operation.name" semantic conventions. It represents the name of the -// operation being executed. -func GraphqlOperationName(val string) attribute.KeyValue { - return GraphqlOperationNameKey.String(val) -} - -// Attributes for the Android platform on which the Android application is -// running. -const ( - // HerokuAppIDKey is the attribute Key conforming to the "heroku.app.id" - // semantic conventions. It represents the unique identifier for the - // application - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2daa2797-e42b-4624-9322-ec3f968df4da' - HerokuAppIDKey = attribute.Key("heroku.app.id") - - // HerokuReleaseCommitKey is the attribute Key conforming to the - // "heroku.release.commit" semantic conventions. It represents the commit - // hash for the current release - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'e6134959463efd8966b20e75b913cafe3f5ec' - HerokuReleaseCommitKey = attribute.Key("heroku.release.commit") - - // HerokuReleaseCreationTimestampKey is the attribute Key conforming to the - // "heroku.release.creation_timestamp" semantic conventions. It represents - // the time and date the release was created - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2022-10-23T18:00:42Z' - HerokuReleaseCreationTimestampKey = attribute.Key("heroku.release.creation_timestamp") -) - -// HerokuAppID returns an attribute KeyValue conforming to the -// "heroku.app.id" semantic conventions. It represents the unique identifier -// for the application -func HerokuAppID(val string) attribute.KeyValue { - return HerokuAppIDKey.String(val) -} - -// HerokuReleaseCommit returns an attribute KeyValue conforming to the -// "heroku.release.commit" semantic conventions. It represents the commit hash -// for the current release -func HerokuReleaseCommit(val string) attribute.KeyValue { - return HerokuReleaseCommitKey.String(val) -} - -// HerokuReleaseCreationTimestamp returns an attribute KeyValue conforming -// to the "heroku.release.creation_timestamp" semantic conventions. It -// represents the time and date the release was created -func HerokuReleaseCreationTimestamp(val string) attribute.KeyValue { - return HerokuReleaseCreationTimestampKey.String(val) -} - -// A host is defined as a computing instance. For example, physical servers, -// virtual machines, switches or disk array. -const ( - // HostArchKey is the attribute Key conforming to the "host.arch" semantic - // conventions. It represents the CPU architecture the host system is - // running on. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - HostArchKey = attribute.Key("host.arch") - - // HostCPUCacheL2SizeKey is the attribute Key conforming to the - // "host.cpu.cache.l2.size" semantic conventions. It represents the amount - // of level 2 memory cache available to the processor (in Bytes). - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 12288000 - HostCPUCacheL2SizeKey = attribute.Key("host.cpu.cache.l2.size") - - // HostCPUFamilyKey is the attribute Key conforming to the - // "host.cpu.family" semantic conventions. It represents the family or - // generation of the CPU. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '6', 'PA-RISC 1.1e' - HostCPUFamilyKey = attribute.Key("host.cpu.family") - - // HostCPUModelIDKey is the attribute Key conforming to the - // "host.cpu.model.id" semantic conventions. It represents the model - // identifier. It provides more granular information about the CPU, - // distinguishing it from other CPUs within the same family. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '6', '9000/778/B180L' - HostCPUModelIDKey = attribute.Key("host.cpu.model.id") - - // HostCPUModelNameKey is the attribute Key conforming to the - // "host.cpu.model.name" semantic conventions. It represents the model - // designation of the processor. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz' - HostCPUModelNameKey = attribute.Key("host.cpu.model.name") - - // HostCPUSteppingKey is the attribute Key conforming to the - // "host.cpu.stepping" semantic conventions. It represents the stepping or - // core revisions. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1', 'r1p1' - HostCPUSteppingKey = attribute.Key("host.cpu.stepping") - - // HostCPUVendorIDKey is the attribute Key conforming to the - // "host.cpu.vendor.id" semantic conventions. It represents the processor - // manufacturer identifier. A maximum 12-character string. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'GenuineIntel' - // Note: [CPUID](https://wiki.osdev.org/CPUID) command returns the vendor - // ID string in EBX, EDX and ECX registers. Writing these to memory in this - // order results in a 12-character string. - HostCPUVendorIDKey = attribute.Key("host.cpu.vendor.id") - - // HostIDKey is the attribute Key conforming to the "host.id" semantic - // conventions. It represents the unique host ID. For Cloud, this must be - // the instance_id assigned by the cloud provider. For non-containerized - // systems, this should be the `machine-id`. See the table below for the - // sources to use to determine the `machine-id` based on operating system. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'fdbf79e8af94cb7f9e8df36789187052' - HostIDKey = attribute.Key("host.id") - - // HostImageIDKey is the attribute Key conforming to the "host.image.id" - // semantic conventions. It represents the vM image ID or host OS image ID. - // For Cloud, this value is from the provider. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'ami-07b06b442921831e5' - HostImageIDKey = attribute.Key("host.image.id") - - // HostImageNameKey is the attribute Key conforming to the - // "host.image.name" semantic conventions. It represents the name of the VM - // image or OS install the host was instantiated from. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'infra-ami-eks-worker-node-7d4ec78312', 'CentOS-8-x86_64-1905' - HostImageNameKey = attribute.Key("host.image.name") - - // HostImageVersionKey is the attribute Key conforming to the - // "host.image.version" semantic conventions. It represents the version - // string of the VM image or host OS as defined in [Version - // Attributes](/docs/resource/README.md#version-attributes). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '0.1' - HostImageVersionKey = attribute.Key("host.image.version") - - // HostIPKey is the attribute Key conforming to the "host.ip" semantic - // conventions. It represents the available IP addresses of the host, - // excluding loopback interfaces. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '192.168.1.140', 'fe80::abc2:4a28:737a:609e' - // Note: IPv4 Addresses MUST be specified in dotted-quad notation. IPv6 - // addresses MUST be specified in the [RFC - // 5952](https://www.rfc-editor.org/rfc/rfc5952.html) format. - HostIPKey = attribute.Key("host.ip") - - // HostMacKey is the attribute Key conforming to the "host.mac" semantic - // conventions. It represents the available MAC addresses of the host, - // excluding loopback interfaces. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'AC-DE-48-23-45-67', 'AC-DE-48-23-45-67-01-9F' - // Note: MAC Addresses MUST be represented in [IEEE RA hexadecimal - // form](https://standards.ieee.org/wp-content/uploads/import/documents/tutorials/eui.pdf): - // as hyphen-separated octets in uppercase hexadecimal form from most to - // least significant. - HostMacKey = attribute.Key("host.mac") - - // HostNameKey is the attribute Key conforming to the "host.name" semantic - // conventions. It represents the name of the host. On Unix systems, it may - // contain what the hostname command returns, or the fully qualified - // hostname, or another name specified by the user. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry-test' - HostNameKey = attribute.Key("host.name") - - // HostTypeKey is the attribute Key conforming to the "host.type" semantic - // conventions. It represents the type of host. For Cloud, this must be the - // machine type. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'n1-standard-1' - HostTypeKey = attribute.Key("host.type") -) - -var ( - // AMD64 - HostArchAMD64 = HostArchKey.String("amd64") - // ARM32 - HostArchARM32 = HostArchKey.String("arm32") - // ARM64 - HostArchARM64 = HostArchKey.String("arm64") - // Itanium - HostArchIA64 = HostArchKey.String("ia64") - // 32-bit PowerPC - HostArchPPC32 = HostArchKey.String("ppc32") - // 64-bit PowerPC - HostArchPPC64 = HostArchKey.String("ppc64") - // IBM z/Architecture - HostArchS390x = HostArchKey.String("s390x") - // 32-bit x86 - HostArchX86 = HostArchKey.String("x86") -) - -// HostCPUCacheL2Size returns an attribute KeyValue conforming to the -// "host.cpu.cache.l2.size" semantic conventions. It represents the amount of -// level 2 memory cache available to the processor (in Bytes). -func HostCPUCacheL2Size(val int) attribute.KeyValue { - return HostCPUCacheL2SizeKey.Int(val) -} - -// HostCPUFamily returns an attribute KeyValue conforming to the -// "host.cpu.family" semantic conventions. It represents the family or -// generation of the CPU. -func HostCPUFamily(val string) attribute.KeyValue { - return HostCPUFamilyKey.String(val) -} - -// HostCPUModelID returns an attribute KeyValue conforming to the -// "host.cpu.model.id" semantic conventions. It represents the model -// identifier. It provides more granular information about the CPU, -// distinguishing it from other CPUs within the same family. -func HostCPUModelID(val string) attribute.KeyValue { - return HostCPUModelIDKey.String(val) -} - -// HostCPUModelName returns an attribute KeyValue conforming to the -// "host.cpu.model.name" semantic conventions. It represents the model -// designation of the processor. -func HostCPUModelName(val string) attribute.KeyValue { - return HostCPUModelNameKey.String(val) -} - -// HostCPUStepping returns an attribute KeyValue conforming to the -// "host.cpu.stepping" semantic conventions. It represents the stepping or core -// revisions. -func HostCPUStepping(val string) attribute.KeyValue { - return HostCPUSteppingKey.String(val) -} - -// HostCPUVendorID returns an attribute KeyValue conforming to the -// "host.cpu.vendor.id" semantic conventions. It represents the processor -// manufacturer identifier. A maximum 12-character string. -func HostCPUVendorID(val string) attribute.KeyValue { - return HostCPUVendorIDKey.String(val) -} - -// HostID returns an attribute KeyValue conforming to the "host.id" semantic -// conventions. It represents the unique host ID. For Cloud, this must be the -// instance_id assigned by the cloud provider. For non-containerized systems, -// this should be the `machine-id`. See the table below for the sources to use -// to determine the `machine-id` based on operating system. -func HostID(val string) attribute.KeyValue { - return HostIDKey.String(val) -} - -// HostImageID returns an attribute KeyValue conforming to the -// "host.image.id" semantic conventions. It represents the vM image ID or host -// OS image ID. For Cloud, this value is from the provider. -func HostImageID(val string) attribute.KeyValue { - return HostImageIDKey.String(val) -} - -// HostImageName returns an attribute KeyValue conforming to the -// "host.image.name" semantic conventions. It represents the name of the VM -// image or OS install the host was instantiated from. -func HostImageName(val string) attribute.KeyValue { - return HostImageNameKey.String(val) -} - -// HostImageVersion returns an attribute KeyValue conforming to the -// "host.image.version" semantic conventions. It represents the version string -// of the VM image or host OS as defined in [Version -// Attributes](/docs/resource/README.md#version-attributes). -func HostImageVersion(val string) attribute.KeyValue { - return HostImageVersionKey.String(val) -} - -// HostIP returns an attribute KeyValue conforming to the "host.ip" semantic -// conventions. It represents the available IP addresses of the host, excluding -// loopback interfaces. -func HostIP(val ...string) attribute.KeyValue { - return HostIPKey.StringSlice(val) -} - -// HostMac returns an attribute KeyValue conforming to the "host.mac" -// semantic conventions. It represents the available MAC addresses of the host, -// excluding loopback interfaces. -func HostMac(val ...string) attribute.KeyValue { - return HostMacKey.StringSlice(val) -} - -// HostName returns an attribute KeyValue conforming to the "host.name" -// semantic conventions. It represents the name of the host. On Unix systems, -// it may contain what the hostname command returns, or the fully qualified -// hostname, or another name specified by the user. -func HostName(val string) attribute.KeyValue { - return HostNameKey.String(val) -} - -// HostType returns an attribute KeyValue conforming to the "host.type" -// semantic conventions. It represents the type of host. For Cloud, this must -// be the machine type. -func HostType(val string) attribute.KeyValue { - return HostTypeKey.String(val) -} - -// Semantic convention attributes in the HTTP namespace. -const ( - // HTTPConnectionStateKey is the attribute Key conforming to the - // "http.connection.state" semantic conventions. It represents the state of - // the HTTP connection in the HTTP connection pool. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'active', 'idle' - HTTPConnectionStateKey = attribute.Key("http.connection.state") - - // HTTPRequestBodySizeKey is the attribute Key conforming to the - // "http.request.body.size" semantic conventions. It represents the size of - // the request payload body in bytes. This is the number of bytes - // transferred excluding headers and is often, but not always, present as - // the - // [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) - // header. For requests using transport encoding, this should be the - // compressed size. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 3495 - HTTPRequestBodySizeKey = attribute.Key("http.request.body.size") - - // HTTPRequestMethodKey is the attribute Key conforming to the - // "http.request.method" semantic conventions. It represents the hTTP - // request method. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'GET', 'POST', 'HEAD' - // Note: HTTP request method value SHOULD be "known" to the - // instrumentation. - // By default, this convention defines "known" methods as the ones listed - // in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - // and the PATCH method defined in - // [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - // - // If the HTTP request method is not known to instrumentation, it MUST set - // the `http.request.method` attribute to `_OTHER`. - // - // If the HTTP instrumentation could end up converting valid HTTP request - // methods to `_OTHER`, then it MUST provide a way to override - // the list of known HTTP methods. If this override is done via environment - // variable, then the environment variable MUST be named - // OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated - // list of case-sensitive known HTTP methods - // (this list MUST be a full override of the default known method, it is - // not a list of known methods in addition to the defaults). - // - // HTTP method names are case-sensitive and `http.request.method` attribute - // value MUST match a known HTTP method name exactly. - // Instrumentations for specific web frameworks that consider HTTP methods - // to be case insensitive, SHOULD populate a canonical equivalent. - // Tracing instrumentations that do so, MUST also set - // `http.request.method_original` to the original value. - HTTPRequestMethodKey = attribute.Key("http.request.method") - - // HTTPRequestMethodOriginalKey is the attribute Key conforming to the - // "http.request.method_original" semantic conventions. It represents the - // original HTTP method sent by the client in the request line. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'GeT', 'ACL', 'foo' - HTTPRequestMethodOriginalKey = attribute.Key("http.request.method_original") - - // HTTPRequestResendCountKey is the attribute Key conforming to the - // "http.request.resend_count" semantic conventions. It represents the - // ordinal number of request resending attempt (for any reason, including - // redirects). - // - // Type: int - // RequirementLevel: Optional - // Stability: stable - // Examples: 3 - // Note: The resend count SHOULD be updated each time an HTTP request gets - // resent by the client, regardless of what was the cause of the resending - // (e.g. redirection, authorization failure, 503 Server Unavailable, - // network issues, or any other). - HTTPRequestResendCountKey = attribute.Key("http.request.resend_count") - - // HTTPRequestSizeKey is the attribute Key conforming to the - // "http.request.size" semantic conventions. It represents the total size - // of the request in bytes. This should be the total number of bytes sent - // over the wire, including the request line (HTTP/1.1), framing (HTTP/2 - // and HTTP/3), headers, and request body if any. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1437 - HTTPRequestSizeKey = attribute.Key("http.request.size") - - // HTTPResponseBodySizeKey is the attribute Key conforming to the - // "http.response.body.size" semantic conventions. It represents the size - // of the response payload body in bytes. This is the number of bytes - // transferred excluding headers and is often, but not always, present as - // the - // [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) - // header. For requests using transport encoding, this should be the - // compressed size. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 3495 - HTTPResponseBodySizeKey = attribute.Key("http.response.body.size") - - // HTTPResponseSizeKey is the attribute Key conforming to the - // "http.response.size" semantic conventions. It represents the total size - // of the response in bytes. This should be the total number of bytes sent - // over the wire, including the status line (HTTP/1.1), framing (HTTP/2 and - // HTTP/3), headers, and response body and trailers if any. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1437 - HTTPResponseSizeKey = attribute.Key("http.response.size") - - // HTTPResponseStatusCodeKey is the attribute Key conforming to the - // "http.response.status_code" semantic conventions. It represents the - // [HTTP response status - // code](https://tools.ietf.org/html/rfc7231#section-6). - // - // Type: int - // RequirementLevel: Optional - // Stability: stable - // Examples: 200 - HTTPResponseStatusCodeKey = attribute.Key("http.response.status_code") - - // HTTPRouteKey is the attribute Key conforming to the "http.route" - // semantic conventions. It represents the matched route, that is, the path - // template in the format used by the respective server framework. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '/users/:userID?', '{controller}/{action}/{id?}' - // Note: MUST NOT be populated when this is not supported by the HTTP - // server framework as the route attribute should have low-cardinality and - // the URI path can NOT substitute it. - // SHOULD include the [application - // root](/docs/http/http-spans.md#http-server-definitions) if there is one. - HTTPRouteKey = attribute.Key("http.route") -) - -var ( - // active state - HTTPConnectionStateActive = HTTPConnectionStateKey.String("active") - // idle state - HTTPConnectionStateIdle = HTTPConnectionStateKey.String("idle") -) - -var ( - // CONNECT method - HTTPRequestMethodConnect = HTTPRequestMethodKey.String("CONNECT") - // DELETE method - HTTPRequestMethodDelete = HTTPRequestMethodKey.String("DELETE") - // GET method - HTTPRequestMethodGet = HTTPRequestMethodKey.String("GET") - // HEAD method - HTTPRequestMethodHead = HTTPRequestMethodKey.String("HEAD") - // OPTIONS method - HTTPRequestMethodOptions = HTTPRequestMethodKey.String("OPTIONS") - // PATCH method - HTTPRequestMethodPatch = HTTPRequestMethodKey.String("PATCH") - // POST method - HTTPRequestMethodPost = HTTPRequestMethodKey.String("POST") - // PUT method - HTTPRequestMethodPut = HTTPRequestMethodKey.String("PUT") - // TRACE method - HTTPRequestMethodTrace = HTTPRequestMethodKey.String("TRACE") - // Any HTTP method that the instrumentation has no prior knowledge of - HTTPRequestMethodOther = HTTPRequestMethodKey.String("_OTHER") -) - -// HTTPRequestBodySize returns an attribute KeyValue conforming to the -// "http.request.body.size" semantic conventions. It represents the size of the -// request payload body in bytes. This is the number of bytes transferred -// excluding headers and is often, but not always, present as the -// [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) -// header. For requests using transport encoding, this should be the compressed -// size. -func HTTPRequestBodySize(val int) attribute.KeyValue { - return HTTPRequestBodySizeKey.Int(val) -} - -// HTTPRequestMethodOriginal returns an attribute KeyValue conforming to the -// "http.request.method_original" semantic conventions. It represents the -// original HTTP method sent by the client in the request line. -func HTTPRequestMethodOriginal(val string) attribute.KeyValue { - return HTTPRequestMethodOriginalKey.String(val) -} - -// HTTPRequestResendCount returns an attribute KeyValue conforming to the -// "http.request.resend_count" semantic conventions. It represents the ordinal -// number of request resending attempt (for any reason, including redirects). -func HTTPRequestResendCount(val int) attribute.KeyValue { - return HTTPRequestResendCountKey.Int(val) -} - -// HTTPRequestSize returns an attribute KeyValue conforming to the -// "http.request.size" semantic conventions. It represents the total size of -// the request in bytes. This should be the total number of bytes sent over the -// wire, including the request line (HTTP/1.1), framing (HTTP/2 and HTTP/3), -// headers, and request body if any. -func HTTPRequestSize(val int) attribute.KeyValue { - return HTTPRequestSizeKey.Int(val) -} - -// HTTPResponseBodySize returns an attribute KeyValue conforming to the -// "http.response.body.size" semantic conventions. It represents the size of -// the response payload body in bytes. This is the number of bytes transferred -// excluding headers and is often, but not always, present as the -// [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) -// header. For requests using transport encoding, this should be the compressed -// size. -func HTTPResponseBodySize(val int) attribute.KeyValue { - return HTTPResponseBodySizeKey.Int(val) -} - -// HTTPResponseSize returns an attribute KeyValue conforming to the -// "http.response.size" semantic conventions. It represents the total size of -// the response in bytes. This should be the total number of bytes sent over -// the wire, including the status line (HTTP/1.1), framing (HTTP/2 and HTTP/3), -// headers, and response body and trailers if any. -func HTTPResponseSize(val int) attribute.KeyValue { - return HTTPResponseSizeKey.Int(val) -} - -// HTTPResponseStatusCode returns an attribute KeyValue conforming to the -// "http.response.status_code" semantic conventions. It represents the [HTTP -// response status code](https://tools.ietf.org/html/rfc7231#section-6). -func HTTPResponseStatusCode(val int) attribute.KeyValue { - return HTTPResponseStatusCodeKey.Int(val) -} - -// HTTPRoute returns an attribute KeyValue conforming to the "http.route" -// semantic conventions. It represents the matched route, that is, the path -// template in the format used by the respective server framework. -func HTTPRoute(val string) attribute.KeyValue { - return HTTPRouteKey.String(val) -} - -// Java Virtual machine related attributes. -const ( - // JvmBufferPoolNameKey is the attribute Key conforming to the - // "jvm.buffer.pool.name" semantic conventions. It represents the name of - // the buffer pool. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'mapped', 'direct' - // Note: Pool names are generally obtained via - // [BufferPoolMXBean#getName()](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/BufferPoolMXBean.html#getName()). - JvmBufferPoolNameKey = attribute.Key("jvm.buffer.pool.name") - - // JvmGcActionKey is the attribute Key conforming to the "jvm.gc.action" - // semantic conventions. It represents the name of the garbage collector - // action. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'end of minor GC', 'end of major GC' - // Note: Garbage collector action is generally obtained via - // [GarbageCollectionNotificationInfo#getGcAction()](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/GarbageCollectionNotificationInfo.html#getGcAction()). - JvmGcActionKey = attribute.Key("jvm.gc.action") - - // JvmGcNameKey is the attribute Key conforming to the "jvm.gc.name" - // semantic conventions. It represents the name of the garbage collector. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'G1 Young Generation', 'G1 Old Generation' - // Note: Garbage collector name is generally obtained via - // [GarbageCollectionNotificationInfo#getGcName()](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/GarbageCollectionNotificationInfo.html#getGcName()). - JvmGcNameKey = attribute.Key("jvm.gc.name") - - // JvmMemoryPoolNameKey is the attribute Key conforming to the - // "jvm.memory.pool.name" semantic conventions. It represents the name of - // the memory pool. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'G1 Old Gen', 'G1 Eden space', 'G1 Survivor Space' - // Note: Pool names are generally obtained via - // [MemoryPoolMXBean#getName()](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryPoolMXBean.html#getName()). - JvmMemoryPoolNameKey = attribute.Key("jvm.memory.pool.name") - - // JvmMemoryTypeKey is the attribute Key conforming to the - // "jvm.memory.type" semantic conventions. It represents the type of - // memory. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'heap', 'non_heap' - JvmMemoryTypeKey = attribute.Key("jvm.memory.type") - - // JvmThreadDaemonKey is the attribute Key conforming to the - // "jvm.thread.daemon" semantic conventions. It represents the whether the - // thread is daemon or not. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: stable - JvmThreadDaemonKey = attribute.Key("jvm.thread.daemon") - - // JvmThreadStateKey is the attribute Key conforming to the - // "jvm.thread.state" semantic conventions. It represents the state of the - // thread. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'runnable', 'blocked' - JvmThreadStateKey = attribute.Key("jvm.thread.state") -) - -var ( - // Heap memory - JvmMemoryTypeHeap = JvmMemoryTypeKey.String("heap") - // Non-heap memory - JvmMemoryTypeNonHeap = JvmMemoryTypeKey.String("non_heap") -) - -var ( - // A thread that has not yet started is in this state - JvmThreadStateNew = JvmThreadStateKey.String("new") - // A thread executing in the Java virtual machine is in this state - JvmThreadStateRunnable = JvmThreadStateKey.String("runnable") - // A thread that is blocked waiting for a monitor lock is in this state - JvmThreadStateBlocked = JvmThreadStateKey.String("blocked") - // A thread that is waiting indefinitely for another thread to perform a particular action is in this state - JvmThreadStateWaiting = JvmThreadStateKey.String("waiting") - // A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state - JvmThreadStateTimedWaiting = JvmThreadStateKey.String("timed_waiting") - // A thread that has exited is in this state - JvmThreadStateTerminated = JvmThreadStateKey.String("terminated") -) - -// JvmBufferPoolName returns an attribute KeyValue conforming to the -// "jvm.buffer.pool.name" semantic conventions. It represents the name of the -// buffer pool. -func JvmBufferPoolName(val string) attribute.KeyValue { - return JvmBufferPoolNameKey.String(val) -} - -// JvmGcAction returns an attribute KeyValue conforming to the -// "jvm.gc.action" semantic conventions. It represents the name of the garbage -// collector action. -func JvmGcAction(val string) attribute.KeyValue { - return JvmGcActionKey.String(val) -} - -// JvmGcName returns an attribute KeyValue conforming to the "jvm.gc.name" -// semantic conventions. It represents the name of the garbage collector. -func JvmGcName(val string) attribute.KeyValue { - return JvmGcNameKey.String(val) -} - -// JvmMemoryPoolName returns an attribute KeyValue conforming to the -// "jvm.memory.pool.name" semantic conventions. It represents the name of the -// memory pool. -func JvmMemoryPoolName(val string) attribute.KeyValue { - return JvmMemoryPoolNameKey.String(val) -} - -// JvmThreadDaemon returns an attribute KeyValue conforming to the -// "jvm.thread.daemon" semantic conventions. It represents the whether the -// thread is daemon or not. -func JvmThreadDaemon(val bool) attribute.KeyValue { - return JvmThreadDaemonKey.Bool(val) -} - -// Kubernetes resource attributes. -const ( - // K8SClusterNameKey is the attribute Key conforming to the - // "k8s.cluster.name" semantic conventions. It represents the name of the - // cluster. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry-cluster' - K8SClusterNameKey = attribute.Key("k8s.cluster.name") - - // K8SClusterUIDKey is the attribute Key conforming to the - // "k8s.cluster.uid" semantic conventions. It represents a pseudo-ID for - // the cluster, set to the UID of the `kube-system` namespace. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '218fc5a9-a5f1-4b54-aa05-46717d0ab26d' - // Note: K8S doesn't have support for obtaining a cluster ID. If this is - // ever - // added, we will recommend collecting the `k8s.cluster.uid` through the - // official APIs. In the meantime, we are able to use the `uid` of the - // `kube-system` namespace as a proxy for cluster ID. Read on for the - // rationale. - // - // Every object created in a K8S cluster is assigned a distinct UID. The - // `kube-system` namespace is used by Kubernetes itself and will exist - // for the lifetime of the cluster. Using the `uid` of the `kube-system` - // namespace is a reasonable proxy for the K8S ClusterID as it will only - // change if the cluster is rebuilt. Furthermore, Kubernetes UIDs are - // UUIDs as standardized by - // [ISO/IEC 9834-8 and ITU-T - // X.667](https://www.itu.int/ITU-T/studygroups/com17/oid.html). - // Which states: - // - // > If generated according to one of the mechanisms defined in Rec. - // ITU-T X.667 | ISO/IEC 9834-8, a UUID is either guaranteed to be - // different from all other UUIDs generated before 3603 A.D., or is - // extremely likely to be different (depending on the mechanism chosen). - // - // Therefore, UIDs between clusters should be extremely unlikely to - // conflict. - K8SClusterUIDKey = attribute.Key("k8s.cluster.uid") - - // K8SContainerNameKey is the attribute Key conforming to the - // "k8s.container.name" semantic conventions. It represents the name of the - // Container from Pod specification, must be unique within a Pod. Container - // runtime usually uses different globally unique name (`container.name`). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'redis' - K8SContainerNameKey = attribute.Key("k8s.container.name") - - // K8SContainerRestartCountKey is the attribute Key conforming to the - // "k8s.container.restart_count" semantic conventions. It represents the - // number of times the container was restarted. This attribute can be used - // to identify a particular container (running or stopped) within a - // container spec. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - K8SContainerRestartCountKey = attribute.Key("k8s.container.restart_count") - - // K8SContainerStatusLastTerminatedReasonKey is the attribute Key - // conforming to the "k8s.container.status.last_terminated_reason" semantic - // conventions. It represents the last terminated reason of the Container. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Evicted', 'Error' - K8SContainerStatusLastTerminatedReasonKey = attribute.Key("k8s.container.status.last_terminated_reason") - - // K8SCronJobNameKey is the attribute Key conforming to the - // "k8s.cronjob.name" semantic conventions. It represents the name of the - // CronJob. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry' - K8SCronJobNameKey = attribute.Key("k8s.cronjob.name") - - // K8SCronJobUIDKey is the attribute Key conforming to the - // "k8s.cronjob.uid" semantic conventions. It represents the UID of the - // CronJob. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SCronJobUIDKey = attribute.Key("k8s.cronjob.uid") - - // K8SDaemonSetNameKey is the attribute Key conforming to the - // "k8s.daemonset.name" semantic conventions. It represents the name of the - // DaemonSet. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry' - K8SDaemonSetNameKey = attribute.Key("k8s.daemonset.name") - - // K8SDaemonSetUIDKey is the attribute Key conforming to the - // "k8s.daemonset.uid" semantic conventions. It represents the UID of the - // DaemonSet. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SDaemonSetUIDKey = attribute.Key("k8s.daemonset.uid") - - // K8SDeploymentNameKey is the attribute Key conforming to the - // "k8s.deployment.name" semantic conventions. It represents the name of - // the Deployment. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry' - K8SDeploymentNameKey = attribute.Key("k8s.deployment.name") - - // K8SDeploymentUIDKey is the attribute Key conforming to the - // "k8s.deployment.uid" semantic conventions. It represents the UID of the - // Deployment. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SDeploymentUIDKey = attribute.Key("k8s.deployment.uid") - - // K8SJobNameKey is the attribute Key conforming to the "k8s.job.name" - // semantic conventions. It represents the name of the Job. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry' - K8SJobNameKey = attribute.Key("k8s.job.name") - - // K8SJobUIDKey is the attribute Key conforming to the "k8s.job.uid" - // semantic conventions. It represents the UID of the Job. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SJobUIDKey = attribute.Key("k8s.job.uid") - - // K8SNamespaceNameKey is the attribute Key conforming to the - // "k8s.namespace.name" semantic conventions. It represents the name of the - // namespace that the pod is running in. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'default' - K8SNamespaceNameKey = attribute.Key("k8s.namespace.name") - - // K8SNodeNameKey is the attribute Key conforming to the "k8s.node.name" - // semantic conventions. It represents the name of the Node. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'node-1' - K8SNodeNameKey = attribute.Key("k8s.node.name") - - // K8SNodeUIDKey is the attribute Key conforming to the "k8s.node.uid" - // semantic conventions. It represents the UID of the Node. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1eb3a0c6-0477-4080-a9cb-0cb7db65c6a2' - K8SNodeUIDKey = attribute.Key("k8s.node.uid") - - // K8SPodNameKey is the attribute Key conforming to the "k8s.pod.name" - // semantic conventions. It represents the name of the Pod. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry-pod-autoconf' - K8SPodNameKey = attribute.Key("k8s.pod.name") - - // K8SPodUIDKey is the attribute Key conforming to the "k8s.pod.uid" - // semantic conventions. It represents the UID of the Pod. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SPodUIDKey = attribute.Key("k8s.pod.uid") - - // K8SReplicaSetNameKey is the attribute Key conforming to the - // "k8s.replicaset.name" semantic conventions. It represents the name of - // the ReplicaSet. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry' - K8SReplicaSetNameKey = attribute.Key("k8s.replicaset.name") - - // K8SReplicaSetUIDKey is the attribute Key conforming to the - // "k8s.replicaset.uid" semantic conventions. It represents the UID of the - // ReplicaSet. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SReplicaSetUIDKey = attribute.Key("k8s.replicaset.uid") - - // K8SStatefulSetNameKey is the attribute Key conforming to the - // "k8s.statefulset.name" semantic conventions. It represents the name of - // the StatefulSet. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry' - K8SStatefulSetNameKey = attribute.Key("k8s.statefulset.name") - - // K8SStatefulSetUIDKey is the attribute Key conforming to the - // "k8s.statefulset.uid" semantic conventions. It represents the UID of the - // StatefulSet. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff' - K8SStatefulSetUIDKey = attribute.Key("k8s.statefulset.uid") -) - -// K8SClusterName returns an attribute KeyValue conforming to the -// "k8s.cluster.name" semantic conventions. It represents the name of the -// cluster. -func K8SClusterName(val string) attribute.KeyValue { - return K8SClusterNameKey.String(val) -} - -// K8SClusterUID returns an attribute KeyValue conforming to the -// "k8s.cluster.uid" semantic conventions. It represents a pseudo-ID for the -// cluster, set to the UID of the `kube-system` namespace. -func K8SClusterUID(val string) attribute.KeyValue { - return K8SClusterUIDKey.String(val) -} - -// K8SContainerName returns an attribute KeyValue conforming to the -// "k8s.container.name" semantic conventions. It represents the name of the -// Container from Pod specification, must be unique within a Pod. Container -// runtime usually uses different globally unique name (`container.name`). -func K8SContainerName(val string) attribute.KeyValue { - return K8SContainerNameKey.String(val) -} - -// K8SContainerRestartCount returns an attribute KeyValue conforming to the -// "k8s.container.restart_count" semantic conventions. It represents the number -// of times the container was restarted. This attribute can be used to identify -// a particular container (running or stopped) within a container spec. -func K8SContainerRestartCount(val int) attribute.KeyValue { - return K8SContainerRestartCountKey.Int(val) -} - -// K8SContainerStatusLastTerminatedReason returns an attribute KeyValue -// conforming to the "k8s.container.status.last_terminated_reason" semantic -// conventions. It represents the last terminated reason of the Container. -func K8SContainerStatusLastTerminatedReason(val string) attribute.KeyValue { - return K8SContainerStatusLastTerminatedReasonKey.String(val) -} - -// K8SCronJobName returns an attribute KeyValue conforming to the -// "k8s.cronjob.name" semantic conventions. It represents the name of the -// CronJob. -func K8SCronJobName(val string) attribute.KeyValue { - return K8SCronJobNameKey.String(val) -} - -// K8SCronJobUID returns an attribute KeyValue conforming to the -// "k8s.cronjob.uid" semantic conventions. It represents the UID of the -// CronJob. -func K8SCronJobUID(val string) attribute.KeyValue { - return K8SCronJobUIDKey.String(val) -} - -// K8SDaemonSetName returns an attribute KeyValue conforming to the -// "k8s.daemonset.name" semantic conventions. It represents the name of the -// DaemonSet. -func K8SDaemonSetName(val string) attribute.KeyValue { - return K8SDaemonSetNameKey.String(val) -} - -// K8SDaemonSetUID returns an attribute KeyValue conforming to the -// "k8s.daemonset.uid" semantic conventions. It represents the UID of the -// DaemonSet. -func K8SDaemonSetUID(val string) attribute.KeyValue { - return K8SDaemonSetUIDKey.String(val) -} - -// K8SDeploymentName returns an attribute KeyValue conforming to the -// "k8s.deployment.name" semantic conventions. It represents the name of the -// Deployment. -func K8SDeploymentName(val string) attribute.KeyValue { - return K8SDeploymentNameKey.String(val) -} - -// K8SDeploymentUID returns an attribute KeyValue conforming to the -// "k8s.deployment.uid" semantic conventions. It represents the UID of the -// Deployment. -func K8SDeploymentUID(val string) attribute.KeyValue { - return K8SDeploymentUIDKey.String(val) -} - -// K8SJobName returns an attribute KeyValue conforming to the "k8s.job.name" -// semantic conventions. It represents the name of the Job. -func K8SJobName(val string) attribute.KeyValue { - return K8SJobNameKey.String(val) -} - -// K8SJobUID returns an attribute KeyValue conforming to the "k8s.job.uid" -// semantic conventions. It represents the UID of the Job. -func K8SJobUID(val string) attribute.KeyValue { - return K8SJobUIDKey.String(val) -} - -// K8SNamespaceName returns an attribute KeyValue conforming to the -// "k8s.namespace.name" semantic conventions. It represents the name of the -// namespace that the pod is running in. -func K8SNamespaceName(val string) attribute.KeyValue { - return K8SNamespaceNameKey.String(val) -} - -// K8SNodeName returns an attribute KeyValue conforming to the -// "k8s.node.name" semantic conventions. It represents the name of the Node. -func K8SNodeName(val string) attribute.KeyValue { - return K8SNodeNameKey.String(val) -} - -// K8SNodeUID returns an attribute KeyValue conforming to the "k8s.node.uid" -// semantic conventions. It represents the UID of the Node. -func K8SNodeUID(val string) attribute.KeyValue { - return K8SNodeUIDKey.String(val) -} - -// K8SPodName returns an attribute KeyValue conforming to the "k8s.pod.name" -// semantic conventions. It represents the name of the Pod. -func K8SPodName(val string) attribute.KeyValue { - return K8SPodNameKey.String(val) -} - -// K8SPodUID returns an attribute KeyValue conforming to the "k8s.pod.uid" -// semantic conventions. It represents the UID of the Pod. -func K8SPodUID(val string) attribute.KeyValue { - return K8SPodUIDKey.String(val) -} - -// K8SReplicaSetName returns an attribute KeyValue conforming to the -// "k8s.replicaset.name" semantic conventions. It represents the name of the -// ReplicaSet. -func K8SReplicaSetName(val string) attribute.KeyValue { - return K8SReplicaSetNameKey.String(val) -} - -// K8SReplicaSetUID returns an attribute KeyValue conforming to the -// "k8s.replicaset.uid" semantic conventions. It represents the UID of the -// ReplicaSet. -func K8SReplicaSetUID(val string) attribute.KeyValue { - return K8SReplicaSetUIDKey.String(val) -} - -// K8SStatefulSetName returns an attribute KeyValue conforming to the -// "k8s.statefulset.name" semantic conventions. It represents the name of the -// StatefulSet. -func K8SStatefulSetName(val string) attribute.KeyValue { - return K8SStatefulSetNameKey.String(val) -} - -// K8SStatefulSetUID returns an attribute KeyValue conforming to the -// "k8s.statefulset.uid" semantic conventions. It represents the UID of the -// StatefulSet. -func K8SStatefulSetUID(val string) attribute.KeyValue { - return K8SStatefulSetUIDKey.String(val) -} - -// Log attributes -const ( - // LogIostreamKey is the attribute Key conforming to the "log.iostream" - // semantic conventions. It represents the stream associated with the log. - // See below for a list of well-known values. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - LogIostreamKey = attribute.Key("log.iostream") -) - -var ( - // Logs from stdout stream - LogIostreamStdout = LogIostreamKey.String("stdout") - // Events from stderr stream - LogIostreamStderr = LogIostreamKey.String("stderr") -) - -// Attributes for a file to which log was emitted. -const ( - // LogFileNameKey is the attribute Key conforming to the "log.file.name" - // semantic conventions. It represents the basename of the file. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'audit.log' - LogFileNameKey = attribute.Key("log.file.name") - - // LogFileNameResolvedKey is the attribute Key conforming to the - // "log.file.name_resolved" semantic conventions. It represents the - // basename of the file, with symlinks resolved. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'uuid.log' - LogFileNameResolvedKey = attribute.Key("log.file.name_resolved") - - // LogFilePathKey is the attribute Key conforming to the "log.file.path" - // semantic conventions. It represents the full path to the file. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/var/log/mysql/audit.log' - LogFilePathKey = attribute.Key("log.file.path") - - // LogFilePathResolvedKey is the attribute Key conforming to the - // "log.file.path_resolved" semantic conventions. It represents the full - // path to the file, with symlinks resolved. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/var/lib/docker/uuid.log' - LogFilePathResolvedKey = attribute.Key("log.file.path_resolved") -) - -// LogFileName returns an attribute KeyValue conforming to the -// "log.file.name" semantic conventions. It represents the basename of the -// file. -func LogFileName(val string) attribute.KeyValue { - return LogFileNameKey.String(val) -} - -// LogFileNameResolved returns an attribute KeyValue conforming to the -// "log.file.name_resolved" semantic conventions. It represents the basename of -// the file, with symlinks resolved. -func LogFileNameResolved(val string) attribute.KeyValue { - return LogFileNameResolvedKey.String(val) -} - -// LogFilePath returns an attribute KeyValue conforming to the -// "log.file.path" semantic conventions. It represents the full path to the -// file. -func LogFilePath(val string) attribute.KeyValue { - return LogFilePathKey.String(val) -} - -// LogFilePathResolved returns an attribute KeyValue conforming to the -// "log.file.path_resolved" semantic conventions. It represents the full path -// to the file, with symlinks resolved. -func LogFilePathResolved(val string) attribute.KeyValue { - return LogFilePathResolvedKey.String(val) -} - -// The generic attributes that may be used in any Log Record. -const ( - // LogRecordUIDKey is the attribute Key conforming to the "log.record.uid" - // semantic conventions. It represents a unique identifier for the Log - // Record. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '01ARZ3NDEKTSV4RRFFQ69G5FAV' - // Note: If an id is provided, other log records with the same id will be - // considered duplicates and can be removed safely. This means, that two - // distinguishable log records MUST have different values. - // The id MAY be an [Universally Unique Lexicographically Sortable - // Identifier (ULID)](https://github.com/ulid/spec), but other identifiers - // (e.g. UUID) may be used as needed. - LogRecordUIDKey = attribute.Key("log.record.uid") -) - -// LogRecordUID returns an attribute KeyValue conforming to the -// "log.record.uid" semantic conventions. It represents a unique identifier for -// the Log Record. -func LogRecordUID(val string) attribute.KeyValue { - return LogRecordUIDKey.String(val) -} - -// Attributes describing telemetry around messaging systems and messaging -// activities. -const ( - // MessagingBatchMessageCountKey is the attribute Key conforming to the - // "messaging.batch.message_count" semantic conventions. It represents the - // number of messages sent, received, or processed in the scope of the - // batching operation. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 0, 1, 2 - // Note: Instrumentations SHOULD NOT set `messaging.batch.message_count` on - // spans that operate with a single message. When a messaging client - // library supports both batch and single-message API for the same - // operation, instrumentations SHOULD use `messaging.batch.message_count` - // for batching APIs and SHOULD NOT use it for single-message APIs. - MessagingBatchMessageCountKey = attribute.Key("messaging.batch.message_count") - - // MessagingClientIDKey is the attribute Key conforming to the - // "messaging.client.id" semantic conventions. It represents a unique - // identifier for the client that consumes or produces a message. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'client-5', 'myhost@8742@s8083jm' - MessagingClientIDKey = attribute.Key("messaging.client.id") - - // MessagingDestinationAnonymousKey is the attribute Key conforming to the - // "messaging.destination.anonymous" semantic conventions. It represents a - // boolean that is true if the message destination is anonymous (could be - // unnamed or have auto-generated name). - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - MessagingDestinationAnonymousKey = attribute.Key("messaging.destination.anonymous") - - // MessagingDestinationNameKey is the attribute Key conforming to the - // "messaging.destination.name" semantic conventions. It represents the - // message destination name - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MyQueue', 'MyTopic' - // Note: Destination name SHOULD uniquely identify a specific queue, topic - // or other entity within the broker. If - // the broker doesn't have such notion, the destination name SHOULD - // uniquely identify the broker. - MessagingDestinationNameKey = attribute.Key("messaging.destination.name") - - // MessagingDestinationPartitionIDKey is the attribute Key conforming to - // the "messaging.destination.partition.id" semantic conventions. It - // represents the identifier of the partition messages are sent to or - // received from, unique within the `messaging.destination.name`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1' - MessagingDestinationPartitionIDKey = attribute.Key("messaging.destination.partition.id") - - // MessagingDestinationTemplateKey is the attribute Key conforming to the - // "messaging.destination.template" semantic conventions. It represents the - // low cardinality representation of the messaging destination name - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/customers/{customerID}' - // Note: Destination names could be constructed from templates. An example - // would be a destination name involving a user name or product id. - // Although the destination name in this case is of high cardinality, the - // underlying template is of low cardinality and can be effectively used - // for grouping and aggregation. - MessagingDestinationTemplateKey = attribute.Key("messaging.destination.template") - - // MessagingDestinationTemporaryKey is the attribute Key conforming to the - // "messaging.destination.temporary" semantic conventions. It represents a - // boolean that is true if the message destination is temporary and might - // not exist anymore after messages are processed. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - MessagingDestinationTemporaryKey = attribute.Key("messaging.destination.temporary") - - // MessagingDestinationPublishAnonymousKey is the attribute Key conforming - // to the "messaging.destination_publish.anonymous" semantic conventions. - // It represents a boolean that is true if the publish message destination - // is anonymous (could be unnamed or have auto-generated name). - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - MessagingDestinationPublishAnonymousKey = attribute.Key("messaging.destination_publish.anonymous") - - // MessagingDestinationPublishNameKey is the attribute Key conforming to - // the "messaging.destination_publish.name" semantic conventions. It - // represents the name of the original destination the message was - // published to - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MyQueue', 'MyTopic' - // Note: The name SHOULD uniquely identify a specific queue, topic, or - // other entity within the broker. If - // the broker doesn't have such notion, the original destination name - // SHOULD uniquely identify the broker. - MessagingDestinationPublishNameKey = attribute.Key("messaging.destination_publish.name") - - // MessagingMessageBodySizeKey is the attribute Key conforming to the - // "messaging.message.body.size" semantic conventions. It represents the - // size of the message body in bytes. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1439 - // Note: This can refer to both the compressed or uncompressed body size. - // If both sizes are known, the uncompressed - // body size should be used. - MessagingMessageBodySizeKey = attribute.Key("messaging.message.body.size") - - // MessagingMessageConversationIDKey is the attribute Key conforming to the - // "messaging.message.conversation_id" semantic conventions. It represents - // the conversation ID identifying the conversation to which the message - // belongs, represented as a string. Sometimes called "Correlation ID". - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MyConversationID' - MessagingMessageConversationIDKey = attribute.Key("messaging.message.conversation_id") - - // MessagingMessageEnvelopeSizeKey is the attribute Key conforming to the - // "messaging.message.envelope.size" semantic conventions. It represents - // the size of the message body and metadata in bytes. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 2738 - // Note: This can refer to both the compressed or uncompressed size. If - // both sizes are known, the uncompressed - // size should be used. - MessagingMessageEnvelopeSizeKey = attribute.Key("messaging.message.envelope.size") - - // MessagingMessageIDKey is the attribute Key conforming to the - // "messaging.message.id" semantic conventions. It represents a value used - // by the messaging system as an identifier for the message, represented as - // a string. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '452a7c7c7c7048c2f887f61572b18fc2' - MessagingMessageIDKey = attribute.Key("messaging.message.id") - - // MessagingOperationNameKey is the attribute Key conforming to the - // "messaging.operation.name" semantic conventions. It represents the - // system-specific name of the messaging operation. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'ack', 'nack', 'send' - MessagingOperationNameKey = attribute.Key("messaging.operation.name") - - // MessagingOperationTypeKey is the attribute Key conforming to the - // "messaging.operation.type" semantic conventions. It represents a string - // identifying the type of the messaging operation. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: If a custom value is used, it MUST be of low cardinality. - MessagingOperationTypeKey = attribute.Key("messaging.operation.type") - - // MessagingSystemKey is the attribute Key conforming to the - // "messaging.system" semantic conventions. It represents the messaging - // system as identified by the client instrumentation. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: The actual messaging system may differ from the one known by the - // client. For example, when using Kafka client libraries to communicate - // with Azure Event Hubs, the `messaging.system` is set to `kafka` based on - // the instrumentation's best knowledge. - MessagingSystemKey = attribute.Key("messaging.system") -) - -var ( - // One or more messages are provided for publishing to an intermediary. If a single message is published, the context of the "Publish" span can be used as the creation context and no "Create" span needs to be created - MessagingOperationTypePublish = MessagingOperationTypeKey.String("publish") - // A message is created. "Create" spans always refer to a single message and are used to provide a unique creation context for messages in batch publishing scenarios - MessagingOperationTypeCreate = MessagingOperationTypeKey.String("create") - // One or more messages are requested by a consumer. This operation refers to pull-based scenarios, where consumers explicitly call methods of messaging SDKs to receive messages - MessagingOperationTypeReceive = MessagingOperationTypeKey.String("receive") - // One or more messages are delivered to or processed by a consumer - MessagingOperationTypeDeliver = MessagingOperationTypeKey.String("process") - // One or more messages are settled - MessagingOperationTypeSettle = MessagingOperationTypeKey.String("settle") -) - -var ( - // Apache ActiveMQ - MessagingSystemActivemq = MessagingSystemKey.String("activemq") - // Amazon Simple Queue Service (SQS) - MessagingSystemAWSSqs = MessagingSystemKey.String("aws_sqs") - // Azure Event Grid - MessagingSystemEventgrid = MessagingSystemKey.String("eventgrid") - // Azure Event Hubs - MessagingSystemEventhubs = MessagingSystemKey.String("eventhubs") - // Azure Service Bus - MessagingSystemServicebus = MessagingSystemKey.String("servicebus") - // Google Cloud Pub/Sub - MessagingSystemGCPPubsub = MessagingSystemKey.String("gcp_pubsub") - // Java Message Service - MessagingSystemJms = MessagingSystemKey.String("jms") - // Apache Kafka - MessagingSystemKafka = MessagingSystemKey.String("kafka") - // RabbitMQ - MessagingSystemRabbitmq = MessagingSystemKey.String("rabbitmq") - // Apache RocketMQ - MessagingSystemRocketmq = MessagingSystemKey.String("rocketmq") -) - -// MessagingBatchMessageCount returns an attribute KeyValue conforming to -// the "messaging.batch.message_count" semantic conventions. It represents the -// number of messages sent, received, or processed in the scope of the batching -// operation. -func MessagingBatchMessageCount(val int) attribute.KeyValue { - return MessagingBatchMessageCountKey.Int(val) -} - -// MessagingClientID returns an attribute KeyValue conforming to the -// "messaging.client.id" semantic conventions. It represents a unique -// identifier for the client that consumes or produces a message. -func MessagingClientID(val string) attribute.KeyValue { - return MessagingClientIDKey.String(val) -} - -// MessagingDestinationAnonymous returns an attribute KeyValue conforming to -// the "messaging.destination.anonymous" semantic conventions. It represents a -// boolean that is true if the message destination is anonymous (could be -// unnamed or have auto-generated name). -func MessagingDestinationAnonymous(val bool) attribute.KeyValue { - return MessagingDestinationAnonymousKey.Bool(val) -} - -// MessagingDestinationName returns an attribute KeyValue conforming to the -// "messaging.destination.name" semantic conventions. It represents the message -// destination name -func MessagingDestinationName(val string) attribute.KeyValue { - return MessagingDestinationNameKey.String(val) -} - -// MessagingDestinationPartitionID returns an attribute KeyValue conforming -// to the "messaging.destination.partition.id" semantic conventions. It -// represents the identifier of the partition messages are sent to or received -// from, unique within the `messaging.destination.name`. -func MessagingDestinationPartitionID(val string) attribute.KeyValue { - return MessagingDestinationPartitionIDKey.String(val) -} - -// MessagingDestinationTemplate returns an attribute KeyValue conforming to -// the "messaging.destination.template" semantic conventions. It represents the -// low cardinality representation of the messaging destination name -func MessagingDestinationTemplate(val string) attribute.KeyValue { - return MessagingDestinationTemplateKey.String(val) -} - -// MessagingDestinationTemporary returns an attribute KeyValue conforming to -// the "messaging.destination.temporary" semantic conventions. It represents a -// boolean that is true if the message destination is temporary and might not -// exist anymore after messages are processed. -func MessagingDestinationTemporary(val bool) attribute.KeyValue { - return MessagingDestinationTemporaryKey.Bool(val) -} - -// MessagingDestinationPublishAnonymous returns an attribute KeyValue -// conforming to the "messaging.destination_publish.anonymous" semantic -// conventions. It represents a boolean that is true if the publish message -// destination is anonymous (could be unnamed or have auto-generated name). -func MessagingDestinationPublishAnonymous(val bool) attribute.KeyValue { - return MessagingDestinationPublishAnonymousKey.Bool(val) -} - -// MessagingDestinationPublishName returns an attribute KeyValue conforming -// to the "messaging.destination_publish.name" semantic conventions. It -// represents the name of the original destination the message was published to -func MessagingDestinationPublishName(val string) attribute.KeyValue { - return MessagingDestinationPublishNameKey.String(val) -} - -// MessagingMessageBodySize returns an attribute KeyValue conforming to the -// "messaging.message.body.size" semantic conventions. It represents the size -// of the message body in bytes. -func MessagingMessageBodySize(val int) attribute.KeyValue { - return MessagingMessageBodySizeKey.Int(val) -} - -// MessagingMessageConversationID returns an attribute KeyValue conforming -// to the "messaging.message.conversation_id" semantic conventions. It -// represents the conversation ID identifying the conversation to which the -// message belongs, represented as a string. Sometimes called "Correlation ID". -func MessagingMessageConversationID(val string) attribute.KeyValue { - return MessagingMessageConversationIDKey.String(val) -} - -// MessagingMessageEnvelopeSize returns an attribute KeyValue conforming to -// the "messaging.message.envelope.size" semantic conventions. It represents -// the size of the message body and metadata in bytes. -func MessagingMessageEnvelopeSize(val int) attribute.KeyValue { - return MessagingMessageEnvelopeSizeKey.Int(val) -} - -// MessagingMessageID returns an attribute KeyValue conforming to the -// "messaging.message.id" semantic conventions. It represents a value used by -// the messaging system as an identifier for the message, represented as a -// string. -func MessagingMessageID(val string) attribute.KeyValue { - return MessagingMessageIDKey.String(val) -} - -// MessagingOperationName returns an attribute KeyValue conforming to the -// "messaging.operation.name" semantic conventions. It represents the -// system-specific name of the messaging operation. -func MessagingOperationName(val string) attribute.KeyValue { - return MessagingOperationNameKey.String(val) -} - -// This group describes attributes specific to Apache Kafka. -const ( - // MessagingKafkaConsumerGroupKey is the attribute Key conforming to the - // "messaging.kafka.consumer.group" semantic conventions. It represents the - // name of the Kafka Consumer Group that is handling the message. Only - // applies to consumers, not producers. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'my-group' - MessagingKafkaConsumerGroupKey = attribute.Key("messaging.kafka.consumer.group") - - // MessagingKafkaMessageKeyKey is the attribute Key conforming to the - // "messaging.kafka.message.key" semantic conventions. It represents the - // message keys in Kafka are used for grouping alike messages to ensure - // they're processed on the same partition. They differ from - // `messaging.message.id` in that they're not unique. If the key is `null`, - // the attribute MUST NOT be set. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myKey' - // Note: If the key type is not string, it's string representation has to - // be supplied for the attribute. If the key has no unambiguous, canonical - // string form, don't include its value. - MessagingKafkaMessageKeyKey = attribute.Key("messaging.kafka.message.key") - - // MessagingKafkaMessageOffsetKey is the attribute Key conforming to the - // "messaging.kafka.message.offset" semantic conventions. It represents the - // offset of a record in the corresponding Kafka partition. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 42 - MessagingKafkaMessageOffsetKey = attribute.Key("messaging.kafka.message.offset") - - // MessagingKafkaMessageTombstoneKey is the attribute Key conforming to the - // "messaging.kafka.message.tombstone" semantic conventions. It represents - // a boolean that is true if the message is a tombstone. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - MessagingKafkaMessageTombstoneKey = attribute.Key("messaging.kafka.message.tombstone") -) - -// MessagingKafkaConsumerGroup returns an attribute KeyValue conforming to -// the "messaging.kafka.consumer.group" semantic conventions. It represents the -// name of the Kafka Consumer Group that is handling the message. Only applies -// to consumers, not producers. -func MessagingKafkaConsumerGroup(val string) attribute.KeyValue { - return MessagingKafkaConsumerGroupKey.String(val) -} - -// MessagingKafkaMessageKey returns an attribute KeyValue conforming to the -// "messaging.kafka.message.key" semantic conventions. It represents the -// message keys in Kafka are used for grouping alike messages to ensure they're -// processed on the same partition. They differ from `messaging.message.id` in -// that they're not unique. If the key is `null`, the attribute MUST NOT be -// set. -func MessagingKafkaMessageKey(val string) attribute.KeyValue { - return MessagingKafkaMessageKeyKey.String(val) -} - -// MessagingKafkaMessageOffset returns an attribute KeyValue conforming to -// the "messaging.kafka.message.offset" semantic conventions. It represents the -// offset of a record in the corresponding Kafka partition. -func MessagingKafkaMessageOffset(val int) attribute.KeyValue { - return MessagingKafkaMessageOffsetKey.Int(val) -} - -// MessagingKafkaMessageTombstone returns an attribute KeyValue conforming -// to the "messaging.kafka.message.tombstone" semantic conventions. It -// represents a boolean that is true if the message is a tombstone. -func MessagingKafkaMessageTombstone(val bool) attribute.KeyValue { - return MessagingKafkaMessageTombstoneKey.Bool(val) -} - -// This group describes attributes specific to RabbitMQ. -const ( - // MessagingRabbitmqDestinationRoutingKeyKey is the attribute Key - // conforming to the "messaging.rabbitmq.destination.routing_key" semantic - // conventions. It represents the rabbitMQ message routing key. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myKey' - MessagingRabbitmqDestinationRoutingKeyKey = attribute.Key("messaging.rabbitmq.destination.routing_key") - - // MessagingRabbitmqMessageDeliveryTagKey is the attribute Key conforming - // to the "messaging.rabbitmq.message.delivery_tag" semantic conventions. - // It represents the rabbitMQ message delivery tag - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 123 - MessagingRabbitmqMessageDeliveryTagKey = attribute.Key("messaging.rabbitmq.message.delivery_tag") -) - -// MessagingRabbitmqDestinationRoutingKey returns an attribute KeyValue -// conforming to the "messaging.rabbitmq.destination.routing_key" semantic -// conventions. It represents the rabbitMQ message routing key. -func MessagingRabbitmqDestinationRoutingKey(val string) attribute.KeyValue { - return MessagingRabbitmqDestinationRoutingKeyKey.String(val) -} - -// MessagingRabbitmqMessageDeliveryTag returns an attribute KeyValue -// conforming to the "messaging.rabbitmq.message.delivery_tag" semantic -// conventions. It represents the rabbitMQ message delivery tag -func MessagingRabbitmqMessageDeliveryTag(val int) attribute.KeyValue { - return MessagingRabbitmqMessageDeliveryTagKey.Int(val) -} - -// This group describes attributes specific to RocketMQ. -const ( - // MessagingRocketmqClientGroupKey is the attribute Key conforming to the - // "messaging.rocketmq.client_group" semantic conventions. It represents - // the name of the RocketMQ producer/consumer group that is handling the - // message. The client type is identified by the SpanKind. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myConsumerGroup' - MessagingRocketmqClientGroupKey = attribute.Key("messaging.rocketmq.client_group") - - // MessagingRocketmqConsumptionModelKey is the attribute Key conforming to - // the "messaging.rocketmq.consumption_model" semantic conventions. It - // represents the model of message consumption. This only applies to - // consumer spans. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - MessagingRocketmqConsumptionModelKey = attribute.Key("messaging.rocketmq.consumption_model") - - // MessagingRocketmqMessageDelayTimeLevelKey is the attribute Key - // conforming to the "messaging.rocketmq.message.delay_time_level" semantic - // conventions. It represents the delay time level for delay message, which - // determines the message delay time. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 3 - MessagingRocketmqMessageDelayTimeLevelKey = attribute.Key("messaging.rocketmq.message.delay_time_level") - - // MessagingRocketmqMessageDeliveryTimestampKey is the attribute Key - // conforming to the "messaging.rocketmq.message.delivery_timestamp" - // semantic conventions. It represents the timestamp in milliseconds that - // the delay message is expected to be delivered to consumer. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1665987217045 - MessagingRocketmqMessageDeliveryTimestampKey = attribute.Key("messaging.rocketmq.message.delivery_timestamp") - - // MessagingRocketmqMessageGroupKey is the attribute Key conforming to the - // "messaging.rocketmq.message.group" semantic conventions. It represents - // the it is essential for FIFO message. Messages that belong to the same - // message group are always processed one by one within the same consumer - // group. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myMessageGroup' - MessagingRocketmqMessageGroupKey = attribute.Key("messaging.rocketmq.message.group") - - // MessagingRocketmqMessageKeysKey is the attribute Key conforming to the - // "messaging.rocketmq.message.keys" semantic conventions. It represents - // the key(s) of message, another way to mark message besides message id. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'keyA', 'keyB' - MessagingRocketmqMessageKeysKey = attribute.Key("messaging.rocketmq.message.keys") - - // MessagingRocketmqMessageTagKey is the attribute Key conforming to the - // "messaging.rocketmq.message.tag" semantic conventions. It represents the - // secondary classifier of message besides topic. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'tagA' - MessagingRocketmqMessageTagKey = attribute.Key("messaging.rocketmq.message.tag") - - // MessagingRocketmqMessageTypeKey is the attribute Key conforming to the - // "messaging.rocketmq.message.type" semantic conventions. It represents - // the type of message. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - MessagingRocketmqMessageTypeKey = attribute.Key("messaging.rocketmq.message.type") - - // MessagingRocketmqNamespaceKey is the attribute Key conforming to the - // "messaging.rocketmq.namespace" semantic conventions. It represents the - // namespace of RocketMQ resources, resources in different namespaces are - // individual. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myNamespace' - MessagingRocketmqNamespaceKey = attribute.Key("messaging.rocketmq.namespace") -) - -var ( - // Clustering consumption model - MessagingRocketmqConsumptionModelClustering = MessagingRocketmqConsumptionModelKey.String("clustering") - // Broadcasting consumption model - MessagingRocketmqConsumptionModelBroadcasting = MessagingRocketmqConsumptionModelKey.String("broadcasting") -) - -var ( - // Normal message - MessagingRocketmqMessageTypeNormal = MessagingRocketmqMessageTypeKey.String("normal") - // FIFO message - MessagingRocketmqMessageTypeFifo = MessagingRocketmqMessageTypeKey.String("fifo") - // Delay message - MessagingRocketmqMessageTypeDelay = MessagingRocketmqMessageTypeKey.String("delay") - // Transaction message - MessagingRocketmqMessageTypeTransaction = MessagingRocketmqMessageTypeKey.String("transaction") -) - -// MessagingRocketmqClientGroup returns an attribute KeyValue conforming to -// the "messaging.rocketmq.client_group" semantic conventions. It represents -// the name of the RocketMQ producer/consumer group that is handling the -// message. The client type is identified by the SpanKind. -func MessagingRocketmqClientGroup(val string) attribute.KeyValue { - return MessagingRocketmqClientGroupKey.String(val) -} - -// MessagingRocketmqMessageDelayTimeLevel returns an attribute KeyValue -// conforming to the "messaging.rocketmq.message.delay_time_level" semantic -// conventions. It represents the delay time level for delay message, which -// determines the message delay time. -func MessagingRocketmqMessageDelayTimeLevel(val int) attribute.KeyValue { - return MessagingRocketmqMessageDelayTimeLevelKey.Int(val) -} - -// MessagingRocketmqMessageDeliveryTimestamp returns an attribute KeyValue -// conforming to the "messaging.rocketmq.message.delivery_timestamp" semantic -// conventions. It represents the timestamp in milliseconds that the delay -// message is expected to be delivered to consumer. -func MessagingRocketmqMessageDeliveryTimestamp(val int) attribute.KeyValue { - return MessagingRocketmqMessageDeliveryTimestampKey.Int(val) -} - -// MessagingRocketmqMessageGroup returns an attribute KeyValue conforming to -// the "messaging.rocketmq.message.group" semantic conventions. It represents -// the it is essential for FIFO message. Messages that belong to the same -// message group are always processed one by one within the same consumer -// group. -func MessagingRocketmqMessageGroup(val string) attribute.KeyValue { - return MessagingRocketmqMessageGroupKey.String(val) -} - -// MessagingRocketmqMessageKeys returns an attribute KeyValue conforming to -// the "messaging.rocketmq.message.keys" semantic conventions. It represents -// the key(s) of message, another way to mark message besides message id. -func MessagingRocketmqMessageKeys(val ...string) attribute.KeyValue { - return MessagingRocketmqMessageKeysKey.StringSlice(val) -} - -// MessagingRocketmqMessageTag returns an attribute KeyValue conforming to -// the "messaging.rocketmq.message.tag" semantic conventions. It represents the -// secondary classifier of message besides topic. -func MessagingRocketmqMessageTag(val string) attribute.KeyValue { - return MessagingRocketmqMessageTagKey.String(val) -} - -// MessagingRocketmqNamespace returns an attribute KeyValue conforming to -// the "messaging.rocketmq.namespace" semantic conventions. It represents the -// namespace of RocketMQ resources, resources in different namespaces are -// individual. -func MessagingRocketmqNamespace(val string) attribute.KeyValue { - return MessagingRocketmqNamespaceKey.String(val) -} - -// This group describes attributes specific to GCP Pub/Sub. -const ( - // MessagingGCPPubsubMessageAckDeadlineKey is the attribute Key conforming - // to the "messaging.gcp_pubsub.message.ack_deadline" semantic conventions. - // It represents the ack deadline in seconds set for the modify ack - // deadline request. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 10 - MessagingGCPPubsubMessageAckDeadlineKey = attribute.Key("messaging.gcp_pubsub.message.ack_deadline") - - // MessagingGCPPubsubMessageAckIDKey is the attribute Key conforming to the - // "messaging.gcp_pubsub.message.ack_id" semantic conventions. It - // represents the ack id for a given message. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'ack_id' - MessagingGCPPubsubMessageAckIDKey = attribute.Key("messaging.gcp_pubsub.message.ack_id") - - // MessagingGCPPubsubMessageDeliveryAttemptKey is the attribute Key - // conforming to the "messaging.gcp_pubsub.message.delivery_attempt" - // semantic conventions. It represents the delivery attempt for a given - // message. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 2 - MessagingGCPPubsubMessageDeliveryAttemptKey = attribute.Key("messaging.gcp_pubsub.message.delivery_attempt") - - // MessagingGCPPubsubMessageOrderingKeyKey is the attribute Key conforming - // to the "messaging.gcp_pubsub.message.ordering_key" semantic conventions. - // It represents the ordering key for a given message. If the attribute is - // not present, the message does not have an ordering key. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'ordering_key' - MessagingGCPPubsubMessageOrderingKeyKey = attribute.Key("messaging.gcp_pubsub.message.ordering_key") -) - -// MessagingGCPPubsubMessageAckDeadline returns an attribute KeyValue -// conforming to the "messaging.gcp_pubsub.message.ack_deadline" semantic -// conventions. It represents the ack deadline in seconds set for the modify -// ack deadline request. -func MessagingGCPPubsubMessageAckDeadline(val int) attribute.KeyValue { - return MessagingGCPPubsubMessageAckDeadlineKey.Int(val) -} - -// MessagingGCPPubsubMessageAckID returns an attribute KeyValue conforming -// to the "messaging.gcp_pubsub.message.ack_id" semantic conventions. It -// represents the ack id for a given message. -func MessagingGCPPubsubMessageAckID(val string) attribute.KeyValue { - return MessagingGCPPubsubMessageAckIDKey.String(val) -} - -// MessagingGCPPubsubMessageDeliveryAttempt returns an attribute KeyValue -// conforming to the "messaging.gcp_pubsub.message.delivery_attempt" semantic -// conventions. It represents the delivery attempt for a given message. -func MessagingGCPPubsubMessageDeliveryAttempt(val int) attribute.KeyValue { - return MessagingGCPPubsubMessageDeliveryAttemptKey.Int(val) -} - -// MessagingGCPPubsubMessageOrderingKey returns an attribute KeyValue -// conforming to the "messaging.gcp_pubsub.message.ordering_key" semantic -// conventions. It represents the ordering key for a given message. If the -// attribute is not present, the message does not have an ordering key. -func MessagingGCPPubsubMessageOrderingKey(val string) attribute.KeyValue { - return MessagingGCPPubsubMessageOrderingKeyKey.String(val) -} - -// This group describes attributes specific to Azure Service Bus. -const ( - // MessagingServicebusDestinationSubscriptionNameKey is the attribute Key - // conforming to the "messaging.servicebus.destination.subscription_name" - // semantic conventions. It represents the name of the subscription in the - // topic messages are received from. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'mySubscription' - MessagingServicebusDestinationSubscriptionNameKey = attribute.Key("messaging.servicebus.destination.subscription_name") - - // MessagingServicebusDispositionStatusKey is the attribute Key conforming - // to the "messaging.servicebus.disposition_status" semantic conventions. - // It represents the describes the [settlement - // type](https://learn.microsoft.com/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock). - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - MessagingServicebusDispositionStatusKey = attribute.Key("messaging.servicebus.disposition_status") - - // MessagingServicebusMessageDeliveryCountKey is the attribute Key - // conforming to the "messaging.servicebus.message.delivery_count" semantic - // conventions. It represents the number of deliveries that have been - // attempted for this message. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 2 - MessagingServicebusMessageDeliveryCountKey = attribute.Key("messaging.servicebus.message.delivery_count") - - // MessagingServicebusMessageEnqueuedTimeKey is the attribute Key - // conforming to the "messaging.servicebus.message.enqueued_time" semantic - // conventions. It represents the UTC epoch seconds at which the message - // has been accepted and stored in the entity. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1701393730 - MessagingServicebusMessageEnqueuedTimeKey = attribute.Key("messaging.servicebus.message.enqueued_time") -) - -var ( - // Message is completed - MessagingServicebusDispositionStatusComplete = MessagingServicebusDispositionStatusKey.String("complete") - // Message is abandoned - MessagingServicebusDispositionStatusAbandon = MessagingServicebusDispositionStatusKey.String("abandon") - // Message is sent to dead letter queue - MessagingServicebusDispositionStatusDeadLetter = MessagingServicebusDispositionStatusKey.String("dead_letter") - // Message is deferred - MessagingServicebusDispositionStatusDefer = MessagingServicebusDispositionStatusKey.String("defer") -) - -// MessagingServicebusDestinationSubscriptionName returns an attribute -// KeyValue conforming to the -// "messaging.servicebus.destination.subscription_name" semantic conventions. -// It represents the name of the subscription in the topic messages are -// received from. -func MessagingServicebusDestinationSubscriptionName(val string) attribute.KeyValue { - return MessagingServicebusDestinationSubscriptionNameKey.String(val) -} - -// MessagingServicebusMessageDeliveryCount returns an attribute KeyValue -// conforming to the "messaging.servicebus.message.delivery_count" semantic -// conventions. It represents the number of deliveries that have been attempted -// for this message. -func MessagingServicebusMessageDeliveryCount(val int) attribute.KeyValue { - return MessagingServicebusMessageDeliveryCountKey.Int(val) -} - -// MessagingServicebusMessageEnqueuedTime returns an attribute KeyValue -// conforming to the "messaging.servicebus.message.enqueued_time" semantic -// conventions. It represents the UTC epoch seconds at which the message has -// been accepted and stored in the entity. -func MessagingServicebusMessageEnqueuedTime(val int) attribute.KeyValue { - return MessagingServicebusMessageEnqueuedTimeKey.Int(val) -} - -// This group describes attributes specific to Azure Event Hubs. -const ( - // MessagingEventhubsConsumerGroupKey is the attribute Key conforming to - // the "messaging.eventhubs.consumer.group" semantic conventions. It - // represents the name of the consumer group the event consumer is - // associated with. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'indexer' - MessagingEventhubsConsumerGroupKey = attribute.Key("messaging.eventhubs.consumer.group") - - // MessagingEventhubsMessageEnqueuedTimeKey is the attribute Key conforming - // to the "messaging.eventhubs.message.enqueued_time" semantic conventions. - // It represents the UTC epoch seconds at which the message has been - // accepted and stored in the entity. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1701393730 - MessagingEventhubsMessageEnqueuedTimeKey = attribute.Key("messaging.eventhubs.message.enqueued_time") -) - -// MessagingEventhubsConsumerGroup returns an attribute KeyValue conforming -// to the "messaging.eventhubs.consumer.group" semantic conventions. It -// represents the name of the consumer group the event consumer is associated -// with. -func MessagingEventhubsConsumerGroup(val string) attribute.KeyValue { - return MessagingEventhubsConsumerGroupKey.String(val) -} - -// MessagingEventhubsMessageEnqueuedTime returns an attribute KeyValue -// conforming to the "messaging.eventhubs.message.enqueued_time" semantic -// conventions. It represents the UTC epoch seconds at which the message has -// been accepted and stored in the entity. -func MessagingEventhubsMessageEnqueuedTime(val int) attribute.KeyValue { - return MessagingEventhubsMessageEnqueuedTimeKey.Int(val) -} - -// These attributes may be used for any network related operation. -const ( - // NetworkCarrierIccKey is the attribute Key conforming to the - // "network.carrier.icc" semantic conventions. It represents the ISO 3166-1 - // alpha-2 2-character country code associated with the mobile carrier - // network. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'DE' - NetworkCarrierIccKey = attribute.Key("network.carrier.icc") - - // NetworkCarrierMccKey is the attribute Key conforming to the - // "network.carrier.mcc" semantic conventions. It represents the mobile - // carrier country code. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '310' - NetworkCarrierMccKey = attribute.Key("network.carrier.mcc") - - // NetworkCarrierMncKey is the attribute Key conforming to the - // "network.carrier.mnc" semantic conventions. It represents the mobile - // carrier network code. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '001' - NetworkCarrierMncKey = attribute.Key("network.carrier.mnc") - - // NetworkCarrierNameKey is the attribute Key conforming to the - // "network.carrier.name" semantic conventions. It represents the name of - // the mobile carrier. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'sprint' - NetworkCarrierNameKey = attribute.Key("network.carrier.name") - - // NetworkConnectionSubtypeKey is the attribute Key conforming to the - // "network.connection.subtype" semantic conventions. It represents the - // this describes more details regarding the connection.type. It may be the - // type of cell technology connection, but it could be used for describing - // details about a wifi connection. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'LTE' - NetworkConnectionSubtypeKey = attribute.Key("network.connection.subtype") - - // NetworkConnectionTypeKey is the attribute Key conforming to the - // "network.connection.type" semantic conventions. It represents the - // internet connection type. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'wifi' - NetworkConnectionTypeKey = attribute.Key("network.connection.type") - - // NetworkIoDirectionKey is the attribute Key conforming to the - // "network.io.direction" semantic conventions. It represents the network - // IO operation direction. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'transmit' - NetworkIoDirectionKey = attribute.Key("network.io.direction") - - // NetworkLocalAddressKey is the attribute Key conforming to the - // "network.local.address" semantic conventions. It represents the local - // address of the network connection - IP address or Unix domain socket - // name. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '10.1.2.80', '/tmp/my.sock' - NetworkLocalAddressKey = attribute.Key("network.local.address") - - // NetworkLocalPortKey is the attribute Key conforming to the - // "network.local.port" semantic conventions. It represents the local port - // number of the network connection. - // - // Type: int - // RequirementLevel: Optional - // Stability: stable - // Examples: 65123 - NetworkLocalPortKey = attribute.Key("network.local.port") - - // NetworkPeerAddressKey is the attribute Key conforming to the - // "network.peer.address" semantic conventions. It represents the peer - // address of the network connection - IP address or Unix domain socket - // name. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '10.1.2.80', '/tmp/my.sock' - NetworkPeerAddressKey = attribute.Key("network.peer.address") - - // NetworkPeerPortKey is the attribute Key conforming to the - // "network.peer.port" semantic conventions. It represents the peer port - // number of the network connection. - // - // Type: int - // RequirementLevel: Optional - // Stability: stable - // Examples: 65123 - NetworkPeerPortKey = attribute.Key("network.peer.port") - - // NetworkProtocolNameKey is the attribute Key conforming to the - // "network.protocol.name" semantic conventions. It represents the [OSI - // application layer](https://osi-model.com/application-layer/) or non-OSI - // equivalent. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'amqp', 'http', 'mqtt' - // Note: The value SHOULD be normalized to lowercase. - NetworkProtocolNameKey = attribute.Key("network.protocol.name") - - // NetworkProtocolVersionKey is the attribute Key conforming to the - // "network.protocol.version" semantic conventions. It represents the - // actual version of the protocol used for network communication. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '1.1', '2' - // Note: If protocol version is subject to negotiation (for example using - // [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute - // SHOULD be set to the negotiated version. If the actual protocol version - // is not known, this attribute SHOULD NOT be set. - NetworkProtocolVersionKey = attribute.Key("network.protocol.version") - - // NetworkTransportKey is the attribute Key conforming to the - // "network.transport" semantic conventions. It represents the [OSI - // transport layer](https://osi-model.com/transport-layer/) or - // [inter-process communication - // method](https://wikipedia.org/wiki/Inter-process_communication). - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'tcp', 'udp' - // Note: The value SHOULD be normalized to lowercase. - // - // Consider always setting the transport when setting a port number, since - // a port number is ambiguous without knowing the transport. For example - // different processes could be listening on TCP port 12345 and UDP port - // 12345. - NetworkTransportKey = attribute.Key("network.transport") - - // NetworkTypeKey is the attribute Key conforming to the "network.type" - // semantic conventions. It represents the [OSI network - // layer](https://osi-model.com/network-layer/) or non-OSI equivalent. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'ipv4', 'ipv6' - // Note: The value SHOULD be normalized to lowercase. - NetworkTypeKey = attribute.Key("network.type") -) - -var ( - // GPRS - NetworkConnectionSubtypeGprs = NetworkConnectionSubtypeKey.String("gprs") - // EDGE - NetworkConnectionSubtypeEdge = NetworkConnectionSubtypeKey.String("edge") - // UMTS - NetworkConnectionSubtypeUmts = NetworkConnectionSubtypeKey.String("umts") - // CDMA - NetworkConnectionSubtypeCdma = NetworkConnectionSubtypeKey.String("cdma") - // EVDO Rel. 0 - NetworkConnectionSubtypeEvdo0 = NetworkConnectionSubtypeKey.String("evdo_0") - // EVDO Rev. A - NetworkConnectionSubtypeEvdoA = NetworkConnectionSubtypeKey.String("evdo_a") - // CDMA2000 1XRTT - NetworkConnectionSubtypeCdma20001xrtt = NetworkConnectionSubtypeKey.String("cdma2000_1xrtt") - // HSDPA - NetworkConnectionSubtypeHsdpa = NetworkConnectionSubtypeKey.String("hsdpa") - // HSUPA - NetworkConnectionSubtypeHsupa = NetworkConnectionSubtypeKey.String("hsupa") - // HSPA - NetworkConnectionSubtypeHspa = NetworkConnectionSubtypeKey.String("hspa") - // IDEN - NetworkConnectionSubtypeIden = NetworkConnectionSubtypeKey.String("iden") - // EVDO Rev. B - NetworkConnectionSubtypeEvdoB = NetworkConnectionSubtypeKey.String("evdo_b") - // LTE - NetworkConnectionSubtypeLte = NetworkConnectionSubtypeKey.String("lte") - // EHRPD - NetworkConnectionSubtypeEhrpd = NetworkConnectionSubtypeKey.String("ehrpd") - // HSPAP - NetworkConnectionSubtypeHspap = NetworkConnectionSubtypeKey.String("hspap") - // GSM - NetworkConnectionSubtypeGsm = NetworkConnectionSubtypeKey.String("gsm") - // TD-SCDMA - NetworkConnectionSubtypeTdScdma = NetworkConnectionSubtypeKey.String("td_scdma") - // IWLAN - NetworkConnectionSubtypeIwlan = NetworkConnectionSubtypeKey.String("iwlan") - // 5G NR (New Radio) - NetworkConnectionSubtypeNr = NetworkConnectionSubtypeKey.String("nr") - // 5G NRNSA (New Radio Non-Standalone) - NetworkConnectionSubtypeNrnsa = NetworkConnectionSubtypeKey.String("nrnsa") - // LTE CA - NetworkConnectionSubtypeLteCa = NetworkConnectionSubtypeKey.String("lte_ca") -) - -var ( - // wifi - NetworkConnectionTypeWifi = NetworkConnectionTypeKey.String("wifi") - // wired - NetworkConnectionTypeWired = NetworkConnectionTypeKey.String("wired") - // cell - NetworkConnectionTypeCell = NetworkConnectionTypeKey.String("cell") - // unavailable - NetworkConnectionTypeUnavailable = NetworkConnectionTypeKey.String("unavailable") - // unknown - NetworkConnectionTypeUnknown = NetworkConnectionTypeKey.String("unknown") -) - -var ( - // transmit - NetworkIoDirectionTransmit = NetworkIoDirectionKey.String("transmit") - // receive - NetworkIoDirectionReceive = NetworkIoDirectionKey.String("receive") -) - -var ( - // TCP - NetworkTransportTCP = NetworkTransportKey.String("tcp") - // UDP - NetworkTransportUDP = NetworkTransportKey.String("udp") - // Named or anonymous pipe - NetworkTransportPipe = NetworkTransportKey.String("pipe") - // Unix domain socket - NetworkTransportUnix = NetworkTransportKey.String("unix") -) - -var ( - // IPv4 - NetworkTypeIpv4 = NetworkTypeKey.String("ipv4") - // IPv6 - NetworkTypeIpv6 = NetworkTypeKey.String("ipv6") -) - -// NetworkCarrierIcc returns an attribute KeyValue conforming to the -// "network.carrier.icc" semantic conventions. It represents the ISO 3166-1 -// alpha-2 2-character country code associated with the mobile carrier network. -func NetworkCarrierIcc(val string) attribute.KeyValue { - return NetworkCarrierIccKey.String(val) -} - -// NetworkCarrierMcc returns an attribute KeyValue conforming to the -// "network.carrier.mcc" semantic conventions. It represents the mobile carrier -// country code. -func NetworkCarrierMcc(val string) attribute.KeyValue { - return NetworkCarrierMccKey.String(val) -} - -// NetworkCarrierMnc returns an attribute KeyValue conforming to the -// "network.carrier.mnc" semantic conventions. It represents the mobile carrier -// network code. -func NetworkCarrierMnc(val string) attribute.KeyValue { - return NetworkCarrierMncKey.String(val) -} - -// NetworkCarrierName returns an attribute KeyValue conforming to the -// "network.carrier.name" semantic conventions. It represents the name of the -// mobile carrier. -func NetworkCarrierName(val string) attribute.KeyValue { - return NetworkCarrierNameKey.String(val) -} - -// NetworkLocalAddress returns an attribute KeyValue conforming to the -// "network.local.address" semantic conventions. It represents the local -// address of the network connection - IP address or Unix domain socket name. -func NetworkLocalAddress(val string) attribute.KeyValue { - return NetworkLocalAddressKey.String(val) -} - -// NetworkLocalPort returns an attribute KeyValue conforming to the -// "network.local.port" semantic conventions. It represents the local port -// number of the network connection. -func NetworkLocalPort(val int) attribute.KeyValue { - return NetworkLocalPortKey.Int(val) -} - -// NetworkPeerAddress returns an attribute KeyValue conforming to the -// "network.peer.address" semantic conventions. It represents the peer address -// of the network connection - IP address or Unix domain socket name. -func NetworkPeerAddress(val string) attribute.KeyValue { - return NetworkPeerAddressKey.String(val) -} - -// NetworkPeerPort returns an attribute KeyValue conforming to the -// "network.peer.port" semantic conventions. It represents the peer port number -// of the network connection. -func NetworkPeerPort(val int) attribute.KeyValue { - return NetworkPeerPortKey.Int(val) -} - -// NetworkProtocolName returns an attribute KeyValue conforming to the -// "network.protocol.name" semantic conventions. It represents the [OSI -// application layer](https://osi-model.com/application-layer/) or non-OSI -// equivalent. -func NetworkProtocolName(val string) attribute.KeyValue { - return NetworkProtocolNameKey.String(val) -} - -// NetworkProtocolVersion returns an attribute KeyValue conforming to the -// "network.protocol.version" semantic conventions. It represents the actual -// version of the protocol used for network communication. -func NetworkProtocolVersion(val string) attribute.KeyValue { - return NetworkProtocolVersionKey.String(val) -} - -// An OCI image manifest. -const ( - // OciManifestDigestKey is the attribute Key conforming to the - // "oci.manifest.digest" semantic conventions. It represents the digest of - // the OCI image manifest. For container images specifically is the digest - // by which the container image is known. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // 'sha256:e4ca62c0d62f3e886e684806dfe9d4e0cda60d54986898173c1083856cfda0f4' - // Note: Follows [OCI Image Manifest - // Specification](https://github.com/opencontainers/image-spec/blob/main/manifest.md), - // and specifically the [Digest - // property](https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests). - // An example can be found in [Example Image - // Manifest](https://docs.docker.com/registry/spec/manifest-v2-2/#example-image-manifest). - OciManifestDigestKey = attribute.Key("oci.manifest.digest") -) - -// OciManifestDigest returns an attribute KeyValue conforming to the -// "oci.manifest.digest" semantic conventions. It represents the digest of the -// OCI image manifest. For container images specifically is the digest by which -// the container image is known. -func OciManifestDigest(val string) attribute.KeyValue { - return OciManifestDigestKey.String(val) -} - -// Attributes used by the OpenTracing Shim layer. -const ( - // OpentracingRefTypeKey is the attribute Key conforming to the - // "opentracing.ref_type" semantic conventions. It represents the - // parent-child Reference type - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Note: The causal relationship between a child Span and a parent Span. - OpentracingRefTypeKey = attribute.Key("opentracing.ref_type") -) - -var ( - // The parent Span depends on the child Span in some capacity - OpentracingRefTypeChildOf = OpentracingRefTypeKey.String("child_of") - // The parent Span doesn't depend in any way on the result of the child Span - OpentracingRefTypeFollowsFrom = OpentracingRefTypeKey.String("follows_from") -) - -// The operating system (OS) on which the process represented by this resource -// is running. -const ( - // OSBuildIDKey is the attribute Key conforming to the "os.build_id" - // semantic conventions. It represents the unique identifier for a - // particular build or compilation of the operating system. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'TQ3C.230805.001.B2', '20E247', '22621' - OSBuildIDKey = attribute.Key("os.build_id") - - // OSDescriptionKey is the attribute Key conforming to the "os.description" - // semantic conventions. It represents the human readable (not intended to - // be parsed) OS version information, like e.g. reported by `ver` or - // `lsb_release -a` commands. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Microsoft Windows [Version 10.0.18363.778]', 'Ubuntu 18.04.1 - // LTS' - OSDescriptionKey = attribute.Key("os.description") - - // OSNameKey is the attribute Key conforming to the "os.name" semantic - // conventions. It represents the human readable operating system name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'iOS', 'Android', 'Ubuntu' - OSNameKey = attribute.Key("os.name") - - // OSTypeKey is the attribute Key conforming to the "os.type" semantic - // conventions. It represents the operating system type. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - OSTypeKey = attribute.Key("os.type") - - // OSVersionKey is the attribute Key conforming to the "os.version" - // semantic conventions. It represents the version string of the operating - // system as defined in [Version - // Attributes](/docs/resource/README.md#version-attributes). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '14.2.1', '18.04.1' - OSVersionKey = attribute.Key("os.version") -) - -var ( - // Microsoft Windows - OSTypeWindows = OSTypeKey.String("windows") - // Linux - OSTypeLinux = OSTypeKey.String("linux") - // Apple Darwin - OSTypeDarwin = OSTypeKey.String("darwin") - // FreeBSD - OSTypeFreeBSD = OSTypeKey.String("freebsd") - // NetBSD - OSTypeNetBSD = OSTypeKey.String("netbsd") - // OpenBSD - OSTypeOpenBSD = OSTypeKey.String("openbsd") - // DragonFly BSD - OSTypeDragonflyBSD = OSTypeKey.String("dragonflybsd") - // HP-UX (Hewlett Packard Unix) - OSTypeHPUX = OSTypeKey.String("hpux") - // AIX (Advanced Interactive eXecutive) - OSTypeAIX = OSTypeKey.String("aix") - // SunOS, Oracle Solaris - OSTypeSolaris = OSTypeKey.String("solaris") - // IBM z/OS - OSTypeZOS = OSTypeKey.String("z_os") -) - -// OSBuildID returns an attribute KeyValue conforming to the "os.build_id" -// semantic conventions. It represents the unique identifier for a particular -// build or compilation of the operating system. -func OSBuildID(val string) attribute.KeyValue { - return OSBuildIDKey.String(val) -} - -// OSDescription returns an attribute KeyValue conforming to the -// "os.description" semantic conventions. It represents the human readable (not -// intended to be parsed) OS version information, like e.g. reported by `ver` -// or `lsb_release -a` commands. -func OSDescription(val string) attribute.KeyValue { - return OSDescriptionKey.String(val) -} - -// OSName returns an attribute KeyValue conforming to the "os.name" semantic -// conventions. It represents the human readable operating system name. -func OSName(val string) attribute.KeyValue { - return OSNameKey.String(val) -} - -// OSVersion returns an attribute KeyValue conforming to the "os.version" -// semantic conventions. It represents the version string of the operating -// system as defined in [Version -// Attributes](/docs/resource/README.md#version-attributes). -func OSVersion(val string) attribute.KeyValue { - return OSVersionKey.String(val) -} - -// Attributes reserved for OpenTelemetry -const ( - // OTelStatusCodeKey is the attribute Key conforming to the - // "otel.status_code" semantic conventions. It represents the name of the - // code, either "OK" or "ERROR". MUST NOT be set if the status code is - // UNSET. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - OTelStatusCodeKey = attribute.Key("otel.status_code") - - // OTelStatusDescriptionKey is the attribute Key conforming to the - // "otel.status_description" semantic conventions. It represents the - // description of the Status if it has a value, otherwise not set. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'resource not found' - OTelStatusDescriptionKey = attribute.Key("otel.status_description") -) - -var ( - // The operation has been validated by an Application developer or Operator to have completed successfully - OTelStatusCodeOk = OTelStatusCodeKey.String("OK") - // The operation contains an error - OTelStatusCodeError = OTelStatusCodeKey.String("ERROR") -) - -// OTelStatusDescription returns an attribute KeyValue conforming to the -// "otel.status_description" semantic conventions. It represents the -// description of the Status if it has a value, otherwise not set. -func OTelStatusDescription(val string) attribute.KeyValue { - return OTelStatusDescriptionKey.String(val) -} - -// Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's -// concepts. -const ( - // OTelScopeNameKey is the attribute Key conforming to the - // "otel.scope.name" semantic conventions. It represents the name of the - // instrumentation scope - (`InstrumentationScope.Name` in OTLP). - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'io.opentelemetry.contrib.mongodb' - OTelScopeNameKey = attribute.Key("otel.scope.name") - - // OTelScopeVersionKey is the attribute Key conforming to the - // "otel.scope.version" semantic conventions. It represents the version of - // the instrumentation scope - (`InstrumentationScope.Version` in OTLP). - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '1.0.0' - OTelScopeVersionKey = attribute.Key("otel.scope.version") -) - -// OTelScopeName returns an attribute KeyValue conforming to the -// "otel.scope.name" semantic conventions. It represents the name of the -// instrumentation scope - (`InstrumentationScope.Name` in OTLP). -func OTelScopeName(val string) attribute.KeyValue { - return OTelScopeNameKey.String(val) -} - -// OTelScopeVersion returns an attribute KeyValue conforming to the -// "otel.scope.version" semantic conventions. It represents the version of the -// instrumentation scope - (`InstrumentationScope.Version` in OTLP). -func OTelScopeVersion(val string) attribute.KeyValue { - return OTelScopeVersionKey.String(val) -} - -// Operations that access some remote service. -const ( - // PeerServiceKey is the attribute Key conforming to the "peer.service" - // semantic conventions. It represents the - // [`service.name`](/docs/resource/README.md#service) of the remote - // service. SHOULD be equal to the actual `service.name` resource attribute - // of the remote service if any. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'AuthTokenCache' - PeerServiceKey = attribute.Key("peer.service") -) - -// PeerService returns an attribute KeyValue conforming to the -// "peer.service" semantic conventions. It represents the -// [`service.name`](/docs/resource/README.md#service) of the remote service. -// SHOULD be equal to the actual `service.name` resource attribute of the -// remote service if any. -func PeerService(val string) attribute.KeyValue { - return PeerServiceKey.String(val) -} - -// An operating system process. -const ( - // ProcessCommandKey is the attribute Key conforming to the - // "process.command" semantic conventions. It represents the command used - // to launch the process (i.e. the command name). On Linux based systems, - // can be set to the zeroth string in `proc/[pid]/cmdline`. On Windows, can - // be set to the first parameter extracted from `GetCommandLineW`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'cmd/otelcol' - ProcessCommandKey = attribute.Key("process.command") - - // ProcessCommandArgsKey is the attribute Key conforming to the - // "process.command_args" semantic conventions. It represents the all the - // command arguments (including the command/executable itself) as received - // by the process. On Linux-based systems (and some other Unixoid systems - // supporting procfs), can be set according to the list of null-delimited - // strings extracted from `proc/[pid]/cmdline`. For libc-based executables, - // this would be the full argv vector passed to `main`. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'cmd/otecol', '--config=config.yaml' - ProcessCommandArgsKey = attribute.Key("process.command_args") - - // ProcessCommandLineKey is the attribute Key conforming to the - // "process.command_line" semantic conventions. It represents the full - // command used to launch the process as a single string representing the - // full command. On Windows, can be set to the result of `GetCommandLineW`. - // Do not set this if you have to assemble it just for monitoring; use - // `process.command_args` instead. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'C:\\cmd\\otecol --config="my directory\\config.yaml"' - ProcessCommandLineKey = attribute.Key("process.command_line") - - // ProcessContextSwitchTypeKey is the attribute Key conforming to the - // "process.context_switch_type" semantic conventions. It represents the - // specifies whether the context switches for this data point were - // voluntary or involuntary. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - ProcessContextSwitchTypeKey = attribute.Key("process.context_switch_type") - - // ProcessCreationTimeKey is the attribute Key conforming to the - // "process.creation.time" semantic conventions. It represents the date and - // time the process was created, in ISO 8601 format. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2023-11-21T09:25:34.853Z' - ProcessCreationTimeKey = attribute.Key("process.creation.time") - - // ProcessExecutableNameKey is the attribute Key conforming to the - // "process.executable.name" semantic conventions. It represents the name - // of the process executable. On Linux based systems, can be set to the - // `Name` in `proc/[pid]/status`. On Windows, can be set to the base name - // of `GetProcessImageFileNameW`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'otelcol' - ProcessExecutableNameKey = attribute.Key("process.executable.name") - - // ProcessExecutablePathKey is the attribute Key conforming to the - // "process.executable.path" semantic conventions. It represents the full - // path to the process executable. On Linux based systems, can be set to - // the target of `proc/[pid]/exe`. On Windows, can be set to the result of - // `GetProcessImageFileNameW`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/usr/bin/cmd/otelcol' - ProcessExecutablePathKey = attribute.Key("process.executable.path") - - // ProcessExitCodeKey is the attribute Key conforming to the - // "process.exit.code" semantic conventions. It represents the exit code of - // the process. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 127 - ProcessExitCodeKey = attribute.Key("process.exit.code") - - // ProcessExitTimeKey is the attribute Key conforming to the - // "process.exit.time" semantic conventions. It represents the date and - // time the process exited, in ISO 8601 format. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2023-11-21T09:26:12.315Z' - ProcessExitTimeKey = attribute.Key("process.exit.time") - - // ProcessGroupLeaderPIDKey is the attribute Key conforming to the - // "process.group_leader.pid" semantic conventions. It represents the PID - // of the process's group leader. This is also the process group ID (PGID) - // of the process. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 23 - ProcessGroupLeaderPIDKey = attribute.Key("process.group_leader.pid") - - // ProcessInteractiveKey is the attribute Key conforming to the - // "process.interactive" semantic conventions. It represents the whether - // the process is connected to an interactive shell. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - ProcessInteractiveKey = attribute.Key("process.interactive") - - // ProcessOwnerKey is the attribute Key conforming to the "process.owner" - // semantic conventions. It represents the username of the user that owns - // the process. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'root' - ProcessOwnerKey = attribute.Key("process.owner") - - // ProcessPagingFaultTypeKey is the attribute Key conforming to the - // "process.paging.fault_type" semantic conventions. It represents the type - // of page fault for this data point. Type `major` is for major/hard page - // faults, and `minor` is for minor/soft page faults. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - ProcessPagingFaultTypeKey = attribute.Key("process.paging.fault_type") - - // ProcessParentPIDKey is the attribute Key conforming to the - // "process.parent_pid" semantic conventions. It represents the parent - // Process identifier (PPID). - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 111 - ProcessParentPIDKey = attribute.Key("process.parent_pid") - - // ProcessPIDKey is the attribute Key conforming to the "process.pid" - // semantic conventions. It represents the process identifier (PID). - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1234 - ProcessPIDKey = attribute.Key("process.pid") - - // ProcessRealUserIDKey is the attribute Key conforming to the - // "process.real_user.id" semantic conventions. It represents the real user - // ID (RUID) of the process. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1000 - ProcessRealUserIDKey = attribute.Key("process.real_user.id") - - // ProcessRealUserNameKey is the attribute Key conforming to the - // "process.real_user.name" semantic conventions. It represents the - // username of the real user of the process. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'operator' - ProcessRealUserNameKey = attribute.Key("process.real_user.name") - - // ProcessRuntimeDescriptionKey is the attribute Key conforming to the - // "process.runtime.description" semantic conventions. It represents an - // additional description about the runtime of the process, for example a - // specific vendor customization of the runtime environment. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Eclipse OpenJ9 Eclipse OpenJ9 VM openj9-0.21.0' - ProcessRuntimeDescriptionKey = attribute.Key("process.runtime.description") - - // ProcessRuntimeNameKey is the attribute Key conforming to the - // "process.runtime.name" semantic conventions. It represents the name of - // the runtime of this process. For compiled native binaries, this SHOULD - // be the name of the compiler. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'OpenJDK Runtime Environment' - ProcessRuntimeNameKey = attribute.Key("process.runtime.name") - - // ProcessRuntimeVersionKey is the attribute Key conforming to the - // "process.runtime.version" semantic conventions. It represents the - // version of the runtime of this process, as returned by the runtime - // without modification. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '14.0.2' - ProcessRuntimeVersionKey = attribute.Key("process.runtime.version") - - // ProcessSavedUserIDKey is the attribute Key conforming to the - // "process.saved_user.id" semantic conventions. It represents the saved - // user ID (SUID) of the process. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1002 - ProcessSavedUserIDKey = attribute.Key("process.saved_user.id") - - // ProcessSavedUserNameKey is the attribute Key conforming to the - // "process.saved_user.name" semantic conventions. It represents the - // username of the saved user. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'operator' - ProcessSavedUserNameKey = attribute.Key("process.saved_user.name") - - // ProcessSessionLeaderPIDKey is the attribute Key conforming to the - // "process.session_leader.pid" semantic conventions. It represents the PID - // of the process's session leader. This is also the session ID (SID) of - // the process. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 14 - ProcessSessionLeaderPIDKey = attribute.Key("process.session_leader.pid") - - // ProcessUserIDKey is the attribute Key conforming to the - // "process.user.id" semantic conventions. It represents the effective user - // ID (EUID) of the process. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1001 - ProcessUserIDKey = attribute.Key("process.user.id") - - // ProcessUserNameKey is the attribute Key conforming to the - // "process.user.name" semantic conventions. It represents the username of - // the effective user of the process. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'root' - ProcessUserNameKey = attribute.Key("process.user.name") - - // ProcessVpidKey is the attribute Key conforming to the "process.vpid" - // semantic conventions. It represents the virtual process identifier. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 12 - // Note: The process ID within a PID namespace. This is not necessarily - // unique across all processes on the host but it is unique within the - // process namespace that the process exists within. - ProcessVpidKey = attribute.Key("process.vpid") -) - -var ( - // voluntary - ProcessContextSwitchTypeVoluntary = ProcessContextSwitchTypeKey.String("voluntary") - // involuntary - ProcessContextSwitchTypeInvoluntary = ProcessContextSwitchTypeKey.String("involuntary") -) - -var ( - // major - ProcessPagingFaultTypeMajor = ProcessPagingFaultTypeKey.String("major") - // minor - ProcessPagingFaultTypeMinor = ProcessPagingFaultTypeKey.String("minor") -) - -// ProcessCommand returns an attribute KeyValue conforming to the -// "process.command" semantic conventions. It represents the command used to -// launch the process (i.e. the command name). On Linux based systems, can be -// set to the zeroth string in `proc/[pid]/cmdline`. On Windows, can be set to -// the first parameter extracted from `GetCommandLineW`. -func ProcessCommand(val string) attribute.KeyValue { - return ProcessCommandKey.String(val) -} - -// ProcessCommandArgs returns an attribute KeyValue conforming to the -// "process.command_args" semantic conventions. It represents the all the -// command arguments (including the command/executable itself) as received by -// the process. On Linux-based systems (and some other Unixoid systems -// supporting procfs), can be set according to the list of null-delimited -// strings extracted from `proc/[pid]/cmdline`. For libc-based executables, -// this would be the full argv vector passed to `main`. -func ProcessCommandArgs(val ...string) attribute.KeyValue { - return ProcessCommandArgsKey.StringSlice(val) -} - -// ProcessCommandLine returns an attribute KeyValue conforming to the -// "process.command_line" semantic conventions. It represents the full command -// used to launch the process as a single string representing the full command. -// On Windows, can be set to the result of `GetCommandLineW`. Do not set this -// if you have to assemble it just for monitoring; use `process.command_args` -// instead. -func ProcessCommandLine(val string) attribute.KeyValue { - return ProcessCommandLineKey.String(val) -} - -// ProcessCreationTime returns an attribute KeyValue conforming to the -// "process.creation.time" semantic conventions. It represents the date and -// time the process was created, in ISO 8601 format. -func ProcessCreationTime(val string) attribute.KeyValue { - return ProcessCreationTimeKey.String(val) -} - -// ProcessExecutableName returns an attribute KeyValue conforming to the -// "process.executable.name" semantic conventions. It represents the name of -// the process executable. On Linux based systems, can be set to the `Name` in -// `proc/[pid]/status`. On Windows, can be set to the base name of -// `GetProcessImageFileNameW`. -func ProcessExecutableName(val string) attribute.KeyValue { - return ProcessExecutableNameKey.String(val) -} - -// ProcessExecutablePath returns an attribute KeyValue conforming to the -// "process.executable.path" semantic conventions. It represents the full path -// to the process executable. On Linux based systems, can be set to the target -// of `proc/[pid]/exe`. On Windows, can be set to the result of -// `GetProcessImageFileNameW`. -func ProcessExecutablePath(val string) attribute.KeyValue { - return ProcessExecutablePathKey.String(val) -} - -// ProcessExitCode returns an attribute KeyValue conforming to the -// "process.exit.code" semantic conventions. It represents the exit code of the -// process. -func ProcessExitCode(val int) attribute.KeyValue { - return ProcessExitCodeKey.Int(val) -} - -// ProcessExitTime returns an attribute KeyValue conforming to the -// "process.exit.time" semantic conventions. It represents the date and time -// the process exited, in ISO 8601 format. -func ProcessExitTime(val string) attribute.KeyValue { - return ProcessExitTimeKey.String(val) -} - -// ProcessGroupLeaderPID returns an attribute KeyValue conforming to the -// "process.group_leader.pid" semantic conventions. It represents the PID of -// the process's group leader. This is also the process group ID (PGID) of the -// process. -func ProcessGroupLeaderPID(val int) attribute.KeyValue { - return ProcessGroupLeaderPIDKey.Int(val) -} - -// ProcessInteractive returns an attribute KeyValue conforming to the -// "process.interactive" semantic conventions. It represents the whether the -// process is connected to an interactive shell. -func ProcessInteractive(val bool) attribute.KeyValue { - return ProcessInteractiveKey.Bool(val) -} - -// ProcessOwner returns an attribute KeyValue conforming to the -// "process.owner" semantic conventions. It represents the username of the user -// that owns the process. -func ProcessOwner(val string) attribute.KeyValue { - return ProcessOwnerKey.String(val) -} - -// ProcessParentPID returns an attribute KeyValue conforming to the -// "process.parent_pid" semantic conventions. It represents the parent Process -// identifier (PPID). -func ProcessParentPID(val int) attribute.KeyValue { - return ProcessParentPIDKey.Int(val) -} - -// ProcessPID returns an attribute KeyValue conforming to the "process.pid" -// semantic conventions. It represents the process identifier (PID). -func ProcessPID(val int) attribute.KeyValue { - return ProcessPIDKey.Int(val) -} - -// ProcessRealUserID returns an attribute KeyValue conforming to the -// "process.real_user.id" semantic conventions. It represents the real user ID -// (RUID) of the process. -func ProcessRealUserID(val int) attribute.KeyValue { - return ProcessRealUserIDKey.Int(val) -} - -// ProcessRealUserName returns an attribute KeyValue conforming to the -// "process.real_user.name" semantic conventions. It represents the username of -// the real user of the process. -func ProcessRealUserName(val string) attribute.KeyValue { - return ProcessRealUserNameKey.String(val) -} - -// ProcessRuntimeDescription returns an attribute KeyValue conforming to the -// "process.runtime.description" semantic conventions. It represents an -// additional description about the runtime of the process, for example a -// specific vendor customization of the runtime environment. -func ProcessRuntimeDescription(val string) attribute.KeyValue { - return ProcessRuntimeDescriptionKey.String(val) -} - -// ProcessRuntimeName returns an attribute KeyValue conforming to the -// "process.runtime.name" semantic conventions. It represents the name of the -// runtime of this process. For compiled native binaries, this SHOULD be the -// name of the compiler. -func ProcessRuntimeName(val string) attribute.KeyValue { - return ProcessRuntimeNameKey.String(val) -} - -// ProcessRuntimeVersion returns an attribute KeyValue conforming to the -// "process.runtime.version" semantic conventions. It represents the version of -// the runtime of this process, as returned by the runtime without -// modification. -func ProcessRuntimeVersion(val string) attribute.KeyValue { - return ProcessRuntimeVersionKey.String(val) -} - -// ProcessSavedUserID returns an attribute KeyValue conforming to the -// "process.saved_user.id" semantic conventions. It represents the saved user -// ID (SUID) of the process. -func ProcessSavedUserID(val int) attribute.KeyValue { - return ProcessSavedUserIDKey.Int(val) -} - -// ProcessSavedUserName returns an attribute KeyValue conforming to the -// "process.saved_user.name" semantic conventions. It represents the username -// of the saved user. -func ProcessSavedUserName(val string) attribute.KeyValue { - return ProcessSavedUserNameKey.String(val) -} - -// ProcessSessionLeaderPID returns an attribute KeyValue conforming to the -// "process.session_leader.pid" semantic conventions. It represents the PID of -// the process's session leader. This is also the session ID (SID) of the -// process. -func ProcessSessionLeaderPID(val int) attribute.KeyValue { - return ProcessSessionLeaderPIDKey.Int(val) -} - -// ProcessUserID returns an attribute KeyValue conforming to the -// "process.user.id" semantic conventions. It represents the effective user ID -// (EUID) of the process. -func ProcessUserID(val int) attribute.KeyValue { - return ProcessUserIDKey.Int(val) -} - -// ProcessUserName returns an attribute KeyValue conforming to the -// "process.user.name" semantic conventions. It represents the username of the -// effective user of the process. -func ProcessUserName(val string) attribute.KeyValue { - return ProcessUserNameKey.String(val) -} - -// ProcessVpid returns an attribute KeyValue conforming to the -// "process.vpid" semantic conventions. It represents the virtual process -// identifier. -func ProcessVpid(val int) attribute.KeyValue { - return ProcessVpidKey.Int(val) -} - -// Attributes for process CPU -const ( - // ProcessCPUStateKey is the attribute Key conforming to the - // "process.cpu.state" semantic conventions. It represents the CPU state of - // the process. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - ProcessCPUStateKey = attribute.Key("process.cpu.state") -) - -var ( - // system - ProcessCPUStateSystem = ProcessCPUStateKey.String("system") - // user - ProcessCPUStateUser = ProcessCPUStateKey.String("user") - // wait - ProcessCPUStateWait = ProcessCPUStateKey.String("wait") -) - -// Attributes for remote procedure calls. -const ( - // RPCConnectRPCErrorCodeKey is the attribute Key conforming to the - // "rpc.connect_rpc.error_code" semantic conventions. It represents the - // [error codes](https://connect.build/docs/protocol/#error-codes) of the - // Connect request. Error codes are always string values. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - RPCConnectRPCErrorCodeKey = attribute.Key("rpc.connect_rpc.error_code") - - // RPCGRPCStatusCodeKey is the attribute Key conforming to the - // "rpc.grpc.status_code" semantic conventions. It represents the [numeric - // status - // code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of - // the gRPC request. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - RPCGRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code") - - // RPCJsonrpcErrorCodeKey is the attribute Key conforming to the - // "rpc.jsonrpc.error_code" semantic conventions. It represents the - // `error.code` property of response if it is an error response. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: -32700, 100 - RPCJsonrpcErrorCodeKey = attribute.Key("rpc.jsonrpc.error_code") - - // RPCJsonrpcErrorMessageKey is the attribute Key conforming to the - // "rpc.jsonrpc.error_message" semantic conventions. It represents the - // `error.message` property of response if it is an error response. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Parse error', 'User already exists' - RPCJsonrpcErrorMessageKey = attribute.Key("rpc.jsonrpc.error_message") - - // RPCJsonrpcRequestIDKey is the attribute Key conforming to the - // "rpc.jsonrpc.request_id" semantic conventions. It represents the `id` - // property of request or response. Since protocol allows id to be int, - // string, `null` or missing (for notifications), value is expected to be - // cast to string for simplicity. Use empty string in case of `null` value. - // Omit entirely if this is a notification. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '10', 'request-7', '' - RPCJsonrpcRequestIDKey = attribute.Key("rpc.jsonrpc.request_id") - - // RPCJsonrpcVersionKey is the attribute Key conforming to the - // "rpc.jsonrpc.version" semantic conventions. It represents the protocol - // version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 - // doesn't specify this, the value can be omitted. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2.0', '1.0' - RPCJsonrpcVersionKey = attribute.Key("rpc.jsonrpc.version") - - // RPCMessageCompressedSizeKey is the attribute Key conforming to the - // "rpc.message.compressed_size" semantic conventions. It represents the - // compressed size of the message in bytes. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - RPCMessageCompressedSizeKey = attribute.Key("rpc.message.compressed_size") - - // RPCMessageIDKey is the attribute Key conforming to the "rpc.message.id" - // semantic conventions. It represents the mUST be calculated as two - // different counters starting from `1` one for sent messages and one for - // received message. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Note: This way we guarantee that the values will be consistent between - // different implementations. - RPCMessageIDKey = attribute.Key("rpc.message.id") - - // RPCMessageTypeKey is the attribute Key conforming to the - // "rpc.message.type" semantic conventions. It represents the whether this - // is a received or sent message. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - RPCMessageTypeKey = attribute.Key("rpc.message.type") - - // RPCMessageUncompressedSizeKey is the attribute Key conforming to the - // "rpc.message.uncompressed_size" semantic conventions. It represents the - // uncompressed size of the message in bytes. - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - RPCMessageUncompressedSizeKey = attribute.Key("rpc.message.uncompressed_size") - - // RPCMethodKey is the attribute Key conforming to the "rpc.method" - // semantic conventions. It represents the name of the (logical) method - // being called, must be equal to the $method part in the span name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'exampleMethod' - // Note: This is the logical name of the method from the RPC interface - // perspective, which can be different from the name of any implementing - // method/function. The `code.function` attribute may be used to store the - // latter (e.g., method actually executing the call on the server side, RPC - // client stub method on the client side). - RPCMethodKey = attribute.Key("rpc.method") - - // RPCServiceKey is the attribute Key conforming to the "rpc.service" - // semantic conventions. It represents the full (logical) name of the - // service being called, including its package name, if applicable. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'myservice.EchoService' - // Note: This is the logical name of the service from the RPC interface - // perspective, which can be different from the name of any implementing - // class. The `code.namespace` attribute may be used to store the latter - // (despite the attribute name, it may include a class name; e.g., class - // with method actually executing the call on the server side, RPC client - // stub class on the client side). - RPCServiceKey = attribute.Key("rpc.service") - - // RPCSystemKey is the attribute Key conforming to the "rpc.system" - // semantic conventions. It represents a string identifying the remoting - // system. See below for a list of well-known identifiers. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - RPCSystemKey = attribute.Key("rpc.system") -) - -var ( - // cancelled - RPCConnectRPCErrorCodeCancelled = RPCConnectRPCErrorCodeKey.String("cancelled") - // unknown - RPCConnectRPCErrorCodeUnknown = RPCConnectRPCErrorCodeKey.String("unknown") - // invalid_argument - RPCConnectRPCErrorCodeInvalidArgument = RPCConnectRPCErrorCodeKey.String("invalid_argument") - // deadline_exceeded - RPCConnectRPCErrorCodeDeadlineExceeded = RPCConnectRPCErrorCodeKey.String("deadline_exceeded") - // not_found - RPCConnectRPCErrorCodeNotFound = RPCConnectRPCErrorCodeKey.String("not_found") - // already_exists - RPCConnectRPCErrorCodeAlreadyExists = RPCConnectRPCErrorCodeKey.String("already_exists") - // permission_denied - RPCConnectRPCErrorCodePermissionDenied = RPCConnectRPCErrorCodeKey.String("permission_denied") - // resource_exhausted - RPCConnectRPCErrorCodeResourceExhausted = RPCConnectRPCErrorCodeKey.String("resource_exhausted") - // failed_precondition - RPCConnectRPCErrorCodeFailedPrecondition = RPCConnectRPCErrorCodeKey.String("failed_precondition") - // aborted - RPCConnectRPCErrorCodeAborted = RPCConnectRPCErrorCodeKey.String("aborted") - // out_of_range - RPCConnectRPCErrorCodeOutOfRange = RPCConnectRPCErrorCodeKey.String("out_of_range") - // unimplemented - RPCConnectRPCErrorCodeUnimplemented = RPCConnectRPCErrorCodeKey.String("unimplemented") - // internal - RPCConnectRPCErrorCodeInternal = RPCConnectRPCErrorCodeKey.String("internal") - // unavailable - RPCConnectRPCErrorCodeUnavailable = RPCConnectRPCErrorCodeKey.String("unavailable") - // data_loss - RPCConnectRPCErrorCodeDataLoss = RPCConnectRPCErrorCodeKey.String("data_loss") - // unauthenticated - RPCConnectRPCErrorCodeUnauthenticated = RPCConnectRPCErrorCodeKey.String("unauthenticated") -) - -var ( - // OK - RPCGRPCStatusCodeOk = RPCGRPCStatusCodeKey.Int(0) - // CANCELLED - RPCGRPCStatusCodeCancelled = RPCGRPCStatusCodeKey.Int(1) - // UNKNOWN - RPCGRPCStatusCodeUnknown = RPCGRPCStatusCodeKey.Int(2) - // INVALID_ARGUMENT - RPCGRPCStatusCodeInvalidArgument = RPCGRPCStatusCodeKey.Int(3) - // DEADLINE_EXCEEDED - RPCGRPCStatusCodeDeadlineExceeded = RPCGRPCStatusCodeKey.Int(4) - // NOT_FOUND - RPCGRPCStatusCodeNotFound = RPCGRPCStatusCodeKey.Int(5) - // ALREADY_EXISTS - RPCGRPCStatusCodeAlreadyExists = RPCGRPCStatusCodeKey.Int(6) - // PERMISSION_DENIED - RPCGRPCStatusCodePermissionDenied = RPCGRPCStatusCodeKey.Int(7) - // RESOURCE_EXHAUSTED - RPCGRPCStatusCodeResourceExhausted = RPCGRPCStatusCodeKey.Int(8) - // FAILED_PRECONDITION - RPCGRPCStatusCodeFailedPrecondition = RPCGRPCStatusCodeKey.Int(9) - // ABORTED - RPCGRPCStatusCodeAborted = RPCGRPCStatusCodeKey.Int(10) - // OUT_OF_RANGE - RPCGRPCStatusCodeOutOfRange = RPCGRPCStatusCodeKey.Int(11) - // UNIMPLEMENTED - RPCGRPCStatusCodeUnimplemented = RPCGRPCStatusCodeKey.Int(12) - // INTERNAL - RPCGRPCStatusCodeInternal = RPCGRPCStatusCodeKey.Int(13) - // UNAVAILABLE - RPCGRPCStatusCodeUnavailable = RPCGRPCStatusCodeKey.Int(14) - // DATA_LOSS - RPCGRPCStatusCodeDataLoss = RPCGRPCStatusCodeKey.Int(15) - // UNAUTHENTICATED - RPCGRPCStatusCodeUnauthenticated = RPCGRPCStatusCodeKey.Int(16) -) - -var ( - // sent - RPCMessageTypeSent = RPCMessageTypeKey.String("SENT") - // received - RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED") -) - -var ( - // gRPC - RPCSystemGRPC = RPCSystemKey.String("grpc") - // Java RMI - RPCSystemJavaRmi = RPCSystemKey.String("java_rmi") - // .NET WCF - RPCSystemDotnetWcf = RPCSystemKey.String("dotnet_wcf") - // Apache Dubbo - RPCSystemApacheDubbo = RPCSystemKey.String("apache_dubbo") - // Connect RPC - RPCSystemConnectRPC = RPCSystemKey.String("connect_rpc") -) - -// RPCJsonrpcErrorCode returns an attribute KeyValue conforming to the -// "rpc.jsonrpc.error_code" semantic conventions. It represents the -// `error.code` property of response if it is an error response. -func RPCJsonrpcErrorCode(val int) attribute.KeyValue { - return RPCJsonrpcErrorCodeKey.Int(val) -} - -// RPCJsonrpcErrorMessage returns an attribute KeyValue conforming to the -// "rpc.jsonrpc.error_message" semantic conventions. It represents the -// `error.message` property of response if it is an error response. -func RPCJsonrpcErrorMessage(val string) attribute.KeyValue { - return RPCJsonrpcErrorMessageKey.String(val) -} - -// RPCJsonrpcRequestID returns an attribute KeyValue conforming to the -// "rpc.jsonrpc.request_id" semantic conventions. It represents the `id` -// property of request or response. Since protocol allows id to be int, string, -// `null` or missing (for notifications), value is expected to be cast to -// string for simplicity. Use empty string in case of `null` value. Omit -// entirely if this is a notification. -func RPCJsonrpcRequestID(val string) attribute.KeyValue { - return RPCJsonrpcRequestIDKey.String(val) -} - -// RPCJsonrpcVersion returns an attribute KeyValue conforming to the -// "rpc.jsonrpc.version" semantic conventions. It represents the protocol -// version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 -// doesn't specify this, the value can be omitted. -func RPCJsonrpcVersion(val string) attribute.KeyValue { - return RPCJsonrpcVersionKey.String(val) -} - -// RPCMessageCompressedSize returns an attribute KeyValue conforming to the -// "rpc.message.compressed_size" semantic conventions. It represents the -// compressed size of the message in bytes. -func RPCMessageCompressedSize(val int) attribute.KeyValue { - return RPCMessageCompressedSizeKey.Int(val) -} - -// RPCMessageID returns an attribute KeyValue conforming to the -// "rpc.message.id" semantic conventions. It represents the mUST be calculated -// as two different counters starting from `1` one for sent messages and one -// for received message. -func RPCMessageID(val int) attribute.KeyValue { - return RPCMessageIDKey.Int(val) -} - -// RPCMessageUncompressedSize returns an attribute KeyValue conforming to -// the "rpc.message.uncompressed_size" semantic conventions. It represents the -// uncompressed size of the message in bytes. -func RPCMessageUncompressedSize(val int) attribute.KeyValue { - return RPCMessageUncompressedSizeKey.Int(val) -} - -// RPCMethod returns an attribute KeyValue conforming to the "rpc.method" -// semantic conventions. It represents the name of the (logical) method being -// called, must be equal to the $method part in the span name. -func RPCMethod(val string) attribute.KeyValue { - return RPCMethodKey.String(val) -} - -// RPCService returns an attribute KeyValue conforming to the "rpc.service" -// semantic conventions. It represents the full (logical) name of the service -// being called, including its package name, if applicable. -func RPCService(val string) attribute.KeyValue { - return RPCServiceKey.String(val) -} - -// These attributes may be used to describe the server in a connection-based -// network interaction where there is one side that initiates the connection -// (the client is the side that initiates the connection). This covers all TCP -// network interactions since TCP is connection-based and one side initiates -// the connection (an exception is made for peer-to-peer communication over TCP -// where the "user-facing" surface of the protocol / API doesn't expose a clear -// notion of client and server). This also covers UDP network interactions -// where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. -const ( - // ServerAddressKey is the attribute Key conforming to the "server.address" - // semantic conventions. It represents the server domain name if available - // without reverse DNS lookup; otherwise, IP address or Unix domain socket - // name. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'example.com', '10.1.2.80', '/tmp/my.sock' - // Note: When observed from the client side, and when communicating through - // an intermediary, `server.address` SHOULD represent the server address - // behind any intermediaries, for example proxies, if it's available. - ServerAddressKey = attribute.Key("server.address") - - // ServerPortKey is the attribute Key conforming to the "server.port" - // semantic conventions. It represents the server port number. - // - // Type: int - // RequirementLevel: Optional - // Stability: stable - // Examples: 80, 8080, 443 - // Note: When observed from the client side, and when communicating through - // an intermediary, `server.port` SHOULD represent the server port behind - // any intermediaries, for example proxies, if it's available. - ServerPortKey = attribute.Key("server.port") -) - -// ServerAddress returns an attribute KeyValue conforming to the -// "server.address" semantic conventions. It represents the server domain name -// if available without reverse DNS lookup; otherwise, IP address or Unix -// domain socket name. -func ServerAddress(val string) attribute.KeyValue { - return ServerAddressKey.String(val) -} - -// ServerPort returns an attribute KeyValue conforming to the "server.port" -// semantic conventions. It represents the server port number. -func ServerPort(val int) attribute.KeyValue { - return ServerPortKey.Int(val) -} - -// A service instance. -const ( - // ServiceInstanceIDKey is the attribute Key conforming to the - // "service.instance.id" semantic conventions. It represents the string ID - // of the service instance. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '627cc493-f310-47de-96bd-71410b7dec09' - // Note: MUST be unique for each instance of the same - // `service.namespace,service.name` pair (in other words - // `service.namespace,service.name,service.instance.id` triplet MUST be - // globally unique). The ID helps to - // distinguish instances of the same service that exist at the same time - // (e.g. instances of a horizontally scaled - // service). - // - // Implementations, such as SDKs, are recommended to generate a random - // Version 1 or Version 4 [RFC - // 4122](https://www.ietf.org/rfc/rfc4122.txt) UUID, but are free to use an - // inherent unique ID as the source of - // this value if stability is desirable. In that case, the ID SHOULD be - // used as source of a UUID Version 5 and - // SHOULD use the following UUID as the namespace: - // `4d63009a-8d0f-11ee-aad7-4c796ed8e320`. - // - // UUIDs are typically recommended, as only an opaque value for the - // purposes of identifying a service instance is - // needed. Similar to what can be seen in the man page for the - // [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html) - // file, the underlying - // data, such as pod name and namespace should be treated as confidential, - // being the user's choice to expose it - // or not via another resource attribute. - // - // For applications running behind an application server (like unicorn), we - // do not recommend using one identifier - // for all processes participating in the application. Instead, it's - // recommended each division (e.g. a worker - // thread in unicorn) to have its own instance.id. - // - // It's not recommended for a Collector to set `service.instance.id` if it - // can't unambiguously determine the - // service instance that is generating that telemetry. For instance, - // creating an UUID based on `pod.name` will - // likely be wrong, as the Collector might not know from which container - // within that pod the telemetry originated. - // However, Collectors can set the `service.instance.id` if they can - // unambiguously determine the service instance - // for that telemetry. This is typically the case for scraping receivers, - // as they know the target address and - // port. - ServiceInstanceIDKey = attribute.Key("service.instance.id") - - // ServiceNameKey is the attribute Key conforming to the "service.name" - // semantic conventions. It represents the logical name of the service. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'shoppingcart' - // Note: MUST be the same for all instances of horizontally scaled - // services. If the value was not specified, SDKs MUST fallback to - // `unknown_service:` concatenated with - // [`process.executable.name`](process.md), e.g. `unknown_service:bash`. If - // `process.executable.name` is not available, the value MUST be set to - // `unknown_service`. - ServiceNameKey = attribute.Key("service.name") - - // ServiceNamespaceKey is the attribute Key conforming to the - // "service.namespace" semantic conventions. It represents a namespace for - // `service.name`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Shop' - // Note: A string value having a meaning that helps to distinguish a group - // of services, for example the team name that owns a group of services. - // `service.name` is expected to be unique within the same namespace. If - // `service.namespace` is not specified in the Resource then `service.name` - // is expected to be unique for all services that have no explicit - // namespace defined (so the empty/unspecified namespace is simply one more - // valid namespace). Zero-length namespace string is assumed equal to - // unspecified namespace. - ServiceNamespaceKey = attribute.Key("service.namespace") - - // ServiceVersionKey is the attribute Key conforming to the - // "service.version" semantic conventions. It represents the version string - // of the service API or implementation. The format is not defined by these - // conventions. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '2.0.0', 'a01dbef8a' - ServiceVersionKey = attribute.Key("service.version") -) - -// ServiceInstanceID returns an attribute KeyValue conforming to the -// "service.instance.id" semantic conventions. It represents the string ID of -// the service instance. -func ServiceInstanceID(val string) attribute.KeyValue { - return ServiceInstanceIDKey.String(val) -} - -// ServiceName returns an attribute KeyValue conforming to the -// "service.name" semantic conventions. It represents the logical name of the -// service. -func ServiceName(val string) attribute.KeyValue { - return ServiceNameKey.String(val) -} - -// ServiceNamespace returns an attribute KeyValue conforming to the -// "service.namespace" semantic conventions. It represents a namespace for -// `service.name`. -func ServiceNamespace(val string) attribute.KeyValue { - return ServiceNamespaceKey.String(val) -} - -// ServiceVersion returns an attribute KeyValue conforming to the -// "service.version" semantic conventions. It represents the version string of -// the service API or implementation. The format is not defined by these -// conventions. -func ServiceVersion(val string) attribute.KeyValue { - return ServiceVersionKey.String(val) -} - -// Session is defined as the period of time encompassing all activities -// performed by the application and the actions executed by the end user. -// Consequently, a Session is represented as a collection of Logs, Events, and -// Spans emitted by the Client Application throughout the Session's duration. -// Each Session is assigned a unique identifier, which is included as an -// attribute in the Logs, Events, and Spans generated during the Session's -// lifecycle. -// When a session reaches end of life, typically due to user inactivity or -// session timeout, a new session identifier will be assigned. The previous -// session identifier may be provided by the instrumentation so that telemetry -// backends can link the two sessions. -const ( - // SessionIDKey is the attribute Key conforming to the "session.id" - // semantic conventions. It represents a unique id to identify a session. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '00112233-4455-6677-8899-aabbccddeeff' - SessionIDKey = attribute.Key("session.id") - - // SessionPreviousIDKey is the attribute Key conforming to the - // "session.previous_id" semantic conventions. It represents the previous - // `session.id` for this user, when known. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '00112233-4455-6677-8899-aabbccddeeff' - SessionPreviousIDKey = attribute.Key("session.previous_id") -) - -// SessionID returns an attribute KeyValue conforming to the "session.id" -// semantic conventions. It represents a unique id to identify a session. -func SessionID(val string) attribute.KeyValue { - return SessionIDKey.String(val) -} - -// SessionPreviousID returns an attribute KeyValue conforming to the -// "session.previous_id" semantic conventions. It represents the previous -// `session.id` for this user, when known. -func SessionPreviousID(val string) attribute.KeyValue { - return SessionPreviousIDKey.String(val) -} - -// SignalR attributes -const ( - // SignalrConnectionStatusKey is the attribute Key conforming to the - // "signalr.connection.status" semantic conventions. It represents the - // signalR HTTP connection closure status. - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'app_shutdown', 'timeout' - SignalrConnectionStatusKey = attribute.Key("signalr.connection.status") - - // SignalrTransportKey is the attribute Key conforming to the - // "signalr.transport" semantic conventions. It represents the [SignalR - // transport - // type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md) - // - // Type: Enum - // RequirementLevel: Optional - // Stability: stable - // Examples: 'web_sockets', 'long_polling' - SignalrTransportKey = attribute.Key("signalr.transport") -) - -var ( - // The connection was closed normally - SignalrConnectionStatusNormalClosure = SignalrConnectionStatusKey.String("normal_closure") - // The connection was closed due to a timeout - SignalrConnectionStatusTimeout = SignalrConnectionStatusKey.String("timeout") - // The connection was closed because the app is shutting down - SignalrConnectionStatusAppShutdown = SignalrConnectionStatusKey.String("app_shutdown") -) - -var ( - // ServerSentEvents protocol - SignalrTransportServerSentEvents = SignalrTransportKey.String("server_sent_events") - // LongPolling protocol - SignalrTransportLongPolling = SignalrTransportKey.String("long_polling") - // WebSockets protocol - SignalrTransportWebSockets = SignalrTransportKey.String("web_sockets") -) - -// These attributes may be used to describe the sender of a network -// exchange/packet. These should be used when there is no client/server -// relationship between the two sides, or when that relationship is unknown. -// This covers low-level network interactions (e.g. packet tracing) where you -// don't know if there was a connection or which side initiated it. This also -// covers unidirectional UDP flows and peer-to-peer communication where the -// "user-facing" surface of the protocol / API doesn't expose a clear notion of -// client and server. -const ( - // SourceAddressKey is the attribute Key conforming to the "source.address" - // semantic conventions. It represents the source address - domain name if - // available without reverse DNS lookup; otherwise, IP address or Unix - // domain socket name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'source.example.com', '10.1.2.80', '/tmp/my.sock' - // Note: When observed from the destination side, and when communicating - // through an intermediary, `source.address` SHOULD represent the source - // address behind any intermediaries, for example proxies, if it's - // available. - SourceAddressKey = attribute.Key("source.address") - - // SourcePortKey is the attribute Key conforming to the "source.port" - // semantic conventions. It represents the source port number - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 3389, 2888 - SourcePortKey = attribute.Key("source.port") -) - -// SourceAddress returns an attribute KeyValue conforming to the -// "source.address" semantic conventions. It represents the source address - -// domain name if available without reverse DNS lookup; otherwise, IP address -// or Unix domain socket name. -func SourceAddress(val string) attribute.KeyValue { - return SourceAddressKey.String(val) -} - -// SourcePort returns an attribute KeyValue conforming to the "source.port" -// semantic conventions. It represents the source port number -func SourcePort(val int) attribute.KeyValue { - return SourcePortKey.Int(val) -} - -// Describes System attributes -const ( - // SystemDeviceKey is the attribute Key conforming to the "system.device" - // semantic conventions. It represents the device identifier - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '(identifier)' - SystemDeviceKey = attribute.Key("system.device") -) - -// SystemDevice returns an attribute KeyValue conforming to the -// "system.device" semantic conventions. It represents the device identifier -func SystemDevice(val string) attribute.KeyValue { - return SystemDeviceKey.String(val) -} - -// Describes System CPU attributes -const ( - // SystemCPULogicalNumberKey is the attribute Key conforming to the - // "system.cpu.logical_number" semantic conventions. It represents the - // logical CPU number [0..n-1] - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 1 - SystemCPULogicalNumberKey = attribute.Key("system.cpu.logical_number") - - // SystemCPUStateKey is the attribute Key conforming to the - // "system.cpu.state" semantic conventions. It represents the state of the - // CPU - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'idle', 'interrupt' - SystemCPUStateKey = attribute.Key("system.cpu.state") -) - -var ( - // user - SystemCPUStateUser = SystemCPUStateKey.String("user") - // system - SystemCPUStateSystem = SystemCPUStateKey.String("system") - // nice - SystemCPUStateNice = SystemCPUStateKey.String("nice") - // idle - SystemCPUStateIdle = SystemCPUStateKey.String("idle") - // iowait - SystemCPUStateIowait = SystemCPUStateKey.String("iowait") - // interrupt - SystemCPUStateInterrupt = SystemCPUStateKey.String("interrupt") - // steal - SystemCPUStateSteal = SystemCPUStateKey.String("steal") -) - -// SystemCPULogicalNumber returns an attribute KeyValue conforming to the -// "system.cpu.logical_number" semantic conventions. It represents the logical -// CPU number [0..n-1] -func SystemCPULogicalNumber(val int) attribute.KeyValue { - return SystemCPULogicalNumberKey.Int(val) -} - -// Describes System Memory attributes -const ( - // SystemMemoryStateKey is the attribute Key conforming to the - // "system.memory.state" semantic conventions. It represents the memory - // state - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'free', 'cached' - SystemMemoryStateKey = attribute.Key("system.memory.state") -) - -var ( - // used - SystemMemoryStateUsed = SystemMemoryStateKey.String("used") - // free - SystemMemoryStateFree = SystemMemoryStateKey.String("free") - // shared - SystemMemoryStateShared = SystemMemoryStateKey.String("shared") - // buffers - SystemMemoryStateBuffers = SystemMemoryStateKey.String("buffers") - // cached - SystemMemoryStateCached = SystemMemoryStateKey.String("cached") -) - -// Describes System Memory Paging attributes -const ( - // SystemPagingDirectionKey is the attribute Key conforming to the - // "system.paging.direction" semantic conventions. It represents the paging - // access direction - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'in' - SystemPagingDirectionKey = attribute.Key("system.paging.direction") - - // SystemPagingStateKey is the attribute Key conforming to the - // "system.paging.state" semantic conventions. It represents the memory - // paging state - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'free' - SystemPagingStateKey = attribute.Key("system.paging.state") - - // SystemPagingTypeKey is the attribute Key conforming to the - // "system.paging.type" semantic conventions. It represents the memory - // paging type - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'minor' - SystemPagingTypeKey = attribute.Key("system.paging.type") -) - -var ( - // in - SystemPagingDirectionIn = SystemPagingDirectionKey.String("in") - // out - SystemPagingDirectionOut = SystemPagingDirectionKey.String("out") -) - -var ( - // used - SystemPagingStateUsed = SystemPagingStateKey.String("used") - // free - SystemPagingStateFree = SystemPagingStateKey.String("free") -) - -var ( - // major - SystemPagingTypeMajor = SystemPagingTypeKey.String("major") - // minor - SystemPagingTypeMinor = SystemPagingTypeKey.String("minor") -) - -// Describes Filesystem attributes -const ( - // SystemFilesystemModeKey is the attribute Key conforming to the - // "system.filesystem.mode" semantic conventions. It represents the - // filesystem mode - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'rw, ro' - SystemFilesystemModeKey = attribute.Key("system.filesystem.mode") - - // SystemFilesystemMountpointKey is the attribute Key conforming to the - // "system.filesystem.mountpoint" semantic conventions. It represents the - // filesystem mount path - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/mnt/data' - SystemFilesystemMountpointKey = attribute.Key("system.filesystem.mountpoint") - - // SystemFilesystemStateKey is the attribute Key conforming to the - // "system.filesystem.state" semantic conventions. It represents the - // filesystem state - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'used' - SystemFilesystemStateKey = attribute.Key("system.filesystem.state") - - // SystemFilesystemTypeKey is the attribute Key conforming to the - // "system.filesystem.type" semantic conventions. It represents the - // filesystem type - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'ext4' - SystemFilesystemTypeKey = attribute.Key("system.filesystem.type") -) - -var ( - // used - SystemFilesystemStateUsed = SystemFilesystemStateKey.String("used") - // free - SystemFilesystemStateFree = SystemFilesystemStateKey.String("free") - // reserved - SystemFilesystemStateReserved = SystemFilesystemStateKey.String("reserved") -) - -var ( - // fat32 - SystemFilesystemTypeFat32 = SystemFilesystemTypeKey.String("fat32") - // exfat - SystemFilesystemTypeExfat = SystemFilesystemTypeKey.String("exfat") - // ntfs - SystemFilesystemTypeNtfs = SystemFilesystemTypeKey.String("ntfs") - // refs - SystemFilesystemTypeRefs = SystemFilesystemTypeKey.String("refs") - // hfsplus - SystemFilesystemTypeHfsplus = SystemFilesystemTypeKey.String("hfsplus") - // ext4 - SystemFilesystemTypeExt4 = SystemFilesystemTypeKey.String("ext4") -) - -// SystemFilesystemMode returns an attribute KeyValue conforming to the -// "system.filesystem.mode" semantic conventions. It represents the filesystem -// mode -func SystemFilesystemMode(val string) attribute.KeyValue { - return SystemFilesystemModeKey.String(val) -} - -// SystemFilesystemMountpoint returns an attribute KeyValue conforming to -// the "system.filesystem.mountpoint" semantic conventions. It represents the -// filesystem mount path -func SystemFilesystemMountpoint(val string) attribute.KeyValue { - return SystemFilesystemMountpointKey.String(val) -} - -// Describes Network attributes -const ( - // SystemNetworkStateKey is the attribute Key conforming to the - // "system.network.state" semantic conventions. It represents a stateless - // protocol MUST NOT set this attribute - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'close_wait' - SystemNetworkStateKey = attribute.Key("system.network.state") -) - -var ( - // close - SystemNetworkStateClose = SystemNetworkStateKey.String("close") - // close_wait - SystemNetworkStateCloseWait = SystemNetworkStateKey.String("close_wait") - // closing - SystemNetworkStateClosing = SystemNetworkStateKey.String("closing") - // delete - SystemNetworkStateDelete = SystemNetworkStateKey.String("delete") - // established - SystemNetworkStateEstablished = SystemNetworkStateKey.String("established") - // fin_wait_1 - SystemNetworkStateFinWait1 = SystemNetworkStateKey.String("fin_wait_1") - // fin_wait_2 - SystemNetworkStateFinWait2 = SystemNetworkStateKey.String("fin_wait_2") - // last_ack - SystemNetworkStateLastAck = SystemNetworkStateKey.String("last_ack") - // listen - SystemNetworkStateListen = SystemNetworkStateKey.String("listen") - // syn_recv - SystemNetworkStateSynRecv = SystemNetworkStateKey.String("syn_recv") - // syn_sent - SystemNetworkStateSynSent = SystemNetworkStateKey.String("syn_sent") - // time_wait - SystemNetworkStateTimeWait = SystemNetworkStateKey.String("time_wait") -) - -// Describes System Process attributes -const ( - // SystemProcessStatusKey is the attribute Key conforming to the - // "system.process.status" semantic conventions. It represents the process - // state, e.g., [Linux Process State - // Codes](https://man7.org/linux/man-pages/man1/ps.1.html#PROCESS_STATE_CODES) - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'running' - SystemProcessStatusKey = attribute.Key("system.process.status") -) - -var ( - // running - SystemProcessStatusRunning = SystemProcessStatusKey.String("running") - // sleeping - SystemProcessStatusSleeping = SystemProcessStatusKey.String("sleeping") - // stopped - SystemProcessStatusStopped = SystemProcessStatusKey.String("stopped") - // defunct - SystemProcessStatusDefunct = SystemProcessStatusKey.String("defunct") -) - -// Attributes for telemetry SDK. -const ( - // TelemetrySDKLanguageKey is the attribute Key conforming to the - // "telemetry.sdk.language" semantic conventions. It represents the - // language of the telemetry SDK. - // - // Type: Enum - // RequirementLevel: Required - // Stability: stable - TelemetrySDKLanguageKey = attribute.Key("telemetry.sdk.language") - - // TelemetrySDKNameKey is the attribute Key conforming to the - // "telemetry.sdk.name" semantic conventions. It represents the name of the - // telemetry SDK as defined above. - // - // Type: string - // RequirementLevel: Required - // Stability: stable - // Examples: 'opentelemetry' - // Note: The OpenTelemetry SDK MUST set the `telemetry.sdk.name` attribute - // to `opentelemetry`. - // If another SDK, like a fork or a vendor-provided implementation, is - // used, this SDK MUST set the - // `telemetry.sdk.name` attribute to the fully-qualified class or module - // name of this SDK's main entry point - // or another suitable identifier depending on the language. - // The identifier `opentelemetry` is reserved and MUST NOT be used in this - // case. - // All custom identifiers SHOULD be stable across different versions of an - // implementation. - TelemetrySDKNameKey = attribute.Key("telemetry.sdk.name") - - // TelemetrySDKVersionKey is the attribute Key conforming to the - // "telemetry.sdk.version" semantic conventions. It represents the version - // string of the telemetry SDK. - // - // Type: string - // RequirementLevel: Required - // Stability: stable - // Examples: '1.2.3' - TelemetrySDKVersionKey = attribute.Key("telemetry.sdk.version") - - // TelemetryDistroNameKey is the attribute Key conforming to the - // "telemetry.distro.name" semantic conventions. It represents the name of - // the auto instrumentation agent or distribution, if used. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'parts-unlimited-java' - // Note: Official auto instrumentation agents and distributions SHOULD set - // the `telemetry.distro.name` attribute to - // a string starting with `opentelemetry-`, e.g. - // `opentelemetry-java-instrumentation`. - TelemetryDistroNameKey = attribute.Key("telemetry.distro.name") - - // TelemetryDistroVersionKey is the attribute Key conforming to the - // "telemetry.distro.version" semantic conventions. It represents the - // version string of the auto instrumentation agent or distribution, if - // used. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1.2.3' - TelemetryDistroVersionKey = attribute.Key("telemetry.distro.version") -) - -var ( - // cpp - TelemetrySDKLanguageCPP = TelemetrySDKLanguageKey.String("cpp") - // dotnet - TelemetrySDKLanguageDotnet = TelemetrySDKLanguageKey.String("dotnet") - // erlang - TelemetrySDKLanguageErlang = TelemetrySDKLanguageKey.String("erlang") - // go - TelemetrySDKLanguageGo = TelemetrySDKLanguageKey.String("go") - // java - TelemetrySDKLanguageJava = TelemetrySDKLanguageKey.String("java") - // nodejs - TelemetrySDKLanguageNodejs = TelemetrySDKLanguageKey.String("nodejs") - // php - TelemetrySDKLanguagePHP = TelemetrySDKLanguageKey.String("php") - // python - TelemetrySDKLanguagePython = TelemetrySDKLanguageKey.String("python") - // ruby - TelemetrySDKLanguageRuby = TelemetrySDKLanguageKey.String("ruby") - // rust - TelemetrySDKLanguageRust = TelemetrySDKLanguageKey.String("rust") - // swift - TelemetrySDKLanguageSwift = TelemetrySDKLanguageKey.String("swift") - // webjs - TelemetrySDKLanguageWebjs = TelemetrySDKLanguageKey.String("webjs") -) - -// TelemetrySDKName returns an attribute KeyValue conforming to the -// "telemetry.sdk.name" semantic conventions. It represents the name of the -// telemetry SDK as defined above. -func TelemetrySDKName(val string) attribute.KeyValue { - return TelemetrySDKNameKey.String(val) -} - -// TelemetrySDKVersion returns an attribute KeyValue conforming to the -// "telemetry.sdk.version" semantic conventions. It represents the version -// string of the telemetry SDK. -func TelemetrySDKVersion(val string) attribute.KeyValue { - return TelemetrySDKVersionKey.String(val) -} - -// TelemetryDistroName returns an attribute KeyValue conforming to the -// "telemetry.distro.name" semantic conventions. It represents the name of the -// auto instrumentation agent or distribution, if used. -func TelemetryDistroName(val string) attribute.KeyValue { - return TelemetryDistroNameKey.String(val) -} - -// TelemetryDistroVersion returns an attribute KeyValue conforming to the -// "telemetry.distro.version" semantic conventions. It represents the version -// string of the auto instrumentation agent or distribution, if used. -func TelemetryDistroVersion(val string) attribute.KeyValue { - return TelemetryDistroVersionKey.String(val) -} - -// These attributes may be used for any operation to store information about a -// thread that started a span. -const ( - // ThreadIDKey is the attribute Key conforming to the "thread.id" semantic - // conventions. It represents the current "managed" thread ID (as opposed - // to OS thread ID). - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 42 - ThreadIDKey = attribute.Key("thread.id") - - // ThreadNameKey is the attribute Key conforming to the "thread.name" - // semantic conventions. It represents the current thread name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'main' - ThreadNameKey = attribute.Key("thread.name") -) - -// ThreadID returns an attribute KeyValue conforming to the "thread.id" -// semantic conventions. It represents the current "managed" thread ID (as -// opposed to OS thread ID). -func ThreadID(val int) attribute.KeyValue { - return ThreadIDKey.Int(val) -} - -// ThreadName returns an attribute KeyValue conforming to the "thread.name" -// semantic conventions. It represents the current thread name. -func ThreadName(val string) attribute.KeyValue { - return ThreadNameKey.String(val) -} - -// Semantic convention attributes in the TLS namespace. -const ( - // TLSCipherKey is the attribute Key conforming to the "tls.cipher" - // semantic conventions. It represents the string indicating the - // [cipher](https://datatracker.ietf.org/doc/html/rfc5246#appendix-A.5) - // used during the current connection. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'TLS_RSA_WITH_3DES_EDE_CBC_SHA', - // 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256' - // Note: The values allowed for `tls.cipher` MUST be one of the - // `Descriptions` of the [registered TLS Cipher - // Suits](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#table-tls-parameters-4). - TLSCipherKey = attribute.Key("tls.cipher") - - // TLSClientCertificateKey is the attribute Key conforming to the - // "tls.client.certificate" semantic conventions. It represents the - // pEM-encoded stand-alone certificate offered by the client. This is - // usually mutually-exclusive of `client.certificate_chain` since this - // value also exists in that list. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MII...' - TLSClientCertificateKey = attribute.Key("tls.client.certificate") - - // TLSClientCertificateChainKey is the attribute Key conforming to the - // "tls.client.certificate_chain" semantic conventions. It represents the - // array of PEM-encoded certificates that make up the certificate chain - // offered by the client. This is usually mutually-exclusive of - // `client.certificate` since that value should be the first certificate in - // the chain. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MII...', 'MI...' - TLSClientCertificateChainKey = attribute.Key("tls.client.certificate_chain") - - // TLSClientHashMd5Key is the attribute Key conforming to the - // "tls.client.hash.md5" semantic conventions. It represents the - // certificate fingerprint using the MD5 digest of DER-encoded version of - // certificate offered by the client. For consistency with other hash - // values, this value should be formatted as an uppercase hash. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC' - TLSClientHashMd5Key = attribute.Key("tls.client.hash.md5") - - // TLSClientHashSha1Key is the attribute Key conforming to the - // "tls.client.hash.sha1" semantic conventions. It represents the - // certificate fingerprint using the SHA1 digest of DER-encoded version of - // certificate offered by the client. For consistency with other hash - // values, this value should be formatted as an uppercase hash. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '9E393D93138888D288266C2D915214D1D1CCEB2A' - TLSClientHashSha1Key = attribute.Key("tls.client.hash.sha1") - - // TLSClientHashSha256Key is the attribute Key conforming to the - // "tls.client.hash.sha256" semantic conventions. It represents the - // certificate fingerprint using the SHA256 digest of DER-encoded version - // of certificate offered by the client. For consistency with other hash - // values, this value should be formatted as an uppercase hash. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0' - TLSClientHashSha256Key = attribute.Key("tls.client.hash.sha256") - - // TLSClientIssuerKey is the attribute Key conforming to the - // "tls.client.issuer" semantic conventions. It represents the - // distinguished name of - // [subject](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) - // of the issuer of the x.509 certificate presented by the client. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'CN=Example Root CA, OU=Infrastructure Team, DC=example, - // DC=com' - TLSClientIssuerKey = attribute.Key("tls.client.issuer") - - // TLSClientJa3Key is the attribute Key conforming to the "tls.client.ja3" - // semantic conventions. It represents a hash that identifies clients based - // on how they perform an SSL/TLS handshake. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'd4e5b18d6b55c71272893221c96ba240' - TLSClientJa3Key = attribute.Key("tls.client.ja3") - - // TLSClientNotAfterKey is the attribute Key conforming to the - // "tls.client.not_after" semantic conventions. It represents the date/Time - // indicating when client certificate is no longer considered valid. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2021-01-01T00:00:00.000Z' - TLSClientNotAfterKey = attribute.Key("tls.client.not_after") - - // TLSClientNotBeforeKey is the attribute Key conforming to the - // "tls.client.not_before" semantic conventions. It represents the - // date/Time indicating when client certificate is first considered valid. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1970-01-01T00:00:00.000Z' - TLSClientNotBeforeKey = attribute.Key("tls.client.not_before") - - // TLSClientServerNameKey is the attribute Key conforming to the - // "tls.client.server_name" semantic conventions. It represents the also - // called an SNI, this tells the server which hostname to which the client - // is attempting to connect to. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'opentelemetry.io' - TLSClientServerNameKey = attribute.Key("tls.client.server_name") - - // TLSClientSubjectKey is the attribute Key conforming to the - // "tls.client.subject" semantic conventions. It represents the - // distinguished name of subject of the x.509 certificate presented by the - // client. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'CN=myclient, OU=Documentation Team, DC=example, DC=com' - TLSClientSubjectKey = attribute.Key("tls.client.subject") - - // TLSClientSupportedCiphersKey is the attribute Key conforming to the - // "tls.client.supported_ciphers" semantic conventions. It represents the - // array of ciphers offered by the client during the client hello. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: '"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - // "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "..."' - TLSClientSupportedCiphersKey = attribute.Key("tls.client.supported_ciphers") - - // TLSCurveKey is the attribute Key conforming to the "tls.curve" semantic - // conventions. It represents the string indicating the curve used for the - // given cipher, when applicable - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'secp256r1' - TLSCurveKey = attribute.Key("tls.curve") - - // TLSEstablishedKey is the attribute Key conforming to the - // "tls.established" semantic conventions. It represents the boolean flag - // indicating if the TLS negotiation was successful and transitioned to an - // encrypted tunnel. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - // Examples: True - TLSEstablishedKey = attribute.Key("tls.established") - - // TLSNextProtocolKey is the attribute Key conforming to the - // "tls.next_protocol" semantic conventions. It represents the string - // indicating the protocol being tunneled. Per the values in the [IANA - // registry](https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids), - // this string should be lower case. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'http/1.1' - TLSNextProtocolKey = attribute.Key("tls.next_protocol") - - // TLSProtocolNameKey is the attribute Key conforming to the - // "tls.protocol.name" semantic conventions. It represents the normalized - // lowercase protocol name parsed from original string of the negotiated - // [SSL/TLS protocol - // version](https://www.openssl.org/docs/man1.1.1/man3/SSL_get_version.html#RETURN-VALUES) - // - // Type: Enum - // RequirementLevel: Optional - // Stability: experimental - TLSProtocolNameKey = attribute.Key("tls.protocol.name") - - // TLSProtocolVersionKey is the attribute Key conforming to the - // "tls.protocol.version" semantic conventions. It represents the numeric - // part of the version parsed from the original string of the negotiated - // [SSL/TLS protocol - // version](https://www.openssl.org/docs/man1.1.1/man3/SSL_get_version.html#RETURN-VALUES) - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1.2', '3' - TLSProtocolVersionKey = attribute.Key("tls.protocol.version") - - // TLSResumedKey is the attribute Key conforming to the "tls.resumed" - // semantic conventions. It represents the boolean flag indicating if this - // TLS connection was resumed from an existing TLS negotiation. - // - // Type: boolean - // RequirementLevel: Optional - // Stability: experimental - // Examples: True - TLSResumedKey = attribute.Key("tls.resumed") - - // TLSServerCertificateKey is the attribute Key conforming to the - // "tls.server.certificate" semantic conventions. It represents the - // pEM-encoded stand-alone certificate offered by the server. This is - // usually mutually-exclusive of `server.certificate_chain` since this - // value also exists in that list. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MII...' - TLSServerCertificateKey = attribute.Key("tls.server.certificate") - - // TLSServerCertificateChainKey is the attribute Key conforming to the - // "tls.server.certificate_chain" semantic conventions. It represents the - // array of PEM-encoded certificates that make up the certificate chain - // offered by the server. This is usually mutually-exclusive of - // `server.certificate` since that value should be the first certificate in - // the chain. - // - // Type: string[] - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'MII...', 'MI...' - TLSServerCertificateChainKey = attribute.Key("tls.server.certificate_chain") - - // TLSServerHashMd5Key is the attribute Key conforming to the - // "tls.server.hash.md5" semantic conventions. It represents the - // certificate fingerprint using the MD5 digest of DER-encoded version of - // certificate offered by the server. For consistency with other hash - // values, this value should be formatted as an uppercase hash. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC' - TLSServerHashMd5Key = attribute.Key("tls.server.hash.md5") - - // TLSServerHashSha1Key is the attribute Key conforming to the - // "tls.server.hash.sha1" semantic conventions. It represents the - // certificate fingerprint using the SHA1 digest of DER-encoded version of - // certificate offered by the server. For consistency with other hash - // values, this value should be formatted as an uppercase hash. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '9E393D93138888D288266C2D915214D1D1CCEB2A' - TLSServerHashSha1Key = attribute.Key("tls.server.hash.sha1") - - // TLSServerHashSha256Key is the attribute Key conforming to the - // "tls.server.hash.sha256" semantic conventions. It represents the - // certificate fingerprint using the SHA256 digest of DER-encoded version - // of certificate offered by the server. For consistency with other hash - // values, this value should be formatted as an uppercase hash. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: - // '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0' - TLSServerHashSha256Key = attribute.Key("tls.server.hash.sha256") - - // TLSServerIssuerKey is the attribute Key conforming to the - // "tls.server.issuer" semantic conventions. It represents the - // distinguished name of - // [subject](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) - // of the issuer of the x.509 certificate presented by the client. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'CN=Example Root CA, OU=Infrastructure Team, DC=example, - // DC=com' - TLSServerIssuerKey = attribute.Key("tls.server.issuer") - - // TLSServerJa3sKey is the attribute Key conforming to the - // "tls.server.ja3s" semantic conventions. It represents a hash that - // identifies servers based on how they perform an SSL/TLS handshake. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'd4e5b18d6b55c71272893221c96ba240' - TLSServerJa3sKey = attribute.Key("tls.server.ja3s") - - // TLSServerNotAfterKey is the attribute Key conforming to the - // "tls.server.not_after" semantic conventions. It represents the date/Time - // indicating when server certificate is no longer considered valid. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '2021-01-01T00:00:00.000Z' - TLSServerNotAfterKey = attribute.Key("tls.server.not_after") - - // TLSServerNotBeforeKey is the attribute Key conforming to the - // "tls.server.not_before" semantic conventions. It represents the - // date/Time indicating when server certificate is first considered valid. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '1970-01-01T00:00:00.000Z' - TLSServerNotBeforeKey = attribute.Key("tls.server.not_before") - - // TLSServerSubjectKey is the attribute Key conforming to the - // "tls.server.subject" semantic conventions. It represents the - // distinguished name of subject of the x.509 certificate presented by the - // server. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'CN=myserver, OU=Documentation Team, DC=example, DC=com' - TLSServerSubjectKey = attribute.Key("tls.server.subject") -) - -var ( - // ssl - TLSProtocolNameSsl = TLSProtocolNameKey.String("ssl") - // tls - TLSProtocolNameTLS = TLSProtocolNameKey.String("tls") -) - -// TLSCipher returns an attribute KeyValue conforming to the "tls.cipher" -// semantic conventions. It represents the string indicating the -// [cipher](https://datatracker.ietf.org/doc/html/rfc5246#appendix-A.5) used -// during the current connection. -func TLSCipher(val string) attribute.KeyValue { - return TLSCipherKey.String(val) -} - -// TLSClientCertificate returns an attribute KeyValue conforming to the -// "tls.client.certificate" semantic conventions. It represents the pEM-encoded -// stand-alone certificate offered by the client. This is usually -// mutually-exclusive of `client.certificate_chain` since this value also -// exists in that list. -func TLSClientCertificate(val string) attribute.KeyValue { - return TLSClientCertificateKey.String(val) -} - -// TLSClientCertificateChain returns an attribute KeyValue conforming to the -// "tls.client.certificate_chain" semantic conventions. It represents the array -// of PEM-encoded certificates that make up the certificate chain offered by -// the client. This is usually mutually-exclusive of `client.certificate` since -// that value should be the first certificate in the chain. -func TLSClientCertificateChain(val ...string) attribute.KeyValue { - return TLSClientCertificateChainKey.StringSlice(val) -} - -// TLSClientHashMd5 returns an attribute KeyValue conforming to the -// "tls.client.hash.md5" semantic conventions. It represents the certificate -// fingerprint using the MD5 digest of DER-encoded version of certificate -// offered by the client. For consistency with other hash values, this value -// should be formatted as an uppercase hash. -func TLSClientHashMd5(val string) attribute.KeyValue { - return TLSClientHashMd5Key.String(val) -} - -// TLSClientHashSha1 returns an attribute KeyValue conforming to the -// "tls.client.hash.sha1" semantic conventions. It represents the certificate -// fingerprint using the SHA1 digest of DER-encoded version of certificate -// offered by the client. For consistency with other hash values, this value -// should be formatted as an uppercase hash. -func TLSClientHashSha1(val string) attribute.KeyValue { - return TLSClientHashSha1Key.String(val) -} - -// TLSClientHashSha256 returns an attribute KeyValue conforming to the -// "tls.client.hash.sha256" semantic conventions. It represents the certificate -// fingerprint using the SHA256 digest of DER-encoded version of certificate -// offered by the client. For consistency with other hash values, this value -// should be formatted as an uppercase hash. -func TLSClientHashSha256(val string) attribute.KeyValue { - return TLSClientHashSha256Key.String(val) -} - -// TLSClientIssuer returns an attribute KeyValue conforming to the -// "tls.client.issuer" semantic conventions. It represents the distinguished -// name of -// [subject](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) of -// the issuer of the x.509 certificate presented by the client. -func TLSClientIssuer(val string) attribute.KeyValue { - return TLSClientIssuerKey.String(val) -} - -// TLSClientJa3 returns an attribute KeyValue conforming to the -// "tls.client.ja3" semantic conventions. It represents a hash that identifies -// clients based on how they perform an SSL/TLS handshake. -func TLSClientJa3(val string) attribute.KeyValue { - return TLSClientJa3Key.String(val) -} - -// TLSClientNotAfter returns an attribute KeyValue conforming to the -// "tls.client.not_after" semantic conventions. It represents the date/Time -// indicating when client certificate is no longer considered valid. -func TLSClientNotAfter(val string) attribute.KeyValue { - return TLSClientNotAfterKey.String(val) -} - -// TLSClientNotBefore returns an attribute KeyValue conforming to the -// "tls.client.not_before" semantic conventions. It represents the date/Time -// indicating when client certificate is first considered valid. -func TLSClientNotBefore(val string) attribute.KeyValue { - return TLSClientNotBeforeKey.String(val) -} - -// TLSClientServerName returns an attribute KeyValue conforming to the -// "tls.client.server_name" semantic conventions. It represents the also called -// an SNI, this tells the server which hostname to which the client is -// attempting to connect to. -func TLSClientServerName(val string) attribute.KeyValue { - return TLSClientServerNameKey.String(val) -} - -// TLSClientSubject returns an attribute KeyValue conforming to the -// "tls.client.subject" semantic conventions. It represents the distinguished -// name of subject of the x.509 certificate presented by the client. -func TLSClientSubject(val string) attribute.KeyValue { - return TLSClientSubjectKey.String(val) -} - -// TLSClientSupportedCiphers returns an attribute KeyValue conforming to the -// "tls.client.supported_ciphers" semantic conventions. It represents the array -// of ciphers offered by the client during the client hello. -func TLSClientSupportedCiphers(val ...string) attribute.KeyValue { - return TLSClientSupportedCiphersKey.StringSlice(val) -} - -// TLSCurve returns an attribute KeyValue conforming to the "tls.curve" -// semantic conventions. It represents the string indicating the curve used for -// the given cipher, when applicable -func TLSCurve(val string) attribute.KeyValue { - return TLSCurveKey.String(val) -} - -// TLSEstablished returns an attribute KeyValue conforming to the -// "tls.established" semantic conventions. It represents the boolean flag -// indicating if the TLS negotiation was successful and transitioned to an -// encrypted tunnel. -func TLSEstablished(val bool) attribute.KeyValue { - return TLSEstablishedKey.Bool(val) -} - -// TLSNextProtocol returns an attribute KeyValue conforming to the -// "tls.next_protocol" semantic conventions. It represents the string -// indicating the protocol being tunneled. Per the values in the [IANA -// registry](https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids), -// this string should be lower case. -func TLSNextProtocol(val string) attribute.KeyValue { - return TLSNextProtocolKey.String(val) -} - -// TLSProtocolVersion returns an attribute KeyValue conforming to the -// "tls.protocol.version" semantic conventions. It represents the numeric part -// of the version parsed from the original string of the negotiated [SSL/TLS -// protocol -// version](https://www.openssl.org/docs/man1.1.1/man3/SSL_get_version.html#RETURN-VALUES) -func TLSProtocolVersion(val string) attribute.KeyValue { - return TLSProtocolVersionKey.String(val) -} - -// TLSResumed returns an attribute KeyValue conforming to the "tls.resumed" -// semantic conventions. It represents the boolean flag indicating if this TLS -// connection was resumed from an existing TLS negotiation. -func TLSResumed(val bool) attribute.KeyValue { - return TLSResumedKey.Bool(val) -} - -// TLSServerCertificate returns an attribute KeyValue conforming to the -// "tls.server.certificate" semantic conventions. It represents the pEM-encoded -// stand-alone certificate offered by the server. This is usually -// mutually-exclusive of `server.certificate_chain` since this value also -// exists in that list. -func TLSServerCertificate(val string) attribute.KeyValue { - return TLSServerCertificateKey.String(val) -} - -// TLSServerCertificateChain returns an attribute KeyValue conforming to the -// "tls.server.certificate_chain" semantic conventions. It represents the array -// of PEM-encoded certificates that make up the certificate chain offered by -// the server. This is usually mutually-exclusive of `server.certificate` since -// that value should be the first certificate in the chain. -func TLSServerCertificateChain(val ...string) attribute.KeyValue { - return TLSServerCertificateChainKey.StringSlice(val) -} - -// TLSServerHashMd5 returns an attribute KeyValue conforming to the -// "tls.server.hash.md5" semantic conventions. It represents the certificate -// fingerprint using the MD5 digest of DER-encoded version of certificate -// offered by the server. For consistency with other hash values, this value -// should be formatted as an uppercase hash. -func TLSServerHashMd5(val string) attribute.KeyValue { - return TLSServerHashMd5Key.String(val) -} - -// TLSServerHashSha1 returns an attribute KeyValue conforming to the -// "tls.server.hash.sha1" semantic conventions. It represents the certificate -// fingerprint using the SHA1 digest of DER-encoded version of certificate -// offered by the server. For consistency with other hash values, this value -// should be formatted as an uppercase hash. -func TLSServerHashSha1(val string) attribute.KeyValue { - return TLSServerHashSha1Key.String(val) -} - -// TLSServerHashSha256 returns an attribute KeyValue conforming to the -// "tls.server.hash.sha256" semantic conventions. It represents the certificate -// fingerprint using the SHA256 digest of DER-encoded version of certificate -// offered by the server. For consistency with other hash values, this value -// should be formatted as an uppercase hash. -func TLSServerHashSha256(val string) attribute.KeyValue { - return TLSServerHashSha256Key.String(val) -} - -// TLSServerIssuer returns an attribute KeyValue conforming to the -// "tls.server.issuer" semantic conventions. It represents the distinguished -// name of -// [subject](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) of -// the issuer of the x.509 certificate presented by the client. -func TLSServerIssuer(val string) attribute.KeyValue { - return TLSServerIssuerKey.String(val) -} - -// TLSServerJa3s returns an attribute KeyValue conforming to the -// "tls.server.ja3s" semantic conventions. It represents a hash that identifies -// servers based on how they perform an SSL/TLS handshake. -func TLSServerJa3s(val string) attribute.KeyValue { - return TLSServerJa3sKey.String(val) -} - -// TLSServerNotAfter returns an attribute KeyValue conforming to the -// "tls.server.not_after" semantic conventions. It represents the date/Time -// indicating when server certificate is no longer considered valid. -func TLSServerNotAfter(val string) attribute.KeyValue { - return TLSServerNotAfterKey.String(val) -} - -// TLSServerNotBefore returns an attribute KeyValue conforming to the -// "tls.server.not_before" semantic conventions. It represents the date/Time -// indicating when server certificate is first considered valid. -func TLSServerNotBefore(val string) attribute.KeyValue { - return TLSServerNotBeforeKey.String(val) -} - -// TLSServerSubject returns an attribute KeyValue conforming to the -// "tls.server.subject" semantic conventions. It represents the distinguished -// name of subject of the x.509 certificate presented by the server. -func TLSServerSubject(val string) attribute.KeyValue { - return TLSServerSubjectKey.String(val) -} - -// Attributes describing URL. -const ( - // URLDomainKey is the attribute Key conforming to the "url.domain" - // semantic conventions. It represents the domain extracted from the - // `url.full`, such as "opentelemetry.io". - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'www.foo.bar', 'opentelemetry.io', '3.12.167.2', - // '[1080:0:0:0:8:800:200C:417A]' - // Note: In some cases a URL may refer to an IP and/or port directly, - // without a domain name. In this case, the IP address would go to the - // domain field. If the URL contains a [literal IPv6 - // address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by - // `[` and `]`, the `[` and `]` characters should also be captured in the - // domain field. - URLDomainKey = attribute.Key("url.domain") - - // URLExtensionKey is the attribute Key conforming to the "url.extension" - // semantic conventions. It represents the file extension extracted from - // the `url.full`, excluding the leading dot. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'png', 'gz' - // Note: The file extension is only set if it exists, as not every url has - // a file extension. When the file name has multiple extensions - // `example.tar.gz`, only the last one should be captured `gz`, not - // `tar.gz`. - URLExtensionKey = attribute.Key("url.extension") - - // URLFragmentKey is the attribute Key conforming to the "url.fragment" - // semantic conventions. It represents the [URI - // fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'SemConv' - URLFragmentKey = attribute.Key("url.fragment") - - // URLFullKey is the attribute Key conforming to the "url.full" semantic - // conventions. It represents the absolute URL describing a network - // resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'https://www.foo.bar/search?q=OpenTelemetry#SemConv', - // '//localhost' - // Note: For network calls, URL usually has - // `scheme://host[:port][path][?query][#fragment]` format, where the - // fragment is not transmitted over HTTP, but if it is known, it SHOULD be - // included nevertheless. - // `url.full` MUST NOT contain credentials passed via URL in form of - // `https://username:password@www.example.com/`. In such case username and - // password SHOULD be redacted and attribute's value SHOULD be - // `https://REDACTED:REDACTED@www.example.com/`. - // `url.full` SHOULD capture the absolute URL when it is available (or can - // be reconstructed). Sensitive content provided in `url.full` SHOULD be - // scrubbed when instrumentations can identify it. - URLFullKey = attribute.Key("url.full") - - // URLOriginalKey is the attribute Key conforming to the "url.original" - // semantic conventions. It represents the unmodified original URL as seen - // in the event source. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'https://www.foo.bar/search?q=OpenTelemetry#SemConv', - // 'search?q=OpenTelemetry' - // Note: In network monitoring, the observed URL may be a full URL, whereas - // in access logs, the URL is often just represented as a path. This field - // is meant to represent the URL as it was observed, complete or not. - // `url.original` might contain credentials passed via URL in form of - // `https://username:password@www.example.com/`. In such case password and - // username SHOULD NOT be redacted and attribute's value SHOULD remain the - // same. - URLOriginalKey = attribute.Key("url.original") - - // URLPathKey is the attribute Key conforming to the "url.path" semantic - // conventions. It represents the [URI - // path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: '/search' - // Note: Sensitive content provided in `url.path` SHOULD be scrubbed when - // instrumentations can identify it. - URLPathKey = attribute.Key("url.path") - - // URLPortKey is the attribute Key conforming to the "url.port" semantic - // conventions. It represents the port extracted from the `url.full` - // - // Type: int - // RequirementLevel: Optional - // Stability: experimental - // Examples: 443 - URLPortKey = attribute.Key("url.port") - - // URLQueryKey is the attribute Key conforming to the "url.query" semantic - // conventions. It represents the [URI - // query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'q=OpenTelemetry' - // Note: Sensitive content provided in `url.query` SHOULD be scrubbed when - // instrumentations can identify it. - URLQueryKey = attribute.Key("url.query") - - // URLRegisteredDomainKey is the attribute Key conforming to the - // "url.registered_domain" semantic conventions. It represents the highest - // registered url domain, stripped of the subdomain. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'example.com', 'foo.co.uk' - // Note: This value can be determined precisely with the [public suffix - // list](http://publicsuffix.org). For example, the registered domain for - // `foo.example.com` is `example.com`. Trying to approximate this by simply - // taking the last two labels will not work well for TLDs such as `co.uk`. - URLRegisteredDomainKey = attribute.Key("url.registered_domain") - - // URLSchemeKey is the attribute Key conforming to the "url.scheme" - // semantic conventions. It represents the [URI - // scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component - // identifying the used protocol. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'https', 'ftp', 'telnet' - URLSchemeKey = attribute.Key("url.scheme") - - // URLSubdomainKey is the attribute Key conforming to the "url.subdomain" - // semantic conventions. It represents the subdomain portion of a fully - // qualified domain name includes all of the names except the host name - // under the registered_domain. In a partially qualified domain, or if the - // qualification level of the full name cannot be determined, subdomain - // contains all of the names below the registered domain. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'east', 'sub2.sub1' - // Note: The subdomain portion of `www.east.mydomain.co.uk` is `east`. If - // the domain has multiple levels of subdomain, such as - // `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, - // with no trailing period. - URLSubdomainKey = attribute.Key("url.subdomain") - - // URLTemplateKey is the attribute Key conforming to the "url.template" - // semantic conventions. It represents the low-cardinality template of an - // [absolute path - // reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '/users/{id}', '/users/:id', '/users?id={id}' - URLTemplateKey = attribute.Key("url.template") - - // URLTopLevelDomainKey is the attribute Key conforming to the - // "url.top_level_domain" semantic conventions. It represents the effective - // top level domain (eTLD), also known as the domain suffix, is the last - // part of the domain name. For example, the top level domain for - // example.com is `com`. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'com', 'co.uk' - // Note: This value can be determined precisely with the [public suffix - // list](http://publicsuffix.org). - URLTopLevelDomainKey = attribute.Key("url.top_level_domain") -) - -// URLDomain returns an attribute KeyValue conforming to the "url.domain" -// semantic conventions. It represents the domain extracted from the -// `url.full`, such as "opentelemetry.io". -func URLDomain(val string) attribute.KeyValue { - return URLDomainKey.String(val) -} - -// URLExtension returns an attribute KeyValue conforming to the -// "url.extension" semantic conventions. It represents the file extension -// extracted from the `url.full`, excluding the leading dot. -func URLExtension(val string) attribute.KeyValue { - return URLExtensionKey.String(val) -} - -// URLFragment returns an attribute KeyValue conforming to the -// "url.fragment" semantic conventions. It represents the [URI -// fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component -func URLFragment(val string) attribute.KeyValue { - return URLFragmentKey.String(val) -} - -// URLFull returns an attribute KeyValue conforming to the "url.full" -// semantic conventions. It represents the absolute URL describing a network -// resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) -func URLFull(val string) attribute.KeyValue { - return URLFullKey.String(val) -} - -// URLOriginal returns an attribute KeyValue conforming to the -// "url.original" semantic conventions. It represents the unmodified original -// URL as seen in the event source. -func URLOriginal(val string) attribute.KeyValue { - return URLOriginalKey.String(val) -} - -// URLPath returns an attribute KeyValue conforming to the "url.path" -// semantic conventions. It represents the [URI -// path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component -func URLPath(val string) attribute.KeyValue { - return URLPathKey.String(val) -} - -// URLPort returns an attribute KeyValue conforming to the "url.port" -// semantic conventions. It represents the port extracted from the `url.full` -func URLPort(val int) attribute.KeyValue { - return URLPortKey.Int(val) -} - -// URLQuery returns an attribute KeyValue conforming to the "url.query" -// semantic conventions. It represents the [URI -// query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component -func URLQuery(val string) attribute.KeyValue { - return URLQueryKey.String(val) -} - -// URLRegisteredDomain returns an attribute KeyValue conforming to the -// "url.registered_domain" semantic conventions. It represents the highest -// registered url domain, stripped of the subdomain. -func URLRegisteredDomain(val string) attribute.KeyValue { - return URLRegisteredDomainKey.String(val) -} - -// URLScheme returns an attribute KeyValue conforming to the "url.scheme" -// semantic conventions. It represents the [URI -// scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component -// identifying the used protocol. -func URLScheme(val string) attribute.KeyValue { - return URLSchemeKey.String(val) -} - -// URLSubdomain returns an attribute KeyValue conforming to the -// "url.subdomain" semantic conventions. It represents the subdomain portion of -// a fully qualified domain name includes all of the names except the host name -// under the registered_domain. In a partially qualified domain, or if the -// qualification level of the full name cannot be determined, subdomain -// contains all of the names below the registered domain. -func URLSubdomain(val string) attribute.KeyValue { - return URLSubdomainKey.String(val) -} - -// URLTemplate returns an attribute KeyValue conforming to the -// "url.template" semantic conventions. It represents the low-cardinality -// template of an [absolute path -// reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). -func URLTemplate(val string) attribute.KeyValue { - return URLTemplateKey.String(val) -} - -// URLTopLevelDomain returns an attribute KeyValue conforming to the -// "url.top_level_domain" semantic conventions. It represents the effective top -// level domain (eTLD), also known as the domain suffix, is the last part of -// the domain name. For example, the top level domain for example.com is `com`. -func URLTopLevelDomain(val string) attribute.KeyValue { - return URLTopLevelDomainKey.String(val) -} - -// Describes user-agent attributes. -const ( - // UserAgentNameKey is the attribute Key conforming to the - // "user_agent.name" semantic conventions. It represents the name of the - // user-agent extracted from original. Usually refers to the browser's - // name. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'Safari', 'YourApp' - // Note: [Example](https://www.whatsmyua.info) of extracting browser's name - // from original string. In the case of using a user-agent for non-browser - // products, such as microservices with multiple names/versions inside the - // `user_agent.original`, the most significant name SHOULD be selected. In - // such a scenario it should align with `user_agent.version` - UserAgentNameKey = attribute.Key("user_agent.name") - - // UserAgentOriginalKey is the attribute Key conforming to the - // "user_agent.original" semantic conventions. It represents the value of - // the [HTTP - // User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) - // header sent by the client. - // - // Type: string - // RequirementLevel: Optional - // Stability: stable - // Examples: 'CERN-LineMode/2.15 libwww/2.17b3', 'Mozilla/5.0 (iPhone; CPU - // iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) - // Version/14.1.2 Mobile/15E148 Safari/604.1', 'YourApp/1.0.0 - // grpc-java-okhttp/1.27.2' - UserAgentOriginalKey = attribute.Key("user_agent.original") - - // UserAgentVersionKey is the attribute Key conforming to the - // "user_agent.version" semantic conventions. It represents the version of - // the user-agent extracted from original. Usually refers to the browser's - // version - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '14.1.2', '1.0.0' - // Note: [Example](https://www.whatsmyua.info) of extracting browser's - // version from original string. In the case of using a user-agent for - // non-browser products, such as microservices with multiple names/versions - // inside the `user_agent.original`, the most significant version SHOULD be - // selected. In such a scenario it should align with `user_agent.name` - UserAgentVersionKey = attribute.Key("user_agent.version") -) - -// UserAgentName returns an attribute KeyValue conforming to the -// "user_agent.name" semantic conventions. It represents the name of the -// user-agent extracted from original. Usually refers to the browser's name. -func UserAgentName(val string) attribute.KeyValue { - return UserAgentNameKey.String(val) -} - -// UserAgentOriginal returns an attribute KeyValue conforming to the -// "user_agent.original" semantic conventions. It represents the value of the -// [HTTP -// User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) -// header sent by the client. -func UserAgentOriginal(val string) attribute.KeyValue { - return UserAgentOriginalKey.String(val) -} - -// UserAgentVersion returns an attribute KeyValue conforming to the -// "user_agent.version" semantic conventions. It represents the version of the -// user-agent extracted from original. Usually refers to the browser's version -func UserAgentVersion(val string) attribute.KeyValue { - return UserAgentVersionKey.String(val) -} - -// The attributes used to describe the packaged software running the -// application code. -const ( - // WebEngineDescriptionKey is the attribute Key conforming to the - // "webengine.description" semantic conventions. It represents the - // additional description of the web engine (e.g. detailed version and - // edition information). - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'WildFly Full 21.0.0.Final (WildFly Core 13.0.1.Final) - - // 2.2.2.Final' - WebEngineDescriptionKey = attribute.Key("webengine.description") - - // WebEngineNameKey is the attribute Key conforming to the "webengine.name" - // semantic conventions. It represents the name of the web engine. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: 'WildFly' - WebEngineNameKey = attribute.Key("webengine.name") - - // WebEngineVersionKey is the attribute Key conforming to the - // "webengine.version" semantic conventions. It represents the version of - // the web engine. - // - // Type: string - // RequirementLevel: Optional - // Stability: experimental - // Examples: '21.0.0' - WebEngineVersionKey = attribute.Key("webengine.version") -) - -// WebEngineDescription returns an attribute KeyValue conforming to the -// "webengine.description" semantic conventions. It represents the additional -// description of the web engine (e.g. detailed version and edition -// information). -func WebEngineDescription(val string) attribute.KeyValue { - return WebEngineDescriptionKey.String(val) -} - -// WebEngineName returns an attribute KeyValue conforming to the -// "webengine.name" semantic conventions. It represents the name of the web -// engine. -func WebEngineName(val string) attribute.KeyValue { - return WebEngineNameKey.String(val) -} - -// WebEngineVersion returns an attribute KeyValue conforming to the -// "webengine.version" semantic conventions. It represents the version of the -// web engine. -func WebEngineVersion(val string) attribute.KeyValue { - return WebEngineVersionKey.String(val) -} diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/doc.go b/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/doc.go deleted file mode 100644 index d031bbea..00000000 --- a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/doc.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Package semconv implements OpenTelemetry semantic conventions. -// -// OpenTelemetry semantic conventions are agreed standardized naming -// patterns for OpenTelemetry things. This package represents the v1.26.0 -// version of the OpenTelemetry semantic conventions. -package semconv // import "go.opentelemetry.io/otel/semconv/v1.26.0" diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/exception.go b/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/exception.go deleted file mode 100644 index bfaee0d5..00000000 --- a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/exception.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package semconv // import "go.opentelemetry.io/otel/semconv/v1.26.0" - -const ( - // ExceptionEventName is the name of the Span event representing an exception. - ExceptionEventName = "exception" -) diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/metric.go b/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/metric.go deleted file mode 100644 index fcdb9f48..00000000 --- a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/metric.go +++ /dev/null @@ -1,1307 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Code generated from semantic convention specification. DO NOT EDIT. - -package semconv // import "go.opentelemetry.io/otel/semconv/v1.26.0" - -const ( - - // ContainerCPUTime is the metric conforming to the "container.cpu.time" - // semantic conventions. It represents the total CPU time consumed. - // Instrument: counter - // Unit: s - // Stability: Experimental - ContainerCPUTimeName = "container.cpu.time" - ContainerCPUTimeUnit = "s" - ContainerCPUTimeDescription = "Total CPU time consumed" - - // ContainerMemoryUsage is the metric conforming to the - // "container.memory.usage" semantic conventions. It represents the memory - // usage of the container. - // Instrument: counter - // Unit: By - // Stability: Experimental - ContainerMemoryUsageName = "container.memory.usage" - ContainerMemoryUsageUnit = "By" - ContainerMemoryUsageDescription = "Memory usage of the container." - - // ContainerDiskIo is the metric conforming to the "container.disk.io" semantic - // conventions. It represents the disk bytes for the container. - // Instrument: counter - // Unit: By - // Stability: Experimental - ContainerDiskIoName = "container.disk.io" - ContainerDiskIoUnit = "By" - ContainerDiskIoDescription = "Disk bytes for the container." - - // ContainerNetworkIo is the metric conforming to the "container.network.io" - // semantic conventions. It represents the network bytes for the container. - // Instrument: counter - // Unit: By - // Stability: Experimental - ContainerNetworkIoName = "container.network.io" - ContainerNetworkIoUnit = "By" - ContainerNetworkIoDescription = "Network bytes for the container." - - // DBClientOperationDuration is the metric conforming to the - // "db.client.operation.duration" semantic conventions. It represents the - // duration of database client operations. - // Instrument: histogram - // Unit: s - // Stability: Experimental - DBClientOperationDurationName = "db.client.operation.duration" - DBClientOperationDurationUnit = "s" - DBClientOperationDurationDescription = "Duration of database client operations." - - // DBClientConnectionCount is the metric conforming to the - // "db.client.connection.count" semantic conventions. It represents the number - // of connections that are currently in state described by the `state` - // attribute. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionCountName = "db.client.connection.count" - DBClientConnectionCountUnit = "{connection}" - DBClientConnectionCountDescription = "The number of connections that are currently in state described by the `state` attribute" - - // DBClientConnectionIdleMax is the metric conforming to the - // "db.client.connection.idle.max" semantic conventions. It represents the - // maximum number of idle open connections allowed. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionIdleMaxName = "db.client.connection.idle.max" - DBClientConnectionIdleMaxUnit = "{connection}" - DBClientConnectionIdleMaxDescription = "The maximum number of idle open connections allowed" - - // DBClientConnectionIdleMin is the metric conforming to the - // "db.client.connection.idle.min" semantic conventions. It represents the - // minimum number of idle open connections allowed. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionIdleMinName = "db.client.connection.idle.min" - DBClientConnectionIdleMinUnit = "{connection}" - DBClientConnectionIdleMinDescription = "The minimum number of idle open connections allowed" - - // DBClientConnectionMax is the metric conforming to the - // "db.client.connection.max" semantic conventions. It represents the maximum - // number of open connections allowed. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionMaxName = "db.client.connection.max" - DBClientConnectionMaxUnit = "{connection}" - DBClientConnectionMaxDescription = "The maximum number of open connections allowed" - - // DBClientConnectionPendingRequests is the metric conforming to the - // "db.client.connection.pending_requests" semantic conventions. It represents - // the number of pending requests for an open connection, cumulative for the - // entire pool. - // Instrument: updowncounter - // Unit: {request} - // Stability: Experimental - DBClientConnectionPendingRequestsName = "db.client.connection.pending_requests" - DBClientConnectionPendingRequestsUnit = "{request}" - DBClientConnectionPendingRequestsDescription = "The number of pending requests for an open connection, cumulative for the entire pool" - - // DBClientConnectionTimeouts is the metric conforming to the - // "db.client.connection.timeouts" semantic conventions. It represents the - // number of connection timeouts that have occurred trying to obtain a - // connection from the pool. - // Instrument: counter - // Unit: {timeout} - // Stability: Experimental - DBClientConnectionTimeoutsName = "db.client.connection.timeouts" - DBClientConnectionTimeoutsUnit = "{timeout}" - DBClientConnectionTimeoutsDescription = "The number of connection timeouts that have occurred trying to obtain a connection from the pool" - - // DBClientConnectionCreateTime is the metric conforming to the - // "db.client.connection.create_time" semantic conventions. It represents the - // time it took to create a new connection. - // Instrument: histogram - // Unit: s - // Stability: Experimental - DBClientConnectionCreateTimeName = "db.client.connection.create_time" - DBClientConnectionCreateTimeUnit = "s" - DBClientConnectionCreateTimeDescription = "The time it took to create a new connection" - - // DBClientConnectionWaitTime is the metric conforming to the - // "db.client.connection.wait_time" semantic conventions. It represents the - // time it took to obtain an open connection from the pool. - // Instrument: histogram - // Unit: s - // Stability: Experimental - DBClientConnectionWaitTimeName = "db.client.connection.wait_time" - DBClientConnectionWaitTimeUnit = "s" - DBClientConnectionWaitTimeDescription = "The time it took to obtain an open connection from the pool" - - // DBClientConnectionUseTime is the metric conforming to the - // "db.client.connection.use_time" semantic conventions. It represents the time - // between borrowing a connection and returning it to the pool. - // Instrument: histogram - // Unit: s - // Stability: Experimental - DBClientConnectionUseTimeName = "db.client.connection.use_time" - DBClientConnectionUseTimeUnit = "s" - DBClientConnectionUseTimeDescription = "The time between borrowing a connection and returning it to the pool" - - // DBClientConnectionsUsage is the metric conforming to the - // "db.client.connections.usage" semantic conventions. It represents the - // deprecated, use `db.client.connection.count` instead. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionsUsageName = "db.client.connections.usage" - DBClientConnectionsUsageUnit = "{connection}" - DBClientConnectionsUsageDescription = "Deprecated, use `db.client.connection.count` instead." - - // DBClientConnectionsIdleMax is the metric conforming to the - // "db.client.connections.idle.max" semantic conventions. It represents the - // deprecated, use `db.client.connection.idle.max` instead. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionsIdleMaxName = "db.client.connections.idle.max" - DBClientConnectionsIdleMaxUnit = "{connection}" - DBClientConnectionsIdleMaxDescription = "Deprecated, use `db.client.connection.idle.max` instead." - - // DBClientConnectionsIdleMin is the metric conforming to the - // "db.client.connections.idle.min" semantic conventions. It represents the - // deprecated, use `db.client.connection.idle.min` instead. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionsIdleMinName = "db.client.connections.idle.min" - DBClientConnectionsIdleMinUnit = "{connection}" - DBClientConnectionsIdleMinDescription = "Deprecated, use `db.client.connection.idle.min` instead." - - // DBClientConnectionsMax is the metric conforming to the - // "db.client.connections.max" semantic conventions. It represents the - // deprecated, use `db.client.connection.max` instead. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - DBClientConnectionsMaxName = "db.client.connections.max" - DBClientConnectionsMaxUnit = "{connection}" - DBClientConnectionsMaxDescription = "Deprecated, use `db.client.connection.max` instead." - - // DBClientConnectionsPendingRequests is the metric conforming to the - // "db.client.connections.pending_requests" semantic conventions. It represents - // the deprecated, use `db.client.connection.pending_requests` instead. - // Instrument: updowncounter - // Unit: {request} - // Stability: Experimental - DBClientConnectionsPendingRequestsName = "db.client.connections.pending_requests" - DBClientConnectionsPendingRequestsUnit = "{request}" - DBClientConnectionsPendingRequestsDescription = "Deprecated, use `db.client.connection.pending_requests` instead." - - // DBClientConnectionsTimeouts is the metric conforming to the - // "db.client.connections.timeouts" semantic conventions. It represents the - // deprecated, use `db.client.connection.timeouts` instead. - // Instrument: counter - // Unit: {timeout} - // Stability: Experimental - DBClientConnectionsTimeoutsName = "db.client.connections.timeouts" - DBClientConnectionsTimeoutsUnit = "{timeout}" - DBClientConnectionsTimeoutsDescription = "Deprecated, use `db.client.connection.timeouts` instead." - - // DBClientConnectionsCreateTime is the metric conforming to the - // "db.client.connections.create_time" semantic conventions. It represents the - // deprecated, use `db.client.connection.create_time` instead. Note: the unit - // also changed from `ms` to `s`. - // Instrument: histogram - // Unit: ms - // Stability: Experimental - DBClientConnectionsCreateTimeName = "db.client.connections.create_time" - DBClientConnectionsCreateTimeUnit = "ms" - DBClientConnectionsCreateTimeDescription = "Deprecated, use `db.client.connection.create_time` instead. Note: the unit also changed from `ms` to `s`." - - // DBClientConnectionsWaitTime is the metric conforming to the - // "db.client.connections.wait_time" semantic conventions. It represents the - // deprecated, use `db.client.connection.wait_time` instead. Note: the unit - // also changed from `ms` to `s`. - // Instrument: histogram - // Unit: ms - // Stability: Experimental - DBClientConnectionsWaitTimeName = "db.client.connections.wait_time" - DBClientConnectionsWaitTimeUnit = "ms" - DBClientConnectionsWaitTimeDescription = "Deprecated, use `db.client.connection.wait_time` instead. Note: the unit also changed from `ms` to `s`." - - // DBClientConnectionsUseTime is the metric conforming to the - // "db.client.connections.use_time" semantic conventions. It represents the - // deprecated, use `db.client.connection.use_time` instead. Note: the unit also - // changed from `ms` to `s`. - // Instrument: histogram - // Unit: ms - // Stability: Experimental - DBClientConnectionsUseTimeName = "db.client.connections.use_time" - DBClientConnectionsUseTimeUnit = "ms" - DBClientConnectionsUseTimeDescription = "Deprecated, use `db.client.connection.use_time` instead. Note: the unit also changed from `ms` to `s`." - - // DNSLookupDuration is the metric conforming to the "dns.lookup.duration" - // semantic conventions. It represents the measures the time taken to perform a - // DNS lookup. - // Instrument: histogram - // Unit: s - // Stability: Experimental - DNSLookupDurationName = "dns.lookup.duration" - DNSLookupDurationUnit = "s" - DNSLookupDurationDescription = "Measures the time taken to perform a DNS lookup." - - // AspnetcoreRoutingMatchAttempts is the metric conforming to the - // "aspnetcore.routing.match_attempts" semantic conventions. It represents the - // number of requests that were attempted to be matched to an endpoint. - // Instrument: counter - // Unit: {match_attempt} - // Stability: Stable - AspnetcoreRoutingMatchAttemptsName = "aspnetcore.routing.match_attempts" - AspnetcoreRoutingMatchAttemptsUnit = "{match_attempt}" - AspnetcoreRoutingMatchAttemptsDescription = "Number of requests that were attempted to be matched to an endpoint." - - // AspnetcoreDiagnosticsExceptions is the metric conforming to the - // "aspnetcore.diagnostics.exceptions" semantic conventions. It represents the - // number of exceptions caught by exception handling middleware. - // Instrument: counter - // Unit: {exception} - // Stability: Stable - AspnetcoreDiagnosticsExceptionsName = "aspnetcore.diagnostics.exceptions" - AspnetcoreDiagnosticsExceptionsUnit = "{exception}" - AspnetcoreDiagnosticsExceptionsDescription = "Number of exceptions caught by exception handling middleware." - - // AspnetcoreRateLimitingActiveRequestLeases is the metric conforming to the - // "aspnetcore.rate_limiting.active_request_leases" semantic conventions. It - // represents the number of requests that are currently active on the server - // that hold a rate limiting lease. - // Instrument: updowncounter - // Unit: {request} - // Stability: Stable - AspnetcoreRateLimitingActiveRequestLeasesName = "aspnetcore.rate_limiting.active_request_leases" - AspnetcoreRateLimitingActiveRequestLeasesUnit = "{request}" - AspnetcoreRateLimitingActiveRequestLeasesDescription = "Number of requests that are currently active on the server that hold a rate limiting lease." - - // AspnetcoreRateLimitingRequestLeaseDuration is the metric conforming to the - // "aspnetcore.rate_limiting.request_lease.duration" semantic conventions. It - // represents the duration of rate limiting lease held by requests on the - // server. - // Instrument: histogram - // Unit: s - // Stability: Stable - AspnetcoreRateLimitingRequestLeaseDurationName = "aspnetcore.rate_limiting.request_lease.duration" - AspnetcoreRateLimitingRequestLeaseDurationUnit = "s" - AspnetcoreRateLimitingRequestLeaseDurationDescription = "The duration of rate limiting lease held by requests on the server." - - // AspnetcoreRateLimitingRequestTimeInQueue is the metric conforming to the - // "aspnetcore.rate_limiting.request.time_in_queue" semantic conventions. It - // represents the time the request spent in a queue waiting to acquire a rate - // limiting lease. - // Instrument: histogram - // Unit: s - // Stability: Stable - AspnetcoreRateLimitingRequestTimeInQueueName = "aspnetcore.rate_limiting.request.time_in_queue" - AspnetcoreRateLimitingRequestTimeInQueueUnit = "s" - AspnetcoreRateLimitingRequestTimeInQueueDescription = "The time the request spent in a queue waiting to acquire a rate limiting lease." - - // AspnetcoreRateLimitingQueuedRequests is the metric conforming to the - // "aspnetcore.rate_limiting.queued_requests" semantic conventions. It - // represents the number of requests that are currently queued, waiting to - // acquire a rate limiting lease. - // Instrument: updowncounter - // Unit: {request} - // Stability: Stable - AspnetcoreRateLimitingQueuedRequestsName = "aspnetcore.rate_limiting.queued_requests" - AspnetcoreRateLimitingQueuedRequestsUnit = "{request}" - AspnetcoreRateLimitingQueuedRequestsDescription = "Number of requests that are currently queued, waiting to acquire a rate limiting lease." - - // AspnetcoreRateLimitingRequests is the metric conforming to the - // "aspnetcore.rate_limiting.requests" semantic conventions. It represents the - // number of requests that tried to acquire a rate limiting lease. - // Instrument: counter - // Unit: {request} - // Stability: Stable - AspnetcoreRateLimitingRequestsName = "aspnetcore.rate_limiting.requests" - AspnetcoreRateLimitingRequestsUnit = "{request}" - AspnetcoreRateLimitingRequestsDescription = "Number of requests that tried to acquire a rate limiting lease." - - // KestrelActiveConnections is the metric conforming to the - // "kestrel.active_connections" semantic conventions. It represents the number - // of connections that are currently active on the server. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Stable - KestrelActiveConnectionsName = "kestrel.active_connections" - KestrelActiveConnectionsUnit = "{connection}" - KestrelActiveConnectionsDescription = "Number of connections that are currently active on the server." - - // KestrelConnectionDuration is the metric conforming to the - // "kestrel.connection.duration" semantic conventions. It represents the - // duration of connections on the server. - // Instrument: histogram - // Unit: s - // Stability: Stable - KestrelConnectionDurationName = "kestrel.connection.duration" - KestrelConnectionDurationUnit = "s" - KestrelConnectionDurationDescription = "The duration of connections on the server." - - // KestrelRejectedConnections is the metric conforming to the - // "kestrel.rejected_connections" semantic conventions. It represents the - // number of connections rejected by the server. - // Instrument: counter - // Unit: {connection} - // Stability: Stable - KestrelRejectedConnectionsName = "kestrel.rejected_connections" - KestrelRejectedConnectionsUnit = "{connection}" - KestrelRejectedConnectionsDescription = "Number of connections rejected by the server." - - // KestrelQueuedConnections is the metric conforming to the - // "kestrel.queued_connections" semantic conventions. It represents the number - // of connections that are currently queued and are waiting to start. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Stable - KestrelQueuedConnectionsName = "kestrel.queued_connections" - KestrelQueuedConnectionsUnit = "{connection}" - KestrelQueuedConnectionsDescription = "Number of connections that are currently queued and are waiting to start." - - // KestrelQueuedRequests is the metric conforming to the - // "kestrel.queued_requests" semantic conventions. It represents the number of - // HTTP requests on multiplexed connections (HTTP/2 and HTTP/3) that are - // currently queued and are waiting to start. - // Instrument: updowncounter - // Unit: {request} - // Stability: Stable - KestrelQueuedRequestsName = "kestrel.queued_requests" - KestrelQueuedRequestsUnit = "{request}" - KestrelQueuedRequestsDescription = "Number of HTTP requests on multiplexed connections (HTTP/2 and HTTP/3) that are currently queued and are waiting to start." - - // KestrelUpgradedConnections is the metric conforming to the - // "kestrel.upgraded_connections" semantic conventions. It represents the - // number of connections that are currently upgraded (WebSockets). . - // Instrument: updowncounter - // Unit: {connection} - // Stability: Stable - KestrelUpgradedConnectionsName = "kestrel.upgraded_connections" - KestrelUpgradedConnectionsUnit = "{connection}" - KestrelUpgradedConnectionsDescription = "Number of connections that are currently upgraded (WebSockets). ." - - // KestrelTLSHandshakeDuration is the metric conforming to the - // "kestrel.tls_handshake.duration" semantic conventions. It represents the - // duration of TLS handshakes on the server. - // Instrument: histogram - // Unit: s - // Stability: Stable - KestrelTLSHandshakeDurationName = "kestrel.tls_handshake.duration" - KestrelTLSHandshakeDurationUnit = "s" - KestrelTLSHandshakeDurationDescription = "The duration of TLS handshakes on the server." - - // KestrelActiveTLSHandshakes is the metric conforming to the - // "kestrel.active_tls_handshakes" semantic conventions. It represents the - // number of TLS handshakes that are currently in progress on the server. - // Instrument: updowncounter - // Unit: {handshake} - // Stability: Stable - KestrelActiveTLSHandshakesName = "kestrel.active_tls_handshakes" - KestrelActiveTLSHandshakesUnit = "{handshake}" - KestrelActiveTLSHandshakesDescription = "Number of TLS handshakes that are currently in progress on the server." - - // SignalrServerConnectionDuration is the metric conforming to the - // "signalr.server.connection.duration" semantic conventions. It represents the - // duration of connections on the server. - // Instrument: histogram - // Unit: s - // Stability: Stable - SignalrServerConnectionDurationName = "signalr.server.connection.duration" - SignalrServerConnectionDurationUnit = "s" - SignalrServerConnectionDurationDescription = "The duration of connections on the server." - - // SignalrServerActiveConnections is the metric conforming to the - // "signalr.server.active_connections" semantic conventions. It represents the - // number of connections that are currently active on the server. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Stable - SignalrServerActiveConnectionsName = "signalr.server.active_connections" - SignalrServerActiveConnectionsUnit = "{connection}" - SignalrServerActiveConnectionsDescription = "Number of connections that are currently active on the server." - - // FaaSInvokeDuration is the metric conforming to the "faas.invoke_duration" - // semantic conventions. It represents the measures the duration of the - // function's logic execution. - // Instrument: histogram - // Unit: s - // Stability: Experimental - FaaSInvokeDurationName = "faas.invoke_duration" - FaaSInvokeDurationUnit = "s" - FaaSInvokeDurationDescription = "Measures the duration of the function's logic execution" - - // FaaSInitDuration is the metric conforming to the "faas.init_duration" - // semantic conventions. It represents the measures the duration of the - // function's initialization, such as a cold start. - // Instrument: histogram - // Unit: s - // Stability: Experimental - FaaSInitDurationName = "faas.init_duration" - FaaSInitDurationUnit = "s" - FaaSInitDurationDescription = "Measures the duration of the function's initialization, such as a cold start" - - // FaaSColdstarts is the metric conforming to the "faas.coldstarts" semantic - // conventions. It represents the number of invocation cold starts. - // Instrument: counter - // Unit: {coldstart} - // Stability: Experimental - FaaSColdstartsName = "faas.coldstarts" - FaaSColdstartsUnit = "{coldstart}" - FaaSColdstartsDescription = "Number of invocation cold starts" - - // FaaSErrors is the metric conforming to the "faas.errors" semantic - // conventions. It represents the number of invocation errors. - // Instrument: counter - // Unit: {error} - // Stability: Experimental - FaaSErrorsName = "faas.errors" - FaaSErrorsUnit = "{error}" - FaaSErrorsDescription = "Number of invocation errors" - - // FaaSInvocations is the metric conforming to the "faas.invocations" semantic - // conventions. It represents the number of successful invocations. - // Instrument: counter - // Unit: {invocation} - // Stability: Experimental - FaaSInvocationsName = "faas.invocations" - FaaSInvocationsUnit = "{invocation}" - FaaSInvocationsDescription = "Number of successful invocations" - - // FaaSTimeouts is the metric conforming to the "faas.timeouts" semantic - // conventions. It represents the number of invocation timeouts. - // Instrument: counter - // Unit: {timeout} - // Stability: Experimental - FaaSTimeoutsName = "faas.timeouts" - FaaSTimeoutsUnit = "{timeout}" - FaaSTimeoutsDescription = "Number of invocation timeouts" - - // FaaSMemUsage is the metric conforming to the "faas.mem_usage" semantic - // conventions. It represents the distribution of max memory usage per - // invocation. - // Instrument: histogram - // Unit: By - // Stability: Experimental - FaaSMemUsageName = "faas.mem_usage" - FaaSMemUsageUnit = "By" - FaaSMemUsageDescription = "Distribution of max memory usage per invocation" - - // FaaSCPUUsage is the metric conforming to the "faas.cpu_usage" semantic - // conventions. It represents the distribution of CPU usage per invocation. - // Instrument: histogram - // Unit: s - // Stability: Experimental - FaaSCPUUsageName = "faas.cpu_usage" - FaaSCPUUsageUnit = "s" - FaaSCPUUsageDescription = "Distribution of CPU usage per invocation" - - // FaaSNetIo is the metric conforming to the "faas.net_io" semantic - // conventions. It represents the distribution of net I/O usage per invocation. - // Instrument: histogram - // Unit: By - // Stability: Experimental - FaaSNetIoName = "faas.net_io" - FaaSNetIoUnit = "By" - FaaSNetIoDescription = "Distribution of net I/O usage per invocation" - - // HTTPServerRequestDuration is the metric conforming to the - // "http.server.request.duration" semantic conventions. It represents the - // duration of HTTP server requests. - // Instrument: histogram - // Unit: s - // Stability: Stable - HTTPServerRequestDurationName = "http.server.request.duration" - HTTPServerRequestDurationUnit = "s" - HTTPServerRequestDurationDescription = "Duration of HTTP server requests." - - // HTTPServerActiveRequests is the metric conforming to the - // "http.server.active_requests" semantic conventions. It represents the number - // of active HTTP server requests. - // Instrument: updowncounter - // Unit: {request} - // Stability: Experimental - HTTPServerActiveRequestsName = "http.server.active_requests" - HTTPServerActiveRequestsUnit = "{request}" - HTTPServerActiveRequestsDescription = "Number of active HTTP server requests." - - // HTTPServerRequestBodySize is the metric conforming to the - // "http.server.request.body.size" semantic conventions. It represents the size - // of HTTP server request bodies. - // Instrument: histogram - // Unit: By - // Stability: Experimental - HTTPServerRequestBodySizeName = "http.server.request.body.size" - HTTPServerRequestBodySizeUnit = "By" - HTTPServerRequestBodySizeDescription = "Size of HTTP server request bodies." - - // HTTPServerResponseBodySize is the metric conforming to the - // "http.server.response.body.size" semantic conventions. It represents the - // size of HTTP server response bodies. - // Instrument: histogram - // Unit: By - // Stability: Experimental - HTTPServerResponseBodySizeName = "http.server.response.body.size" - HTTPServerResponseBodySizeUnit = "By" - HTTPServerResponseBodySizeDescription = "Size of HTTP server response bodies." - - // HTTPClientRequestDuration is the metric conforming to the - // "http.client.request.duration" semantic conventions. It represents the - // duration of HTTP client requests. - // Instrument: histogram - // Unit: s - // Stability: Stable - HTTPClientRequestDurationName = "http.client.request.duration" - HTTPClientRequestDurationUnit = "s" - HTTPClientRequestDurationDescription = "Duration of HTTP client requests." - - // HTTPClientRequestBodySize is the metric conforming to the - // "http.client.request.body.size" semantic conventions. It represents the size - // of HTTP client request bodies. - // Instrument: histogram - // Unit: By - // Stability: Experimental - HTTPClientRequestBodySizeName = "http.client.request.body.size" - HTTPClientRequestBodySizeUnit = "By" - HTTPClientRequestBodySizeDescription = "Size of HTTP client request bodies." - - // HTTPClientResponseBodySize is the metric conforming to the - // "http.client.response.body.size" semantic conventions. It represents the - // size of HTTP client response bodies. - // Instrument: histogram - // Unit: By - // Stability: Experimental - HTTPClientResponseBodySizeName = "http.client.response.body.size" - HTTPClientResponseBodySizeUnit = "By" - HTTPClientResponseBodySizeDescription = "Size of HTTP client response bodies." - - // HTTPClientOpenConnections is the metric conforming to the - // "http.client.open_connections" semantic conventions. It represents the - // number of outbound HTTP connections that are currently active or idle on the - // client. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - HTTPClientOpenConnectionsName = "http.client.open_connections" - HTTPClientOpenConnectionsUnit = "{connection}" - HTTPClientOpenConnectionsDescription = "Number of outbound HTTP connections that are currently active or idle on the client." - - // HTTPClientConnectionDuration is the metric conforming to the - // "http.client.connection.duration" semantic conventions. It represents the - // duration of the successfully established outbound HTTP connections. - // Instrument: histogram - // Unit: s - // Stability: Experimental - HTTPClientConnectionDurationName = "http.client.connection.duration" - HTTPClientConnectionDurationUnit = "s" - HTTPClientConnectionDurationDescription = "The duration of the successfully established outbound HTTP connections." - - // HTTPClientActiveRequests is the metric conforming to the - // "http.client.active_requests" semantic conventions. It represents the number - // of active HTTP requests. - // Instrument: updowncounter - // Unit: {request} - // Stability: Experimental - HTTPClientActiveRequestsName = "http.client.active_requests" - HTTPClientActiveRequestsUnit = "{request}" - HTTPClientActiveRequestsDescription = "Number of active HTTP requests." - - // JvmMemoryInit is the metric conforming to the "jvm.memory.init" semantic - // conventions. It represents the measure of initial memory requested. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - JvmMemoryInitName = "jvm.memory.init" - JvmMemoryInitUnit = "By" - JvmMemoryInitDescription = "Measure of initial memory requested." - - // JvmSystemCPUUtilization is the metric conforming to the - // "jvm.system.cpu.utilization" semantic conventions. It represents the recent - // CPU utilization for the whole system as reported by the JVM. - // Instrument: gauge - // Unit: 1 - // Stability: Experimental - JvmSystemCPUUtilizationName = "jvm.system.cpu.utilization" - JvmSystemCPUUtilizationUnit = "1" - JvmSystemCPUUtilizationDescription = "Recent CPU utilization for the whole system as reported by the JVM." - - // JvmSystemCPULoad1m is the metric conforming to the "jvm.system.cpu.load_1m" - // semantic conventions. It represents the average CPU load of the whole system - // for the last minute as reported by the JVM. - // Instrument: gauge - // Unit: {run_queue_item} - // Stability: Experimental - JvmSystemCPULoad1mName = "jvm.system.cpu.load_1m" - JvmSystemCPULoad1mUnit = "{run_queue_item}" - JvmSystemCPULoad1mDescription = "Average CPU load of the whole system for the last minute as reported by the JVM." - - // JvmBufferMemoryUsage is the metric conforming to the - // "jvm.buffer.memory.usage" semantic conventions. It represents the measure of - // memory used by buffers. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - JvmBufferMemoryUsageName = "jvm.buffer.memory.usage" - JvmBufferMemoryUsageUnit = "By" - JvmBufferMemoryUsageDescription = "Measure of memory used by buffers." - - // JvmBufferMemoryLimit is the metric conforming to the - // "jvm.buffer.memory.limit" semantic conventions. It represents the measure of - // total memory capacity of buffers. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - JvmBufferMemoryLimitName = "jvm.buffer.memory.limit" - JvmBufferMemoryLimitUnit = "By" - JvmBufferMemoryLimitDescription = "Measure of total memory capacity of buffers." - - // JvmBufferCount is the metric conforming to the "jvm.buffer.count" semantic - // conventions. It represents the number of buffers in the pool. - // Instrument: updowncounter - // Unit: {buffer} - // Stability: Experimental - JvmBufferCountName = "jvm.buffer.count" - JvmBufferCountUnit = "{buffer}" - JvmBufferCountDescription = "Number of buffers in the pool." - - // JvmMemoryUsed is the metric conforming to the "jvm.memory.used" semantic - // conventions. It represents the measure of memory used. - // Instrument: updowncounter - // Unit: By - // Stability: Stable - JvmMemoryUsedName = "jvm.memory.used" - JvmMemoryUsedUnit = "By" - JvmMemoryUsedDescription = "Measure of memory used." - - // JvmMemoryCommitted is the metric conforming to the "jvm.memory.committed" - // semantic conventions. It represents the measure of memory committed. - // Instrument: updowncounter - // Unit: By - // Stability: Stable - JvmMemoryCommittedName = "jvm.memory.committed" - JvmMemoryCommittedUnit = "By" - JvmMemoryCommittedDescription = "Measure of memory committed." - - // JvmMemoryLimit is the metric conforming to the "jvm.memory.limit" semantic - // conventions. It represents the measure of max obtainable memory. - // Instrument: updowncounter - // Unit: By - // Stability: Stable - JvmMemoryLimitName = "jvm.memory.limit" - JvmMemoryLimitUnit = "By" - JvmMemoryLimitDescription = "Measure of max obtainable memory." - - // JvmMemoryUsedAfterLastGc is the metric conforming to the - // "jvm.memory.used_after_last_gc" semantic conventions. It represents the - // measure of memory used, as measured after the most recent garbage collection - // event on this pool. - // Instrument: updowncounter - // Unit: By - // Stability: Stable - JvmMemoryUsedAfterLastGcName = "jvm.memory.used_after_last_gc" - JvmMemoryUsedAfterLastGcUnit = "By" - JvmMemoryUsedAfterLastGcDescription = "Measure of memory used, as measured after the most recent garbage collection event on this pool." - - // JvmGcDuration is the metric conforming to the "jvm.gc.duration" semantic - // conventions. It represents the duration of JVM garbage collection actions. - // Instrument: histogram - // Unit: s - // Stability: Stable - JvmGcDurationName = "jvm.gc.duration" - JvmGcDurationUnit = "s" - JvmGcDurationDescription = "Duration of JVM garbage collection actions." - - // JvmThreadCount is the metric conforming to the "jvm.thread.count" semantic - // conventions. It represents the number of executing platform threads. - // Instrument: updowncounter - // Unit: {thread} - // Stability: Stable - JvmThreadCountName = "jvm.thread.count" - JvmThreadCountUnit = "{thread}" - JvmThreadCountDescription = "Number of executing platform threads." - - // JvmClassLoaded is the metric conforming to the "jvm.class.loaded" semantic - // conventions. It represents the number of classes loaded since JVM start. - // Instrument: counter - // Unit: {class} - // Stability: Stable - JvmClassLoadedName = "jvm.class.loaded" - JvmClassLoadedUnit = "{class}" - JvmClassLoadedDescription = "Number of classes loaded since JVM start." - - // JvmClassUnloaded is the metric conforming to the "jvm.class.unloaded" - // semantic conventions. It represents the number of classes unloaded since JVM - // start. - // Instrument: counter - // Unit: {class} - // Stability: Stable - JvmClassUnloadedName = "jvm.class.unloaded" - JvmClassUnloadedUnit = "{class}" - JvmClassUnloadedDescription = "Number of classes unloaded since JVM start." - - // JvmClassCount is the metric conforming to the "jvm.class.count" semantic - // conventions. It represents the number of classes currently loaded. - // Instrument: updowncounter - // Unit: {class} - // Stability: Stable - JvmClassCountName = "jvm.class.count" - JvmClassCountUnit = "{class}" - JvmClassCountDescription = "Number of classes currently loaded." - - // JvmCPUCount is the metric conforming to the "jvm.cpu.count" semantic - // conventions. It represents the number of processors available to the Java - // virtual machine. - // Instrument: updowncounter - // Unit: {cpu} - // Stability: Stable - JvmCPUCountName = "jvm.cpu.count" - JvmCPUCountUnit = "{cpu}" - JvmCPUCountDescription = "Number of processors available to the Java virtual machine." - - // JvmCPUTime is the metric conforming to the "jvm.cpu.time" semantic - // conventions. It represents the cPU time used by the process as reported by - // the JVM. - // Instrument: counter - // Unit: s - // Stability: Stable - JvmCPUTimeName = "jvm.cpu.time" - JvmCPUTimeUnit = "s" - JvmCPUTimeDescription = "CPU time used by the process as reported by the JVM." - - // JvmCPURecentUtilization is the metric conforming to the - // "jvm.cpu.recent_utilization" semantic conventions. It represents the recent - // CPU utilization for the process as reported by the JVM. - // Instrument: gauge - // Unit: 1 - // Stability: Stable - JvmCPURecentUtilizationName = "jvm.cpu.recent_utilization" - JvmCPURecentUtilizationUnit = "1" - JvmCPURecentUtilizationDescription = "Recent CPU utilization for the process as reported by the JVM." - - // MessagingPublishDuration is the metric conforming to the - // "messaging.publish.duration" semantic conventions. It represents the - // measures the duration of publish operation. - // Instrument: histogram - // Unit: s - // Stability: Experimental - MessagingPublishDurationName = "messaging.publish.duration" - MessagingPublishDurationUnit = "s" - MessagingPublishDurationDescription = "Measures the duration of publish operation." - - // MessagingReceiveDuration is the metric conforming to the - // "messaging.receive.duration" semantic conventions. It represents the - // measures the duration of receive operation. - // Instrument: histogram - // Unit: s - // Stability: Experimental - MessagingReceiveDurationName = "messaging.receive.duration" - MessagingReceiveDurationUnit = "s" - MessagingReceiveDurationDescription = "Measures the duration of receive operation." - - // MessagingProcessDuration is the metric conforming to the - // "messaging.process.duration" semantic conventions. It represents the - // measures the duration of process operation. - // Instrument: histogram - // Unit: s - // Stability: Experimental - MessagingProcessDurationName = "messaging.process.duration" - MessagingProcessDurationUnit = "s" - MessagingProcessDurationDescription = "Measures the duration of process operation." - - // MessagingPublishMessages is the metric conforming to the - // "messaging.publish.messages" semantic conventions. It represents the - // measures the number of published messages. - // Instrument: counter - // Unit: {message} - // Stability: Experimental - MessagingPublishMessagesName = "messaging.publish.messages" - MessagingPublishMessagesUnit = "{message}" - MessagingPublishMessagesDescription = "Measures the number of published messages." - - // MessagingReceiveMessages is the metric conforming to the - // "messaging.receive.messages" semantic conventions. It represents the - // measures the number of received messages. - // Instrument: counter - // Unit: {message} - // Stability: Experimental - MessagingReceiveMessagesName = "messaging.receive.messages" - MessagingReceiveMessagesUnit = "{message}" - MessagingReceiveMessagesDescription = "Measures the number of received messages." - - // MessagingProcessMessages is the metric conforming to the - // "messaging.process.messages" semantic conventions. It represents the - // measures the number of processed messages. - // Instrument: counter - // Unit: {message} - // Stability: Experimental - MessagingProcessMessagesName = "messaging.process.messages" - MessagingProcessMessagesUnit = "{message}" - MessagingProcessMessagesDescription = "Measures the number of processed messages." - - // ProcessCPUTime is the metric conforming to the "process.cpu.time" semantic - // conventions. It represents the total CPU seconds broken down by different - // states. - // Instrument: counter - // Unit: s - // Stability: Experimental - ProcessCPUTimeName = "process.cpu.time" - ProcessCPUTimeUnit = "s" - ProcessCPUTimeDescription = "Total CPU seconds broken down by different states." - - // ProcessCPUUtilization is the metric conforming to the - // "process.cpu.utilization" semantic conventions. It represents the difference - // in process.cpu.time since the last measurement, divided by the elapsed time - // and number of CPUs available to the process. - // Instrument: gauge - // Unit: 1 - // Stability: Experimental - ProcessCPUUtilizationName = "process.cpu.utilization" - ProcessCPUUtilizationUnit = "1" - ProcessCPUUtilizationDescription = "Difference in process.cpu.time since the last measurement, divided by the elapsed time and number of CPUs available to the process." - - // ProcessMemoryUsage is the metric conforming to the "process.memory.usage" - // semantic conventions. It represents the amount of physical memory in use. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - ProcessMemoryUsageName = "process.memory.usage" - ProcessMemoryUsageUnit = "By" - ProcessMemoryUsageDescription = "The amount of physical memory in use." - - // ProcessMemoryVirtual is the metric conforming to the - // "process.memory.virtual" semantic conventions. It represents the amount of - // committed virtual memory. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - ProcessMemoryVirtualName = "process.memory.virtual" - ProcessMemoryVirtualUnit = "By" - ProcessMemoryVirtualDescription = "The amount of committed virtual memory." - - // ProcessDiskIo is the metric conforming to the "process.disk.io" semantic - // conventions. It represents the disk bytes transferred. - // Instrument: counter - // Unit: By - // Stability: Experimental - ProcessDiskIoName = "process.disk.io" - ProcessDiskIoUnit = "By" - ProcessDiskIoDescription = "Disk bytes transferred." - - // ProcessNetworkIo is the metric conforming to the "process.network.io" - // semantic conventions. It represents the network bytes transferred. - // Instrument: counter - // Unit: By - // Stability: Experimental - ProcessNetworkIoName = "process.network.io" - ProcessNetworkIoUnit = "By" - ProcessNetworkIoDescription = "Network bytes transferred." - - // ProcessThreadCount is the metric conforming to the "process.thread.count" - // semantic conventions. It represents the process threads count. - // Instrument: updowncounter - // Unit: {thread} - // Stability: Experimental - ProcessThreadCountName = "process.thread.count" - ProcessThreadCountUnit = "{thread}" - ProcessThreadCountDescription = "Process threads count." - - // ProcessOpenFileDescriptorCount is the metric conforming to the - // "process.open_file_descriptor.count" semantic conventions. It represents the - // number of file descriptors in use by the process. - // Instrument: updowncounter - // Unit: {count} - // Stability: Experimental - ProcessOpenFileDescriptorCountName = "process.open_file_descriptor.count" - ProcessOpenFileDescriptorCountUnit = "{count}" - ProcessOpenFileDescriptorCountDescription = "Number of file descriptors in use by the process." - - // ProcessContextSwitches is the metric conforming to the - // "process.context_switches" semantic conventions. It represents the number of - // times the process has been context switched. - // Instrument: counter - // Unit: {count} - // Stability: Experimental - ProcessContextSwitchesName = "process.context_switches" - ProcessContextSwitchesUnit = "{count}" - ProcessContextSwitchesDescription = "Number of times the process has been context switched." - - // ProcessPagingFaults is the metric conforming to the "process.paging.faults" - // semantic conventions. It represents the number of page faults the process - // has made. - // Instrument: counter - // Unit: {fault} - // Stability: Experimental - ProcessPagingFaultsName = "process.paging.faults" - ProcessPagingFaultsUnit = "{fault}" - ProcessPagingFaultsDescription = "Number of page faults the process has made." - - // RPCServerDuration is the metric conforming to the "rpc.server.duration" - // semantic conventions. It represents the measures the duration of inbound - // RPC. - // Instrument: histogram - // Unit: ms - // Stability: Experimental - RPCServerDurationName = "rpc.server.duration" - RPCServerDurationUnit = "ms" - RPCServerDurationDescription = "Measures the duration of inbound RPC." - - // RPCServerRequestSize is the metric conforming to the - // "rpc.server.request.size" semantic conventions. It represents the measures - // the size of RPC request messages (uncompressed). - // Instrument: histogram - // Unit: By - // Stability: Experimental - RPCServerRequestSizeName = "rpc.server.request.size" - RPCServerRequestSizeUnit = "By" - RPCServerRequestSizeDescription = "Measures the size of RPC request messages (uncompressed)." - - // RPCServerResponseSize is the metric conforming to the - // "rpc.server.response.size" semantic conventions. It represents the measures - // the size of RPC response messages (uncompressed). - // Instrument: histogram - // Unit: By - // Stability: Experimental - RPCServerResponseSizeName = "rpc.server.response.size" - RPCServerResponseSizeUnit = "By" - RPCServerResponseSizeDescription = "Measures the size of RPC response messages (uncompressed)." - - // RPCServerRequestsPerRPC is the metric conforming to the - // "rpc.server.requests_per_rpc" semantic conventions. It represents the - // measures the number of messages received per RPC. - // Instrument: histogram - // Unit: {count} - // Stability: Experimental - RPCServerRequestsPerRPCName = "rpc.server.requests_per_rpc" - RPCServerRequestsPerRPCUnit = "{count}" - RPCServerRequestsPerRPCDescription = "Measures the number of messages received per RPC." - - // RPCServerResponsesPerRPC is the metric conforming to the - // "rpc.server.responses_per_rpc" semantic conventions. It represents the - // measures the number of messages sent per RPC. - // Instrument: histogram - // Unit: {count} - // Stability: Experimental - RPCServerResponsesPerRPCName = "rpc.server.responses_per_rpc" - RPCServerResponsesPerRPCUnit = "{count}" - RPCServerResponsesPerRPCDescription = "Measures the number of messages sent per RPC." - - // RPCClientDuration is the metric conforming to the "rpc.client.duration" - // semantic conventions. It represents the measures the duration of outbound - // RPC. - // Instrument: histogram - // Unit: ms - // Stability: Experimental - RPCClientDurationName = "rpc.client.duration" - RPCClientDurationUnit = "ms" - RPCClientDurationDescription = "Measures the duration of outbound RPC." - - // RPCClientRequestSize is the metric conforming to the - // "rpc.client.request.size" semantic conventions. It represents the measures - // the size of RPC request messages (uncompressed). - // Instrument: histogram - // Unit: By - // Stability: Experimental - RPCClientRequestSizeName = "rpc.client.request.size" - RPCClientRequestSizeUnit = "By" - RPCClientRequestSizeDescription = "Measures the size of RPC request messages (uncompressed)." - - // RPCClientResponseSize is the metric conforming to the - // "rpc.client.response.size" semantic conventions. It represents the measures - // the size of RPC response messages (uncompressed). - // Instrument: histogram - // Unit: By - // Stability: Experimental - RPCClientResponseSizeName = "rpc.client.response.size" - RPCClientResponseSizeUnit = "By" - RPCClientResponseSizeDescription = "Measures the size of RPC response messages (uncompressed)." - - // RPCClientRequestsPerRPC is the metric conforming to the - // "rpc.client.requests_per_rpc" semantic conventions. It represents the - // measures the number of messages received per RPC. - // Instrument: histogram - // Unit: {count} - // Stability: Experimental - RPCClientRequestsPerRPCName = "rpc.client.requests_per_rpc" - RPCClientRequestsPerRPCUnit = "{count}" - RPCClientRequestsPerRPCDescription = "Measures the number of messages received per RPC." - - // RPCClientResponsesPerRPC is the metric conforming to the - // "rpc.client.responses_per_rpc" semantic conventions. It represents the - // measures the number of messages sent per RPC. - // Instrument: histogram - // Unit: {count} - // Stability: Experimental - RPCClientResponsesPerRPCName = "rpc.client.responses_per_rpc" - RPCClientResponsesPerRPCUnit = "{count}" - RPCClientResponsesPerRPCDescription = "Measures the number of messages sent per RPC." - - // SystemCPUTime is the metric conforming to the "system.cpu.time" semantic - // conventions. It represents the seconds each logical CPU spent on each mode. - // Instrument: counter - // Unit: s - // Stability: Experimental - SystemCPUTimeName = "system.cpu.time" - SystemCPUTimeUnit = "s" - SystemCPUTimeDescription = "Seconds each logical CPU spent on each mode" - - // SystemCPUUtilization is the metric conforming to the - // "system.cpu.utilization" semantic conventions. It represents the difference - // in system.cpu.time since the last measurement, divided by the elapsed time - // and number of logical CPUs. - // Instrument: gauge - // Unit: 1 - // Stability: Experimental - SystemCPUUtilizationName = "system.cpu.utilization" - SystemCPUUtilizationUnit = "1" - SystemCPUUtilizationDescription = "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs" - - // SystemCPUFrequency is the metric conforming to the "system.cpu.frequency" - // semantic conventions. It represents the reports the current frequency of the - // CPU in Hz. - // Instrument: gauge - // Unit: {Hz} - // Stability: Experimental - SystemCPUFrequencyName = "system.cpu.frequency" - SystemCPUFrequencyUnit = "{Hz}" - SystemCPUFrequencyDescription = "Reports the current frequency of the CPU in Hz" - - // SystemCPUPhysicalCount is the metric conforming to the - // "system.cpu.physical.count" semantic conventions. It represents the reports - // the number of actual physical processor cores on the hardware. - // Instrument: updowncounter - // Unit: {cpu} - // Stability: Experimental - SystemCPUPhysicalCountName = "system.cpu.physical.count" - SystemCPUPhysicalCountUnit = "{cpu}" - SystemCPUPhysicalCountDescription = "Reports the number of actual physical processor cores on the hardware" - - // SystemCPULogicalCount is the metric conforming to the - // "system.cpu.logical.count" semantic conventions. It represents the reports - // the number of logical (virtual) processor cores created by the operating - // system to manage multitasking. - // Instrument: updowncounter - // Unit: {cpu} - // Stability: Experimental - SystemCPULogicalCountName = "system.cpu.logical.count" - SystemCPULogicalCountUnit = "{cpu}" - SystemCPULogicalCountDescription = "Reports the number of logical (virtual) processor cores created by the operating system to manage multitasking" - - // SystemMemoryUsage is the metric conforming to the "system.memory.usage" - // semantic conventions. It represents the reports memory in use by state. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - SystemMemoryUsageName = "system.memory.usage" - SystemMemoryUsageUnit = "By" - SystemMemoryUsageDescription = "Reports memory in use by state." - - // SystemMemoryLimit is the metric conforming to the "system.memory.limit" - // semantic conventions. It represents the total memory available in the - // system. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - SystemMemoryLimitName = "system.memory.limit" - SystemMemoryLimitUnit = "By" - SystemMemoryLimitDescription = "Total memory available in the system." - - // SystemMemoryShared is the metric conforming to the "system.memory.shared" - // semantic conventions. It represents the shared memory used (mostly by - // tmpfs). - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - SystemMemorySharedName = "system.memory.shared" - SystemMemorySharedUnit = "By" - SystemMemorySharedDescription = "Shared memory used (mostly by tmpfs)." - - // SystemMemoryUtilization is the metric conforming to the - // "system.memory.utilization" semantic conventions. - // Instrument: gauge - // Unit: 1 - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemMemoryUtilizationName = "system.memory.utilization" - SystemMemoryUtilizationUnit = "1" - - // SystemPagingUsage is the metric conforming to the "system.paging.usage" - // semantic conventions. It represents the unix swap or windows pagefile usage. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - SystemPagingUsageName = "system.paging.usage" - SystemPagingUsageUnit = "By" - SystemPagingUsageDescription = "Unix swap or windows pagefile usage" - - // SystemPagingUtilization is the metric conforming to the - // "system.paging.utilization" semantic conventions. - // Instrument: gauge - // Unit: 1 - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemPagingUtilizationName = "system.paging.utilization" - SystemPagingUtilizationUnit = "1" - - // SystemPagingFaults is the metric conforming to the "system.paging.faults" - // semantic conventions. - // Instrument: counter - // Unit: {fault} - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemPagingFaultsName = "system.paging.faults" - SystemPagingFaultsUnit = "{fault}" - - // SystemPagingOperations is the metric conforming to the - // "system.paging.operations" semantic conventions. - // Instrument: counter - // Unit: {operation} - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemPagingOperationsName = "system.paging.operations" - SystemPagingOperationsUnit = "{operation}" - - // SystemDiskIo is the metric conforming to the "system.disk.io" semantic - // conventions. - // Instrument: counter - // Unit: By - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemDiskIoName = "system.disk.io" - SystemDiskIoUnit = "By" - - // SystemDiskOperations is the metric conforming to the - // "system.disk.operations" semantic conventions. - // Instrument: counter - // Unit: {operation} - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemDiskOperationsName = "system.disk.operations" - SystemDiskOperationsUnit = "{operation}" - - // SystemDiskIoTime is the metric conforming to the "system.disk.io_time" - // semantic conventions. It represents the time disk spent activated. - // Instrument: counter - // Unit: s - // Stability: Experimental - SystemDiskIoTimeName = "system.disk.io_time" - SystemDiskIoTimeUnit = "s" - SystemDiskIoTimeDescription = "Time disk spent activated" - - // SystemDiskOperationTime is the metric conforming to the - // "system.disk.operation_time" semantic conventions. It represents the sum of - // the time each operation took to complete. - // Instrument: counter - // Unit: s - // Stability: Experimental - SystemDiskOperationTimeName = "system.disk.operation_time" - SystemDiskOperationTimeUnit = "s" - SystemDiskOperationTimeDescription = "Sum of the time each operation took to complete" - - // SystemDiskMerged is the metric conforming to the "system.disk.merged" - // semantic conventions. - // Instrument: counter - // Unit: {operation} - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemDiskMergedName = "system.disk.merged" - SystemDiskMergedUnit = "{operation}" - - // SystemFilesystemUsage is the metric conforming to the - // "system.filesystem.usage" semantic conventions. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemFilesystemUsageName = "system.filesystem.usage" - SystemFilesystemUsageUnit = "By" - - // SystemFilesystemUtilization is the metric conforming to the - // "system.filesystem.utilization" semantic conventions. - // Instrument: gauge - // Unit: 1 - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemFilesystemUtilizationName = "system.filesystem.utilization" - SystemFilesystemUtilizationUnit = "1" - - // SystemNetworkDropped is the metric conforming to the - // "system.network.dropped" semantic conventions. It represents the count of - // packets that are dropped or discarded even though there was no error. - // Instrument: counter - // Unit: {packet} - // Stability: Experimental - SystemNetworkDroppedName = "system.network.dropped" - SystemNetworkDroppedUnit = "{packet}" - SystemNetworkDroppedDescription = "Count of packets that are dropped or discarded even though there was no error" - - // SystemNetworkPackets is the metric conforming to the - // "system.network.packets" semantic conventions. - // Instrument: counter - // Unit: {packet} - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemNetworkPacketsName = "system.network.packets" - SystemNetworkPacketsUnit = "{packet}" - - // SystemNetworkErrors is the metric conforming to the "system.network.errors" - // semantic conventions. It represents the count of network errors detected. - // Instrument: counter - // Unit: {error} - // Stability: Experimental - SystemNetworkErrorsName = "system.network.errors" - SystemNetworkErrorsUnit = "{error}" - SystemNetworkErrorsDescription = "Count of network errors detected" - - // SystemNetworkIo is the metric conforming to the "system.network.io" semantic - // conventions. - // Instrument: counter - // Unit: By - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemNetworkIoName = "system.network.io" - SystemNetworkIoUnit = "By" - - // SystemNetworkConnections is the metric conforming to the - // "system.network.connections" semantic conventions. - // Instrument: updowncounter - // Unit: {connection} - // Stability: Experimental - // NOTE: The description (brief) for this metric is not defined in the semantic-conventions repository. - SystemNetworkConnectionsName = "system.network.connections" - SystemNetworkConnectionsUnit = "{connection}" - - // SystemProcessCount is the metric conforming to the "system.process.count" - // semantic conventions. It represents the total number of processes in each - // state. - // Instrument: updowncounter - // Unit: {process} - // Stability: Experimental - SystemProcessCountName = "system.process.count" - SystemProcessCountUnit = "{process}" - SystemProcessCountDescription = "Total number of processes in each state" - - // SystemProcessCreated is the metric conforming to the - // "system.process.created" semantic conventions. It represents the total - // number of processes created over uptime of the host. - // Instrument: counter - // Unit: {process} - // Stability: Experimental - SystemProcessCreatedName = "system.process.created" - SystemProcessCreatedUnit = "{process}" - SystemProcessCreatedDescription = "Total number of processes created over uptime of the host" - - // SystemLinuxMemoryAvailable is the metric conforming to the - // "system.linux.memory.available" semantic conventions. It represents an - // estimate of how much memory is available for starting new applications, - // without causing swapping. - // Instrument: updowncounter - // Unit: By - // Stability: Experimental - SystemLinuxMemoryAvailableName = "system.linux.memory.available" - SystemLinuxMemoryAvailableUnit = "By" - SystemLinuxMemoryAvailableDescription = "An estimate of how much memory is available for starting new applications, without causing swapping" -) diff --git a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/schema.go b/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/schema.go deleted file mode 100644 index 4c87c7ad..00000000 --- a/vendor/go.opentelemetry.io/otel/semconv/v1.26.0/schema.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package semconv // import "go.opentelemetry.io/otel/semconv/v1.26.0" - -// SchemaURL is the schema URL that matches the version of the semantic conventions -// that this package defines. Semconv packages starting from v1.4.0 must declare -// non-empty schema URL in the form https://opentelemetry.io/schemas/ -const SchemaURL = "https://opentelemetry.io/schemas/1.26.0" diff --git a/vendor/go.opentelemetry.io/otel/trace.go b/vendor/go.opentelemetry.io/otel/trace.go index 6836c654..caf7249d 100644 --- a/vendor/go.opentelemetry.io/otel/trace.go +++ b/vendor/go.opentelemetry.io/otel/trace.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" diff --git a/vendor/go.opentelemetry.io/otel/trace/README.md b/vendor/go.opentelemetry.io/otel/trace/README.md deleted file mode 100644 index 58ccaba6..00000000 --- a/vendor/go.opentelemetry.io/otel/trace/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Trace API - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/trace)](https://pkg.go.dev/go.opentelemetry.io/otel/trace) diff --git a/vendor/go.opentelemetry.io/otel/trace/config.go b/vendor/go.opentelemetry.io/otel/trace/config.go index 273d58e0..3aadc66c 100644 --- a/vendor/go.opentelemetry.io/otel/trace/config.go +++ b/vendor/go.opentelemetry.io/otel/trace/config.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/trace" diff --git a/vendor/go.opentelemetry.io/otel/trace/context.go b/vendor/go.opentelemetry.io/otel/trace/context.go index 5650a174..76f9a083 100644 --- a/vendor/go.opentelemetry.io/otel/trace/context.go +++ b/vendor/go.opentelemetry.io/otel/trace/context.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/trace" @@ -36,12 +47,12 @@ func ContextWithRemoteSpanContext(parent context.Context, rsc SpanContext) conte // performs no operations is returned. func SpanFromContext(ctx context.Context) Span { if ctx == nil { - return noopSpanInstance + return noopSpan{} } if span, ok := ctx.Value(currentSpanKey).(Span); ok { return span } - return noopSpanInstance + return noopSpan{} } // SpanContextFromContext returns the current Span's SpanContext. diff --git a/vendor/go.opentelemetry.io/otel/trace/doc.go b/vendor/go.opentelemetry.io/otel/trace/doc.go index d661c5d1..440f3d75 100644 --- a/vendor/go.opentelemetry.io/otel/trace/doc.go +++ b/vendor/go.opentelemetry.io/otel/trace/doc.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /* Package trace provides an implementation of the tracing part of the diff --git a/vendor/go.opentelemetry.io/otel/trace/embedded/README.md b/vendor/go.opentelemetry.io/otel/trace/embedded/README.md deleted file mode 100644 index 7754a239..00000000 --- a/vendor/go.opentelemetry.io/otel/trace/embedded/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Trace Embedded - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/trace/embedded)](https://pkg.go.dev/go.opentelemetry.io/otel/trace/embedded) diff --git a/vendor/go.opentelemetry.io/otel/trace/embedded/embedded.go b/vendor/go.opentelemetry.io/otel/trace/embedded/embedded.go index 3e359a00..898db5a7 100644 --- a/vendor/go.opentelemetry.io/otel/trace/embedded/embedded.go +++ b/vendor/go.opentelemetry.io/otel/trace/embedded/embedded.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package embedded provides interfaces embedded within the [OpenTelemetry // trace API]. diff --git a/vendor/go.opentelemetry.io/otel/trace/nonrecording.go b/vendor/go.opentelemetry.io/otel/trace/nonrecording.go index c00221e7..88fcb816 100644 --- a/vendor/go.opentelemetry.io/otel/trace/nonrecording.go +++ b/vendor/go.opentelemetry.io/otel/trace/nonrecording.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/trace" diff --git a/vendor/go.opentelemetry.io/otel/trace/noop.go b/vendor/go.opentelemetry.io/otel/trace/noop.go index ca20e999..c125491c 100644 --- a/vendor/go.opentelemetry.io/otel/trace/noop.go +++ b/vendor/go.opentelemetry.io/otel/trace/noop.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/trace" @@ -41,7 +52,7 @@ func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption span := SpanFromContext(ctx) if _, ok := span.(nonRecordingSpan); !ok { // span is likely already a noopSpan, but let's be sure - span = noopSpanInstance + span = noopSpan{} } return ContextWithSpan(ctx, span), span } @@ -49,7 +60,7 @@ func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption // noopSpan is an implementation of Span that performs no operations. type noopSpan struct{ embedded.Span } -var noopSpanInstance Span = noopSpan{} +var _ Span = noopSpan{} // SpanContext returns an empty span context. func (noopSpan) SpanContext() SpanContext { return SpanContext{} } @@ -75,9 +86,6 @@ func (noopSpan) RecordError(error, ...EventOption) {} // AddEvent does nothing. func (noopSpan) AddEvent(string, ...EventOption) {} -// AddLink does nothing. -func (noopSpan) AddLink(Link) {} - // SetName does nothing. func (noopSpan) SetName(string) {} diff --git a/vendor/go.opentelemetry.io/otel/trace/noop/README.md b/vendor/go.opentelemetry.io/otel/trace/noop/README.md deleted file mode 100644 index cd382c82..00000000 --- a/vendor/go.opentelemetry.io/otel/trace/noop/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Trace Noop - -[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/trace/noop)](https://pkg.go.dev/go.opentelemetry.io/otel/trace/noop) diff --git a/vendor/go.opentelemetry.io/otel/trace/noop/noop.go b/vendor/go.opentelemetry.io/otel/trace/noop/noop.go index 64a4f1b3..7f485543 100644 --- a/vendor/go.opentelemetry.io/otel/trace/noop/noop.go +++ b/vendor/go.opentelemetry.io/otel/trace/noop/noop.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package noop provides an implementation of the OpenTelemetry trace API that // produces no telemetry and minimizes used computation resources. @@ -67,13 +78,11 @@ func (t Tracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) span = Span{sc: sc} } else { // No parent, return a No-Op span with an empty span context. - span = noopSpanInstance + span = Span{} } return trace.ContextWithSpan(ctx, span), span } -var noopSpanInstance trace.Span = Span{} - // Span is an OpenTelemetry No-Op Span. type Span struct { embedded.Span @@ -102,9 +111,6 @@ func (Span) RecordError(error, ...trace.EventOption) {} // AddEvent does nothing. func (Span) AddEvent(string, ...trace.EventOption) {} -// AddLink does nothing. -func (Span) AddLink(trace.Link) {} - // SetName does nothing. func (Span) SetName(string) {} diff --git a/vendor/go.opentelemetry.io/otel/trace/trace.go b/vendor/go.opentelemetry.io/otel/trace/trace.go index 28877d4a..26a4b226 100644 --- a/vendor/go.opentelemetry.io/otel/trace/trace.go +++ b/vendor/go.opentelemetry.io/otel/trace/trace.go @@ -1,5 +1,16 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/trace" @@ -350,12 +361,6 @@ type Span interface { // AddEvent adds an event with the provided name and options. AddEvent(name string, options ...EventOption) - // AddLink adds a link. - // Adding links at span creation using WithLinks is preferred to calling AddLink - // later, for contexts that are available during span creation, because head - // sampling decisions can only consider information present during span creation. - AddLink(link Link) - // IsRecording returns the recording state of the Span. It will return // true if the Span is active and events can be recorded. IsRecording() bool diff --git a/vendor/go.opentelemetry.io/otel/trace/tracestate.go b/vendor/go.opentelemetry.io/otel/trace/tracestate.go index 20b5cf24..d1e47ca2 100644 --- a/vendor/go.opentelemetry.io/otel/trace/tracestate.go +++ b/vendor/go.opentelemetry.io/otel/trace/tracestate.go @@ -1,19 +1,36 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package trace // import "go.opentelemetry.io/otel/trace" import ( "encoding/json" "fmt" + "regexp" "strings" ) const ( maxListMembers = 32 - listDelimiters = "," - memberDelimiter = "=" + listDelimiter = "," + + // based on the W3C Trace Context specification, see + // https://www.w3.org/TR/trace-context-1/#tracestate-header + noTenantKeyFormat = `[a-z][_0-9a-z\-\*\/]*` + withTenantKeyFormat = `[a-z0-9][_0-9a-z\-\*\/]*@[a-z][_0-9a-z\-\*\/]*` + valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]*[\x21-\x2b\x2d-\x3c\x3e-\x7e]` errInvalidKey errorConst = "invalid tracestate key" errInvalidValue errorConst = "invalid tracestate value" @@ -22,128 +39,43 @@ const ( errDuplicate errorConst = "duplicate list-member in tracestate" ) +var ( + noTenantKeyRe = regexp.MustCompile(`^` + noTenantKeyFormat + `$`) + withTenantKeyRe = regexp.MustCompile(`^` + withTenantKeyFormat + `$`) + valueRe = regexp.MustCompile(`^` + valueFormat + `$`) + memberRe = regexp.MustCompile(`^\s*((?:` + noTenantKeyFormat + `)|(?:` + withTenantKeyFormat + `))=(` + valueFormat + `)\s*$`) +) + type member struct { Key string Value string } -// according to (chr = %x20 / (nblk-char = %x21-2B / %x2D-3C / %x3E-7E) ) -// means (chr = %x20-2B / %x2D-3C / %x3E-7E) . -func checkValueChar(v byte) bool { - return v >= '\x20' && v <= '\x7e' && v != '\x2c' && v != '\x3d' -} - -// according to (nblk-chr = %x21-2B / %x2D-3C / %x3E-7E) . -func checkValueLast(v byte) bool { - return v >= '\x21' && v <= '\x7e' && v != '\x2c' && v != '\x3d' -} - -// based on the W3C Trace Context specification -// -// value = (0*255(chr)) nblk-chr -// nblk-chr = %x21-2B / %x2D-3C / %x3E-7E -// chr = %x20 / nblk-chr -// -// see https://www.w3.org/TR/trace-context-1/#value -func checkValue(val string) bool { - n := len(val) - if n == 0 || n > 256 { - return false - } - for i := 0; i < n-1; i++ { - if !checkValueChar(val[i]) { - return false - } +func newMember(key, value string) (member, error) { + if len(key) > 256 { + return member{}, fmt.Errorf("%w: %s", errInvalidKey, key) } - return checkValueLast(val[n-1]) -} - -func checkKeyRemain(key string) bool { - // ( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ) - for _, v := range key { - if isAlphaNum(byte(v)) { - continue + if !noTenantKeyRe.MatchString(key) { + if !withTenantKeyRe.MatchString(key) { + return member{}, fmt.Errorf("%w: %s", errInvalidKey, key) } - switch v { - case '_', '-', '*', '/': - continue + atIndex := strings.LastIndex(key, "@") + if atIndex > 241 || len(key)-1-atIndex > 14 { + return member{}, fmt.Errorf("%w: %s", errInvalidKey, key) } - return false } - return true -} - -// according to -// -// simple-key = lcalpha (0*255( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )) -// system-id = lcalpha (0*13( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )) -// -// param n is remain part length, should be 255 in simple-key or 13 in system-id. -func checkKeyPart(key string, n int) bool { - if len(key) == 0 { - return false - } - first := key[0] // key's first char - ret := len(key[1:]) <= n - ret = ret && first >= 'a' && first <= 'z' - return ret && checkKeyRemain(key[1:]) -} - -func isAlphaNum(c byte) bool { - if c >= 'a' && c <= 'z' { - return true - } - return c >= '0' && c <= '9' -} - -// according to -// -// tenant-id = ( lcalpha / DIGIT ) 0*240( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ) -// -// param n is remain part length, should be 240 exactly. -func checkKeyTenant(key string, n int) bool { - if len(key) == 0 { - return false - } - return isAlphaNum(key[0]) && len(key[1:]) <= n && checkKeyRemain(key[1:]) -} - -// based on the W3C Trace Context specification -// -// key = simple-key / multi-tenant-key -// simple-key = lcalpha (0*255( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )) -// multi-tenant-key = tenant-id "@" system-id -// tenant-id = ( lcalpha / DIGIT ) (0*240( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )) -// system-id = lcalpha (0*13( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )) -// lcalpha = %x61-7A ; a-z -// -// see https://www.w3.org/TR/trace-context-1/#tracestate-header. -func checkKey(key string) bool { - tenant, system, ok := strings.Cut(key, "@") - if !ok { - return checkKeyPart(key, 255) - } - return checkKeyTenant(tenant, 240) && checkKeyPart(system, 13) -} - -func newMember(key, value string) (member, error) { - if !checkKey(key) { - return member{}, errInvalidKey - } - if !checkValue(value) { - return member{}, errInvalidValue + if len(value) > 256 || !valueRe.MatchString(value) { + return member{}, fmt.Errorf("%w: %s", errInvalidValue, value) } return member{Key: key, Value: value}, nil } func parseMember(m string) (member, error) { - key, val, ok := strings.Cut(m, memberDelimiter) - if !ok { + matches := memberRe.FindStringSubmatch(m) + if len(matches) != 3 { return member{}, fmt.Errorf("%w: %s", errInvalidMember, m) } - key = strings.TrimLeft(key, " \t") - val = strings.TrimRight(val, " \t") - result, e := newMember(key, val) + result, e := newMember(matches[1], matches[2]) if e != nil { return member{}, fmt.Errorf("%w: %s", errInvalidMember, m) } @@ -153,7 +85,7 @@ func parseMember(m string) (member, error) { // String encodes member into a string compliant with the W3C Trace Context // specification. func (m member) String() string { - return m.Key + "=" + m.Value + return fmt.Sprintf("%s=%s", m.Key, m.Value) } // TraceState provides additional vendor-specific trace identification @@ -177,8 +109,8 @@ var _ json.Marshaler = TraceState{} // ParseTraceState attempts to decode a TraceState from the passed // string. It returns an error if the input is invalid according to the W3C // Trace Context specification. -func ParseTraceState(ts string) (TraceState, error) { - if ts == "" { +func ParseTraceState(tracestate string) (TraceState, error) { + if tracestate == "" { return TraceState{}, nil } @@ -188,9 +120,7 @@ func ParseTraceState(ts string) (TraceState, error) { var members []member found := make(map[string]struct{}) - for ts != "" { - var memberStr string - memberStr, ts, _ = strings.Cut(ts, listDelimiters) + for _, memberStr := range strings.Split(tracestate, listDelimiter) { if len(memberStr) == 0 { continue } @@ -223,29 +153,11 @@ func (ts TraceState) MarshalJSON() ([]byte, error) { // Trace Context specification. The returned string will be invalid if the // TraceState contains any invalid members. func (ts TraceState) String() string { - if len(ts.list) == 0 { - return "" - } - var n int - n += len(ts.list) // member delimiters: '=' - n += len(ts.list) - 1 // list delimiters: ',' - for _, mem := range ts.list { - n += len(mem.Key) - n += len(mem.Value) + members := make([]string, len(ts.list)) + for i, m := range ts.list { + members[i] = m.String() } - - var sb strings.Builder - sb.Grow(n) - _, _ = sb.WriteString(ts.list[0].Key) - _ = sb.WriteByte('=') - _, _ = sb.WriteString(ts.list[0].Value) - for i := 1; i < len(ts.list); i++ { - _ = sb.WriteByte(listDelimiters[0]) - _, _ = sb.WriteString(ts.list[i].Key) - _ = sb.WriteByte('=') - _, _ = sb.WriteString(ts.list[i].Value) - } - return sb.String() + return strings.Join(members, listDelimiter) } // Get returns the value paired with key from the corresponding TraceState @@ -277,25 +189,15 @@ func (ts TraceState) Insert(key, value string) (TraceState, error) { if err != nil { return ts, err } - n := len(ts.list) - found := n - for i := range ts.list { - if ts.list[i].Key == key { - found = i - } - } - cTS := TraceState{} - if found == n && n < maxListMembers { - cTS.list = make([]member, n+1) - } else { - cTS.list = make([]member, n) + + cTS := ts.Delete(key) + if cTS.Len()+1 <= maxListMembers { + cTS.list = append(cTS.list, member{}) } - cTS.list[0] = m // When the number of members exceeds capacity, drop the "right-most". - copy(cTS.list[1:], ts.list[0:found]) - if found < n { - copy(cTS.list[1+found:], ts.list[found+1:]) - } + copy(cTS.list[1:], cTS.list) + cTS.list[0] = m + return cTS, nil } diff --git a/vendor/go.opentelemetry.io/otel/verify_examples.sh b/vendor/go.opentelemetry.io/otel/verify_examples.sh index e57bf57f..dbb61a42 100644 --- a/vendor/go.opentelemetry.io/otel/verify_examples.sh +++ b/vendor/go.opentelemetry.io/otel/verify_examples.sh @@ -1,7 +1,18 @@ #!/bin/bash # Copyright The OpenTelemetry Authors -# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. set -euo pipefail diff --git a/vendor/go.opentelemetry.io/otel/verify_readmes.sh b/vendor/go.opentelemetry.io/otel/verify_readmes.sh deleted file mode 100644 index 1e87855e..00000000 --- a/vendor/go.opentelemetry.io/otel/verify_readmes.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# Copyright The OpenTelemetry Authors -# SPDX-License-Identifier: Apache-2.0 - -set -euo pipefail - -dirs=$(find . -type d -not -path "*/internal*" -not -path "*/test*" -not -path "*/example*" -not -path "*/.*" | sort) - -missingReadme=false -for dir in $dirs; do - if [ ! -f "$dir/README.md" ]; then - echo "couldn't find README.md for $dir" - missingReadme=true - fi -done - -if [ "$missingReadme" = true ] ; then - echo "Error: some READMEs couldn't be found." - exit 1 -fi diff --git a/vendor/go.opentelemetry.io/otel/version.go b/vendor/go.opentelemetry.io/otel/version.go index ab289605..e2f74358 100644 --- a/vendor/go.opentelemetry.io/otel/version.go +++ b/vendor/go.opentelemetry.io/otel/version.go @@ -1,9 +1,20 @@ // Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package otel // import "go.opentelemetry.io/otel" // Version is the current release version of OpenTelemetry in use. func Version() string { - return "1.28.0" + return "1.21.0" } diff --git a/vendor/go.opentelemetry.io/otel/versions.yaml b/vendor/go.opentelemetry.io/otel/versions.yaml index 241cfc82..3c153c9d 100644 --- a/vendor/go.opentelemetry.io/otel/versions.yaml +++ b/vendor/go.opentelemetry.io/otel/versions.yaml @@ -1,27 +1,32 @@ # Copyright The OpenTelemetry Authors -# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module-sets: stable-v1: - version: v1.28.0 + version: v1.21.0 modules: - go.opentelemetry.io/otel - - go.opentelemetry.io/otel/bridge/opencensus - - go.opentelemetry.io/otel/bridge/opencensus/test - go.opentelemetry.io/otel/bridge/opentracing - go.opentelemetry.io/otel/bridge/opentracing/test - go.opentelemetry.io/otel/example/dice - go.opentelemetry.io/otel/example/namedtracer - - go.opentelemetry.io/otel/example/opencensus - go.opentelemetry.io/otel/example/otel-collector - go.opentelemetry.io/otel/example/passthrough - go.opentelemetry.io/otel/example/zipkin - - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc - - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp - go.opentelemetry.io/otel/exporters/otlp/otlptrace - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp - - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric - go.opentelemetry.io/otel/exporters/stdout/stdouttrace - go.opentelemetry.io/otel/exporters/zipkin - go.opentelemetry.io/otel/metric @@ -29,21 +34,19 @@ module-sets: - go.opentelemetry.io/otel/sdk/metric - go.opentelemetry.io/otel/trace experimental-metrics: - version: v0.50.0 + version: v0.44.0 modules: + - go.opentelemetry.io/otel/bridge/opencensus + - go.opentelemetry.io/otel/bridge/opencensus/test + - go.opentelemetry.io/otel/example/opencensus - go.opentelemetry.io/otel/example/prometheus + - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc + - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp - go.opentelemetry.io/otel/exporters/prometheus - experimental-logs: - version: v0.4.0 - modules: - - go.opentelemetry.io/otel/log - - go.opentelemetry.io/otel/sdk/log - - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp - - go.opentelemetry.io/otel/exporters/stdout/stdoutlog + - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric experimental-schema: - version: v0.0.8 + version: v0.0.7 modules: - go.opentelemetry.io/otel/schema excluded-modules: - go.opentelemetry.io/otel/internal/tools - - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go index 3bee6629..f4ded5fe 100644 --- a/vendor/golang.org/x/crypto/hkdf/hkdf.go +++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go @@ -8,7 +8,7 @@ // HKDF is a cryptographic key derivation function (KDF) with the goal of // expanding limited input keying material into one or more cryptographically // strong secret keys. -package hkdf +package hkdf // import "golang.org/x/crypto/hkdf" import ( "crypto/hmac" diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go index 28cd99c7..904b57e0 100644 --- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -16,7 +16,7 @@ Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To choose, you can pass the `New` functions from the different SHA packages to pbkdf2.Key. */ -package pbkdf2 +package pbkdf2 // import "golang.org/x/crypto/pbkdf2" import ( "crypto/hmac" diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go index b6d33ef0..cf3eeb15 100644 --- a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go @@ -7,7 +7,7 @@ // Deprecated: RIPEMD-160 is a legacy hash and should not be used for new // applications. Also, this package does not and will not provide an optimized // implementation. Instead, use a modern hash like SHA-256 (from crypto/sha256). -package ripemd160 +package ripemd160 // import "golang.org/x/crypto/ripemd160" // RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart // Preneel with specifications available at: diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go index 76fa40fb..c971a99f 100644 --- a/vendor/golang.org/x/crypto/scrypt/scrypt.go +++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go @@ -5,7 +5,7 @@ // Package scrypt implements the scrypt key derivation function as defined in // Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard // Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf). -package scrypt +package scrypt // import "golang.org/x/crypto/scrypt" import ( "crypto/sha256" diff --git a/vendor/golang.org/x/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go index 7e023090..decd8cf9 100644 --- a/vendor/golang.org/x/crypto/sha3/doc.go +++ b/vendor/golang.org/x/crypto/sha3/doc.go @@ -59,4 +59,4 @@ // They produce output of the same length, with the same security strengths // against all attacks. This means, in particular, that SHA3-256 only has // 128-bit collision resistance, because its output length is 32 bytes. -package sha3 +package sha3 // import "golang.org/x/crypto/sha3" diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go index c544b29e..5eae6cb9 100644 --- a/vendor/golang.org/x/crypto/sha3/hashes.go +++ b/vendor/golang.org/x/crypto/sha3/hashes.go @@ -9,7 +9,6 @@ package sha3 // bytes. import ( - "crypto" "hash" ) @@ -41,13 +40,6 @@ func New512() hash.Hash { return new512() } -func init() { - crypto.RegisterHash(crypto.SHA3_224, New224) - crypto.RegisterHash(crypto.SHA3_256, New256) - crypto.RegisterHash(crypto.SHA3_384, New384) - crypto.RegisterHash(crypto.SHA3_512, New512) -} - func new224Generic() *state { return &state{rate: 144, outputLen: 28, dsbyte: 0x06} } diff --git a/vendor/golang.org/x/crypto/sha3/register.go b/vendor/golang.org/x/crypto/sha3/register.go new file mode 100644 index 00000000..addfd504 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/register.go @@ -0,0 +1,18 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.4 + +package sha3 + +import ( + "crypto" +) + +func init() { + crypto.RegisterHash(crypto.SHA3_224, New224) + crypto.RegisterHash(crypto.SHA3_256, New256) + crypto.RegisterHash(crypto.SHA3_384, New384) + crypto.RegisterHash(crypto.SHA3_512, New512) +} diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE index 2a7cf70d..6a66aea5 100644 --- a/vendor/golang.org/x/exp/LICENSE +++ b/vendor/golang.org/x/exp/LICENSE @@ -1,4 +1,4 @@ -Copyright 2009 The Go Authors. +Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer. copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google LLC nor the names of its + * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/vendor/golang.org/x/sys/unix/mremap.go b/vendor/golang.org/x/sys/unix/mremap.go index 3a5e776f..fd45fe52 100644 --- a/vendor/golang.org/x/sys/unix/mremap.go +++ b/vendor/golang.org/x/sys/unix/mremap.go @@ -50,8 +50,3 @@ func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data [ func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { return mapper.Mremap(oldData, newLength, flags) } - -func MremapPtr(oldAddr unsafe.Pointer, oldSize uintptr, newAddr unsafe.Pointer, newSize uintptr, flags int) (ret unsafe.Pointer, err error) { - xaddr, err := mapper.mremap(uintptr(oldAddr), oldSize, newSize, flags, uintptr(newAddr)) - return unsafe.Pointer(xaddr), err -} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 4cc7b005..59542a89 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -542,18 +542,6 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) { } } -//sys pthread_chdir_np(path string) (err error) - -func PthreadChdir(path string) (err error) { - return pthread_chdir_np(path) -} - -//sys pthread_fchdir_np(fd int) (err error) - -func PthreadFchdir(fd int) (err error) { - return pthread_fchdir_np(fd) -} - //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go index 4e92e5aa..77081de8 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix.go @@ -154,15 +154,6 @@ func Munmap(b []byte) (err error) { return mapper.Munmap(b) } -func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) { - xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset) - return unsafe.Pointer(xaddr), err -} - -func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) { - return mapper.munmap(uintptr(addr), length) -} - func Read(fd int, p []byte) (n int, err error) { n, err = read(fd, p) if raceenabled { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index 07642c30..ccb02f24 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -760,39 +760,6 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pthread_chdir_np(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(libc_pthread_chdir_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_pthread_chdir_np_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_pthread_chdir_np pthread_chdir_np "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pthread_fchdir_np(fd int) (err error) { - _, _, e1 := syscall_syscall(libc_pthread_fchdir_np_trampoline_addr, uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_pthread_fchdir_np_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_pthread_fchdir_np pthread_fchdir_np "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index 923e08cb..8b8bb284 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -228,16 +228,6 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) -TEXT libc_pthread_chdir_np_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_pthread_chdir_np(SB) -GLOBL ·libc_pthread_chdir_np_trampoline_addr(SB), RODATA, $8 -DATA ·libc_pthread_chdir_np_trampoline_addr(SB)/8, $libc_pthread_chdir_np_trampoline<>(SB) - -TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_pthread_fchdir_np(SB) -GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 -DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) - TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 7d73dda6..1b40b997 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -760,39 +760,6 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pthread_chdir_np(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(libc_pthread_chdir_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_pthread_chdir_np_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_pthread_chdir_np pthread_chdir_np "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pthread_fchdir_np(fd int) (err error) { - _, _, e1 := syscall_syscall(libc_pthread_fchdir_np_trampoline_addr, uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_pthread_fchdir_np_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_pthread_fchdir_np pthread_fchdir_np "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index 05770011..08362c1a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -228,16 +228,6 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) -TEXT libc_pthread_chdir_np_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_pthread_chdir_np(SB) -GLOBL ·libc_pthread_chdir_np_trampoline_addr(SB), RODATA, $8 -DATA ·libc_pthread_chdir_np_trampoline_addr(SB)/8, $libc_pthread_chdir_np_trampoline<>(SB) - -TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_pthread_fchdir_np(SB) -GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 -DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) - TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go index 97651b5b..6f7d2ac7 100644 --- a/vendor/golang.org/x/sys/windows/security_windows.go +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -894,7 +894,7 @@ type ACL struct { aclRevision byte sbz1 byte aclSize uint16 - AceCount uint16 + aceCount uint16 sbz2 uint16 } @@ -1087,27 +1087,6 @@ type EXPLICIT_ACCESS struct { Trustee TRUSTEE } -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header -type ACE_HEADER struct { - AceType uint8 - AceFlags uint8 - AceSize uint16 -} - -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace -type ACCESS_ALLOWED_ACE struct { - Header ACE_HEADER - Mask ACCESS_MASK - SidStart uint32 -} - -const ( - // Constants for AceType - // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header - ACCESS_ALLOWED_ACE_TYPE = 0 - ACCESS_DENIED_ACE_TYPE = 1 -) - // This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions. type TrusteeValue uintptr @@ -1179,7 +1158,6 @@ type OBJECTS_AND_NAME struct { //sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD //sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW -//sys GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (ret error) = advapi32.GetAce // Control returns the security descriptor control bits. func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) { diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index eba76101..9f73df75 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -91,7 +91,6 @@ var ( procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW") procEqualSid = modadvapi32.NewProc("EqualSid") procFreeSid = modadvapi32.NewProc("FreeSid") - procGetAce = modadvapi32.NewProc("GetAce") procGetLengthSid = modadvapi32.NewProc("GetLengthSid") procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW") procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl") @@ -1225,14 +1224,6 @@ func setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCE return } -func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (ret error) { - r0, _, _ := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce))) - if r0 == 0 { - ret = GetLastError() - } - return -} - func SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) { r1, _, e1 := syscall.Syscall(procSetKernelObjectSecurity.Addr(), 3, uintptr(handle), uintptr(securityInformation), uintptr(unsafe.Pointer(securityDescriptor))) if r1 == 0 { diff --git a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go index 24bc98ac..a45f112b 100644 --- a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go +++ b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go @@ -84,7 +84,7 @@ type decoder struct { } // newError returns an error object with position info. -func (d decoder) newError(pos int, f string, x ...any) error { +func (d decoder) newError(pos int, f string, x ...interface{}) error { line, column := d.Position(pos) head := fmt.Sprintf("(line %d:%d): ", line, column) return errors.New(head+f, x...) @@ -96,7 +96,7 @@ func (d decoder) unexpectedTokenError(tok text.Token) error { } // syntaxError returns a syntax error for given position. -func (d decoder) syntaxError(pos int, f string, x ...any) error { +func (d decoder) syntaxError(pos int, f string, x ...interface{}) error { line, column := d.Position(pos) head := fmt.Sprintf("syntax error (line %d:%d): ", line, column) return errors.New(head+f, x...) diff --git a/vendor/google.golang.org/protobuf/encoding/prototext/encode.go b/vendor/google.golang.org/protobuf/encoding/prototext/encode.go index 1f57e661..95967e81 100644 --- a/vendor/google.golang.org/protobuf/encoding/prototext/encode.go +++ b/vendor/google.golang.org/protobuf/encoding/prototext/encode.go @@ -27,17 +27,15 @@ const defaultIndent = " " // Format formats the message as a multiline string. // This function is only intended for human consumption and ignores errors. -// Do not depend on the output being stable. Its output will change across -// different builds of your program, even when using the same version of the -// protobuf module. +// Do not depend on the output being stable. It may change over time across +// different versions of the program. func Format(m proto.Message) string { return MarshalOptions{Multiline: true}.Format(m) } // Marshal writes the given [proto.Message] in textproto format using default -// options. Do not depend on the output being stable. Its output will change -// across different builds of your program, even when using the same version of -// the protobuf module. +// options. Do not depend on the output being stable. It may change over time +// across different versions of the program. func Marshal(m proto.Message) ([]byte, error) { return MarshalOptions{}.Marshal(m) } @@ -86,9 +84,8 @@ type MarshalOptions struct { // Format formats the message as a string. // This method is only intended for human consumption and ignores errors. -// Do not depend on the output being stable. Its output will change across -// different builds of your program, even when using the same version of the -// protobuf module. +// Do not depend on the output being stable. It may change over time across +// different versions of the program. func (o MarshalOptions) Format(m proto.Message) string { if m == nil || !m.ProtoReflect().IsValid() { return "" // invalid syntax, but okay since this is for debugging @@ -101,9 +98,8 @@ func (o MarshalOptions) Format(m proto.Message) string { } // Marshal writes the given [proto.Message] in textproto format using options in -// MarshalOptions object. Do not depend on the output being stable. Its output -// will change across different builds of your program, even when using the -// same version of the protobuf module. +// MarshalOptions object. Do not depend on the output being stable. It may +// change over time across different versions of the program. func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) { return o.marshal(nil, m) } diff --git a/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go b/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go index 87e46bd4..a45625c8 100644 --- a/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go +++ b/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go @@ -252,7 +252,6 @@ func formatDescOpt(t protoreflect.Descriptor, isRoot, allowMulti bool, record fu {rv.MethodByName("Values"), "Values"}, {rv.MethodByName("ReservedNames"), "ReservedNames"}, {rv.MethodByName("ReservedRanges"), "ReservedRanges"}, - {rv.MethodByName("IsClosed"), "IsClosed"}, }...) case protoreflect.EnumValueDescriptor: diff --git a/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb b/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb index ff6a3836..18f07568 100644 Binary files a/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb and b/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb differ diff --git a/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go b/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go index 7e87c760..373d2083 100644 --- a/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go +++ b/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go @@ -32,7 +32,6 @@ var byteType = reflect.TypeOf(byte(0)) func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescriptors) protoreflect.FieldDescriptor { f := new(filedesc.Field) f.L0.ParentFile = filedesc.SurrogateProto2 - f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures for len(tag) > 0 { i := strings.IndexByte(tag, ',') if i < 0 { @@ -108,7 +107,8 @@ func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescri f.L1.StringName.InitJSON(jsonName) } case s == "packed": - f.L1.EditionFeatures.IsPacked = true + f.L1.HasPacked = true + f.L1.IsPacked = true case strings.HasPrefix(s, "weak="): f.L1.IsWeak = true f.L1.Message = filedesc.PlaceholderMessage(protoreflect.FullName(s[len("weak="):])) diff --git a/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go b/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go index 099b2bf4..87853e78 100644 --- a/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go +++ b/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go @@ -601,7 +601,7 @@ func (d *Decoder) consumeToken(kind Kind, size int, attrs uint8) Token { // newSyntaxError returns a syntax error with line and column information for // current position. -func (d *Decoder) newSyntaxError(f string, x ...any) error { +func (d *Decoder) newSyntaxError(f string, x ...interface{}) error { e := errors.New(f, x...) line, column := d.Position(len(d.orig) - len(d.in)) return errors.New("syntax error (line %d:%d): %v", line, column, e) diff --git a/vendor/google.golang.org/protobuf/internal/errors/errors.go b/vendor/google.golang.org/protobuf/internal/errors/errors.go index c2d6bd52..20c17b35 100644 --- a/vendor/google.golang.org/protobuf/internal/errors/errors.go +++ b/vendor/google.golang.org/protobuf/internal/errors/errors.go @@ -17,7 +17,7 @@ var Error = errors.New("protobuf error") // New formats a string according to the format specifier and arguments and // returns an error that has a "proto" prefix. -func New(f string, x ...any) error { +func New(f string, x ...interface{}) error { return &prefixError{s: format(f, x...)} } @@ -43,7 +43,7 @@ func (e *prefixError) Unwrap() error { // Wrap returns an error that has a "proto" prefix, the formatted string described // by the format specifier and arguments, and a suffix of err. The error wraps err. -func Wrap(err error, f string, x ...any) error { +func Wrap(err error, f string, x ...interface{}) error { return &wrapError{ s: format(f, x...), err: err, @@ -67,7 +67,7 @@ func (e *wrapError) Is(target error) bool { return target == Error } -func format(f string, x ...any) string { +func format(f string, x ...interface{}) string { // avoid "proto: " prefix when chaining for i := 0; i < len(x); i++ { switch e := x[i].(type) { @@ -87,18 +87,3 @@ func InvalidUTF8(name string) error { func RequiredNotSet(name string) error { return New("required field %v not set", name) } - -type SizeMismatchError struct { - Calculated, Measured int -} - -func (e *SizeMismatchError) Error() string { - return fmt.Sprintf("size mismatch (see https://github.com/golang/protobuf/issues/1609): calculated=%d, measured=%d", e.Calculated, e.Measured) -} - -func MismatchedSizeCalculation(calculated, measured int) error { - return &SizeMismatchError{ - Calculated: calculated, - Measured: measured, - } -} diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc.go index df53ff40..8826bcf4 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc.go @@ -7,7 +7,6 @@ package filedesc import ( "bytes" "fmt" - "strings" "sync" "sync/atomic" @@ -109,12 +108,9 @@ func (fd *File) ParentFile() protoreflect.FileDescriptor { return fd } func (fd *File) Parent() protoreflect.Descriptor { return nil } func (fd *File) Index() int { return 0 } func (fd *File) Syntax() protoreflect.Syntax { return fd.L1.Syntax } - -// Not exported and just used to reconstruct the original FileDescriptor proto -func (fd *File) Edition() int32 { return int32(fd.L1.Edition) } -func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() } -func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package } -func (fd *File) IsPlaceholder() bool { return false } +func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() } +func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package } +func (fd *File) IsPlaceholder() bool { return false } func (fd *File) Options() protoreflect.ProtoMessage { if f := fd.lazyInit().Options; f != nil { return f() @@ -206,9 +202,6 @@ func (ed *Enum) lazyInit() *EnumL2 { ed.L0.ParentFile.lazyInit() // implicitly initializes L2 return ed.L2 } -func (ed *Enum) IsClosed() bool { - return !ed.L1.EditionFeatures.IsOpenEnum -} func (ed *EnumValue) Options() protoreflect.ProtoMessage { if f := ed.L1.Options; f != nil { @@ -258,6 +251,10 @@ type ( StringName stringName IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto IsWeak bool // promoted from google.protobuf.FieldOptions + HasPacked bool // promoted from google.protobuf.FieldOptions + IsPacked bool // promoted from google.protobuf.FieldOptions + HasEnforceUTF8 bool // promoted from google.protobuf.FieldOptions + EnforceUTF8 bool // promoted from google.protobuf.FieldOptions Default defaultValue ContainingOneof protoreflect.OneofDescriptor // must be consistent with Message.Oneofs.Fields Enum protoreflect.EnumDescriptor @@ -334,7 +331,8 @@ func (fd *Field) HasPresence() bool { if fd.L1.Cardinality == protoreflect.Repeated { return false } - return fd.IsExtension() || fd.L1.EditionFeatures.IsFieldPresence || fd.L1.Message != nil || fd.L1.ContainingOneof != nil + explicitFieldPresence := fd.Syntax() == protoreflect.Editions && fd.L1.EditionFeatures.IsFieldPresence + return fd.Syntax() == protoreflect.Proto2 || explicitFieldPresence || fd.L1.Message != nil || fd.L1.ContainingOneof != nil } func (fd *Field) HasOptionalKeyword() bool { return (fd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && fd.L1.Cardinality == protoreflect.Optional && fd.L1.ContainingOneof == nil) || fd.L1.IsProto3Optional @@ -347,7 +345,14 @@ func (fd *Field) IsPacked() bool { case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind: return false } - return fd.L1.EditionFeatures.IsPacked + if fd.L0.ParentFile.L1.Syntax == protoreflect.Editions { + return fd.L1.EditionFeatures.IsPacked + } + if fd.L0.ParentFile.L1.Syntax == protoreflect.Proto3 { + // proto3 repeated fields are packed by default. + return !fd.L1.HasPacked || fd.L1.IsPacked + } + return fd.L1.IsPacked } func (fd *Field) IsExtension() bool { return false } func (fd *Field) IsWeak() bool { return fd.L1.IsWeak } @@ -383,10 +388,6 @@ func (fd *Field) Message() protoreflect.MessageDescriptor { } return fd.L1.Message } -func (fd *Field) IsMapEntry() bool { - parent, ok := fd.L0.Parent.(protoreflect.MessageDescriptor) - return ok && parent.IsMapEntry() -} func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) } func (fd *Field) ProtoType(protoreflect.FieldDescriptor) {} @@ -398,7 +399,13 @@ func (fd *Field) ProtoType(protoreflect.FieldDescriptor) {} // WARNING: This method is exempt from the compatibility promise and may be // removed in the future without warning. func (fd *Field) EnforceUTF8() bool { - return fd.L1.EditionFeatures.IsUTF8Validated + if fd.L0.ParentFile.L1.Syntax == protoreflect.Editions { + return fd.L1.EditionFeatures.IsUTF8Validated + } + if fd.L1.HasEnforceUTF8 { + return fd.L1.EnforceUTF8 + } + return fd.L0.ParentFile.L1.Syntax == protoreflect.Proto3 } func (od *Oneof) IsSynthetic() bool { @@ -431,6 +438,7 @@ type ( Options func() protoreflect.ProtoMessage StringName stringName IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto + IsPacked bool // promoted from google.protobuf.FieldOptions Default defaultValue Enum protoreflect.EnumDescriptor Message protoreflect.MessageDescriptor @@ -453,16 +461,7 @@ func (xd *Extension) HasPresence() bool { return xd.L1.Cardi func (xd *Extension) HasOptionalKeyword() bool { return (xd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && xd.L1.Cardinality == protoreflect.Optional) || xd.lazyInit().IsProto3Optional } -func (xd *Extension) IsPacked() bool { - if xd.L1.Cardinality != protoreflect.Repeated { - return false - } - switch xd.L1.Kind { - case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind: - return false - } - return xd.L1.EditionFeatures.IsPacked -} +func (xd *Extension) IsPacked() bool { return xd.lazyInit().IsPacked } func (xd *Extension) IsExtension() bool { return true } func (xd *Extension) IsWeak() bool { return false } func (xd *Extension) IsList() bool { return xd.Cardinality() == protoreflect.Repeated } @@ -543,9 +542,8 @@ func (md *Method) ProtoInternal(pragma.DoNotImplement) {} // Surrogate files are can be used to create standalone descriptors // where the syntax is only information derived from the parent file. var ( - SurrogateProto2 = &File{L1: FileL1{Syntax: protoreflect.Proto2}, L2: &FileL2{}} - SurrogateProto3 = &File{L1: FileL1{Syntax: protoreflect.Proto3}, L2: &FileL2{}} - SurrogateEdition2023 = &File{L1: FileL1{Syntax: protoreflect.Editions, Edition: Edition2023}, L2: &FileL2{}} + SurrogateProto2 = &File{L1: FileL1{Syntax: protoreflect.Proto2}, L2: &FileL2{}} + SurrogateProto3 = &File{L1: FileL1{Syntax: protoreflect.Proto3}, L2: &FileL2{}} ) type ( @@ -587,34 +585,6 @@ func (s *stringName) InitJSON(name string) { s.nameJSON = name } -// Returns true if this field is structured like the synthetic field of a proto2 -// group. This allows us to expand our treatment of delimited fields without -// breaking proto2 files that have been upgraded to editions. -func isGroupLike(fd protoreflect.FieldDescriptor) bool { - // Groups are always group types. - if fd.Kind() != protoreflect.GroupKind { - return false - } - - // Group fields are always the lowercase type name. - if strings.ToLower(string(fd.Message().Name())) != string(fd.Name()) { - return false - } - - // Groups could only be defined in the same file they're used. - if fd.Message().ParentFile() != fd.ParentFile() { - return false - } - - // Group messages are always defined in the same scope as the field. File - // level extensions will compare NULL == NULL here, which is why the file - // comparison above is necessary to ensure both come from the same file. - if fd.IsExtension() { - return fd.Parent() == fd.Message().Parent() - } - return fd.ContainingMessage() == fd.Message().Parent() -} - func (s *stringName) lazyInit(fd protoreflect.FieldDescriptor) *stringName { s.once.Do(func() { if fd.IsExtension() { @@ -635,7 +605,7 @@ func (s *stringName) lazyInit(fd protoreflect.FieldDescriptor) *stringName { // Format the text name. s.nameText = string(fd.Name()) - if isGroupLike(fd) { + if fd.Kind() == protoreflect.GroupKind { s.nameText = string(fd.Message().Name()) } } diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go index 8a57d60b..237e64fd 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go @@ -113,10 +113,8 @@ func (fd *File) unmarshalSeed(b []byte) { switch string(v) { case "proto2": fd.L1.Syntax = protoreflect.Proto2 - fd.L1.Edition = EditionProto2 case "proto3": fd.L1.Syntax = protoreflect.Proto3 - fd.L1.Edition = EditionProto3 case "editions": fd.L1.Syntax = protoreflect.Editions default: @@ -179,10 +177,11 @@ func (fd *File) unmarshalSeed(b []byte) { // If syntax is missing, it is assumed to be proto2. if fd.L1.Syntax == 0 { fd.L1.Syntax = protoreflect.Proto2 - fd.L1.Edition = EditionProto2 } - fd.L1.EditionFeatures = getFeaturesFor(fd.L1.Edition) + if fd.L1.Syntax == protoreflect.Editions { + fd.L1.EditionFeatures = getFeaturesFor(fd.L1.Edition) + } // Parse editions features from options if any if options != nil { @@ -268,7 +267,6 @@ func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protorefl ed.L0.ParentFile = pf ed.L0.Parent = pd ed.L0.Index = i - ed.L1.EditionFeatures = featuresFromParentDesc(ed.Parent()) var numValues int for b := b; len(b) > 0; { @@ -445,7 +443,6 @@ func (xd *Extension) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd prot xd.L0.ParentFile = pf xd.L0.Parent = pd xd.L0.Index = i - xd.L1.EditionFeatures = featuresFromParentDesc(pd) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) @@ -470,38 +467,6 @@ func (xd *Extension) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd prot xd.L0.FullName = appendFullName(sb, pd.FullName(), v) case genid.FieldDescriptorProto_Extendee_field_number: xd.L1.Extendee = PlaceholderMessage(makeFullName(sb, v)) - case genid.FieldDescriptorProto_Options_field_number: - xd.unmarshalOptions(v) - } - default: - m := protowire.ConsumeFieldValue(num, typ, b) - b = b[m:] - } - } - - if xd.L1.Kind == protoreflect.MessageKind && xd.L1.EditionFeatures.IsDelimitedEncoded { - xd.L1.Kind = protoreflect.GroupKind - } -} - -func (xd *Extension) unmarshalOptions(b []byte) { - for len(b) > 0 { - num, typ, n := protowire.ConsumeTag(b) - b = b[n:] - switch typ { - case protowire.VarintType: - v, m := protowire.ConsumeVarint(b) - b = b[m:] - switch num { - case genid.FieldOptions_Packed_field_number: - xd.L1.EditionFeatures.IsPacked = protowire.DecodeBool(v) - } - case protowire.BytesType: - v, m := protowire.ConsumeBytes(b) - b = b[m:] - switch num { - case genid.FieldOptions_Features_field_number: - xd.L1.EditionFeatures = unmarshalFeatureSet(v, xd.L1.EditionFeatures) } default: m := protowire.ConsumeFieldValue(num, typ, b) @@ -534,7 +499,7 @@ func (sd *Service) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protor } var nameBuilderPool = sync.Pool{ - New: func() any { return new(strs.Builder) }, + New: func() interface{} { return new(strs.Builder) }, } func getBuilder() *strs.Builder { diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go index e56c91a8..482a61cc 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go @@ -45,11 +45,6 @@ func (file *File) resolveMessages() { case protoreflect.MessageKind, protoreflect.GroupKind: fd.L1.Message = file.resolveMessageDependency(fd.L1.Message, listFieldDeps, depIdx) depIdx++ - if fd.L1.Kind == protoreflect.GroupKind && (fd.IsMap() || fd.IsMapEntry()) { - // A map field might inherit delimited encoding from a file-wide default feature. - // But maps never actually use delimited encoding. (At least for now...) - fd.L1.Kind = protoreflect.MessageKind - } } // Default is resolved here since it depends on Enum being resolved. @@ -471,10 +466,10 @@ func (fd *Field) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd protoref b = b[m:] } } - if fd.L1.Kind == protoreflect.MessageKind && fd.L1.EditionFeatures.IsDelimitedEncoded { + if fd.Syntax() == protoreflect.Editions && fd.L1.Kind == protoreflect.MessageKind && fd.L1.EditionFeatures.IsDelimitedEncoded { fd.L1.Kind = protoreflect.GroupKind } - if fd.L1.EditionFeatures.IsLegacyRequired { + if fd.Syntax() == protoreflect.Editions && fd.L1.EditionFeatures.IsLegacyRequired { fd.L1.Cardinality = protoreflect.Required } if rawTypeName != nil { @@ -501,11 +496,13 @@ func (fd *Field) unmarshalOptions(b []byte) { b = b[m:] switch num { case genid.FieldOptions_Packed_field_number: - fd.L1.EditionFeatures.IsPacked = protowire.DecodeBool(v) + fd.L1.HasPacked = true + fd.L1.IsPacked = protowire.DecodeBool(v) case genid.FieldOptions_Weak_field_number: fd.L1.IsWeak = protowire.DecodeBool(v) case FieldOptions_EnforceUTF8: - fd.L1.EditionFeatures.IsUTF8Validated = protowire.DecodeBool(v) + fd.L1.HasEnforceUTF8 = true + fd.L1.EnforceUTF8 = protowire.DecodeBool(v) } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) @@ -551,6 +548,7 @@ func (od *Oneof) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd protoref func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) { var rawTypeName []byte var rawOptions []byte + xd.L1.EditionFeatures = featuresFromParentDesc(xd.L1.Extendee) xd.L2 = new(ExtensionL2) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) @@ -574,6 +572,7 @@ func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) { case genid.FieldDescriptorProto_TypeName_field_number: rawTypeName = v case genid.FieldDescriptorProto_Options_field_number: + xd.unmarshalOptions(v) rawOptions = appendOptions(rawOptions, v) } default: @@ -581,6 +580,12 @@ func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) { b = b[m:] } } + if xd.Syntax() == protoreflect.Editions && xd.L1.Kind == protoreflect.MessageKind && xd.L1.EditionFeatures.IsDelimitedEncoded { + xd.L1.Kind = protoreflect.GroupKind + } + if xd.Syntax() == protoreflect.Editions && xd.L1.EditionFeatures.IsLegacyRequired { + xd.L1.Cardinality = protoreflect.Required + } if rawTypeName != nil { name := makeFullName(sb, rawTypeName) switch xd.L1.Kind { @@ -593,6 +598,32 @@ func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) { xd.L2.Options = xd.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Field, rawOptions) } +func (xd *Extension) unmarshalOptions(b []byte) { + for len(b) > 0 { + num, typ, n := protowire.ConsumeTag(b) + b = b[n:] + switch typ { + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + b = b[m:] + switch num { + case genid.FieldOptions_Packed_field_number: + xd.L2.IsPacked = protowire.DecodeBool(v) + } + case protowire.BytesType: + v, m := protowire.ConsumeBytes(b) + b = b[m:] + switch num { + case genid.FieldOptions_Features_field_number: + xd.L1.EditionFeatures = unmarshalFeatureSet(v, xd.L1.EditionFeatures) + } + default: + m := protowire.ConsumeFieldValue(num, typ, b) + b = b[m:] + } + } +} + func (sd *Service) unmarshalFull(b []byte, sb *strs.Builder) { var rawMethods [][]byte var rawOptions []byte diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc_list_gen.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc_list_gen.go index f4107c05..30db19fd 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc_list_gen.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc_list_gen.go @@ -8,7 +8,6 @@ package filedesc import ( "fmt" - "strings" "sync" "google.golang.org/protobuf/internal/descfmt" @@ -199,16 +198,6 @@ func (p *Fields) lazyInit() *Fields { if _, ok := p.byText[d.TextName()]; !ok { p.byText[d.TextName()] = d } - if isGroupLike(d) { - lowerJSONName := strings.ToLower(d.JSONName()) - if _, ok := p.byJSON[lowerJSONName]; !ok { - p.byJSON[lowerJSONName] = d - } - lowerTextName := strings.ToLower(d.TextName()) - if _, ok := p.byText[lowerTextName]; !ok { - p.byText[lowerTextName] = d - } - } if _, ok := p.byNum[d.Number()]; !ok { p.byNum[d.Number()] = d } diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/editions.go b/vendor/google.golang.org/protobuf/internal/filedesc/editions.go index 11f5f356..0375a49d 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/editions.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/editions.go @@ -14,13 +14,9 @@ import ( ) var defaultsCache = make(map[Edition]EditionFeatures) -var defaultsKeys = []Edition{} func init() { unmarshalEditionDefaults(editiondefaults.Defaults) - SurrogateProto2.L1.EditionFeatures = getFeaturesFor(EditionProto2) - SurrogateProto3.L1.EditionFeatures = getFeaturesFor(EditionProto3) - SurrogateEdition2023.L1.EditionFeatures = getFeaturesFor(Edition2023) } func unmarshalGoFeature(b []byte, parent EditionFeatures) EditionFeatures { @@ -108,15 +104,12 @@ func unmarshalEditionDefault(b []byte) { v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { - case genid.FeatureSetDefaults_FeatureSetEditionDefault_FixedFeatures_field_number: - fs = unmarshalFeatureSet(v, fs) - case genid.FeatureSetDefaults_FeatureSetEditionDefault_OverridableFeatures_field_number: + case genid.FeatureSetDefaults_FeatureSetEditionDefault_Features_field_number: fs = unmarshalFeatureSet(v, fs) } } } defaultsCache[ed] = fs - defaultsKeys = append(defaultsKeys, ed) } func unmarshalEditionDefaults(b []byte) { @@ -142,15 +135,8 @@ func unmarshalEditionDefaults(b []byte) { } func getFeaturesFor(ed Edition) EditionFeatures { - match := EditionUnknown - for _, key := range defaultsKeys { - if key > ed { - break - } - match = key - } - if match == EditionUnknown { - panic(fmt.Sprintf("unsupported edition: %v", ed)) + if def, ok := defaultsCache[ed]; ok { + return def } - return defaultsCache[match] + panic(fmt.Sprintf("unsupported edition: %v", ed)) } diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/placeholder.go b/vendor/google.golang.org/protobuf/internal/filedesc/placeholder.go index bfb3b841..28240ebc 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/placeholder.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/placeholder.go @@ -63,7 +63,6 @@ func (e PlaceholderEnum) Options() protoreflect.ProtoMessage { return des func (e PlaceholderEnum) Values() protoreflect.EnumValueDescriptors { return emptyEnumValues } func (e PlaceholderEnum) ReservedNames() protoreflect.Names { return emptyNames } func (e PlaceholderEnum) ReservedRanges() protoreflect.EnumRanges { return emptyEnumRanges } -func (e PlaceholderEnum) IsClosed() bool { return false } func (e PlaceholderEnum) ProtoType(protoreflect.EnumDescriptor) { return } func (e PlaceholderEnum) ProtoInternal(pragma.DoNotImplement) { return } diff --git a/vendor/google.golang.org/protobuf/internal/filetype/build.go b/vendor/google.golang.org/protobuf/internal/filetype/build.go index ba83fea4..f0e38c4e 100644 --- a/vendor/google.golang.org/protobuf/internal/filetype/build.go +++ b/vendor/google.golang.org/protobuf/internal/filetype/build.go @@ -68,7 +68,7 @@ type Builder struct { // and for input and output messages referenced by service methods. // Dependencies must come after declarations, but the ordering of // dependencies themselves is unspecified. - GoTypes []any + GoTypes []interface{} // DependencyIndexes is an ordered list of indexes into GoTypes for the // dependencies of messages, extensions, or services. @@ -268,7 +268,7 @@ func (x depIdxs) Get(i, j int32) int32 { type ( resolverByIndex struct { - goTypes []any + goTypes []interface{} depIdxs depIdxs fileRegistry } diff --git a/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go b/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go index f30ab6b5..40272c89 100644 --- a/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go +++ b/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go @@ -21,7 +21,6 @@ const ( // Enum values for google.protobuf.Edition. const ( Edition_EDITION_UNKNOWN_enum_value = 0 - Edition_EDITION_LEGACY_enum_value = 900 Edition_EDITION_PROTO2_enum_value = 998 Edition_EDITION_PROTO3_enum_value = 999 Edition_EDITION_2023_enum_value = 1000 @@ -654,7 +653,6 @@ const ( FieldOptions_Targets_field_name protoreflect.Name = "targets" FieldOptions_EditionDefaults_field_name protoreflect.Name = "edition_defaults" FieldOptions_Features_field_name protoreflect.Name = "features" - FieldOptions_FeatureSupport_field_name protoreflect.Name = "feature_support" FieldOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option" FieldOptions_Ctype_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.ctype" @@ -669,7 +667,6 @@ const ( FieldOptions_Targets_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.targets" FieldOptions_EditionDefaults_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.edition_defaults" FieldOptions_Features_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.features" - FieldOptions_FeatureSupport_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.feature_support" FieldOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.uninterpreted_option" ) @@ -687,7 +684,6 @@ const ( FieldOptions_Targets_field_number protoreflect.FieldNumber = 19 FieldOptions_EditionDefaults_field_number protoreflect.FieldNumber = 20 FieldOptions_Features_field_number protoreflect.FieldNumber = 21 - FieldOptions_FeatureSupport_field_number protoreflect.FieldNumber = 22 FieldOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999 ) @@ -771,33 +767,6 @@ const ( FieldOptions_EditionDefault_Value_field_number protoreflect.FieldNumber = 2 ) -// Names for google.protobuf.FieldOptions.FeatureSupport. -const ( - FieldOptions_FeatureSupport_message_name protoreflect.Name = "FeatureSupport" - FieldOptions_FeatureSupport_message_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport" -) - -// Field names for google.protobuf.FieldOptions.FeatureSupport. -const ( - FieldOptions_FeatureSupport_EditionIntroduced_field_name protoreflect.Name = "edition_introduced" - FieldOptions_FeatureSupport_EditionDeprecated_field_name protoreflect.Name = "edition_deprecated" - FieldOptions_FeatureSupport_DeprecationWarning_field_name protoreflect.Name = "deprecation_warning" - FieldOptions_FeatureSupport_EditionRemoved_field_name protoreflect.Name = "edition_removed" - - FieldOptions_FeatureSupport_EditionIntroduced_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.edition_introduced" - FieldOptions_FeatureSupport_EditionDeprecated_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.edition_deprecated" - FieldOptions_FeatureSupport_DeprecationWarning_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.deprecation_warning" - FieldOptions_FeatureSupport_EditionRemoved_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.edition_removed" -) - -// Field numbers for google.protobuf.FieldOptions.FeatureSupport. -const ( - FieldOptions_FeatureSupport_EditionIntroduced_field_number protoreflect.FieldNumber = 1 - FieldOptions_FeatureSupport_EditionDeprecated_field_number protoreflect.FieldNumber = 2 - FieldOptions_FeatureSupport_DeprecationWarning_field_number protoreflect.FieldNumber = 3 - FieldOptions_FeatureSupport_EditionRemoved_field_number protoreflect.FieldNumber = 4 -) - // Names for google.protobuf.OneofOptions. const ( OneofOptions_message_name protoreflect.Name = "OneofOptions" @@ -860,13 +829,11 @@ const ( EnumValueOptions_Deprecated_field_name protoreflect.Name = "deprecated" EnumValueOptions_Features_field_name protoreflect.Name = "features" EnumValueOptions_DebugRedact_field_name protoreflect.Name = "debug_redact" - EnumValueOptions_FeatureSupport_field_name protoreflect.Name = "feature_support" EnumValueOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option" EnumValueOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.deprecated" EnumValueOptions_Features_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.features" EnumValueOptions_DebugRedact_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.debug_redact" - EnumValueOptions_FeatureSupport_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.feature_support" EnumValueOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.uninterpreted_option" ) @@ -875,7 +842,6 @@ const ( EnumValueOptions_Deprecated_field_number protoreflect.FieldNumber = 1 EnumValueOptions_Features_field_number protoreflect.FieldNumber = 2 EnumValueOptions_DebugRedact_field_number protoreflect.FieldNumber = 3 - EnumValueOptions_FeatureSupport_field_number protoreflect.FieldNumber = 4 EnumValueOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999 ) @@ -1144,20 +1110,17 @@ const ( // Field names for google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault. const ( - FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_name protoreflect.Name = "edition" - FeatureSetDefaults_FeatureSetEditionDefault_OverridableFeatures_field_name protoreflect.Name = "overridable_features" - FeatureSetDefaults_FeatureSetEditionDefault_FixedFeatures_field_name protoreflect.Name = "fixed_features" + FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_name protoreflect.Name = "edition" + FeatureSetDefaults_FeatureSetEditionDefault_Features_field_name protoreflect.Name = "features" - FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_fullname protoreflect.FullName = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault.edition" - FeatureSetDefaults_FeatureSetEditionDefault_OverridableFeatures_field_fullname protoreflect.FullName = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault.overridable_features" - FeatureSetDefaults_FeatureSetEditionDefault_FixedFeatures_field_fullname protoreflect.FullName = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault.fixed_features" + FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_fullname protoreflect.FullName = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault.edition" + FeatureSetDefaults_FeatureSetEditionDefault_Features_field_fullname protoreflect.FullName = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault.features" ) // Field numbers for google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault. const ( - FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_number protoreflect.FieldNumber = 3 - FeatureSetDefaults_FeatureSetEditionDefault_OverridableFeatures_field_number protoreflect.FieldNumber = 4 - FeatureSetDefaults_FeatureSetEditionDefault_FixedFeatures_field_number protoreflect.FieldNumber = 5 + FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_number protoreflect.FieldNumber = 3 + FeatureSetDefaults_FeatureSetEditionDefault_Features_field_number protoreflect.FieldNumber = 2 ) // Names for google.protobuf.SourceCodeInfo. diff --git a/vendor/google.golang.org/protobuf/internal/genid/go_features_gen.go b/vendor/google.golang.org/protobuf/internal/genid/go_features_gen.go index 9a652a2b..fd9015e8 100644 --- a/vendor/google.golang.org/protobuf/internal/genid/go_features_gen.go +++ b/vendor/google.golang.org/protobuf/internal/genid/go_features_gen.go @@ -10,7 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" ) -const File_google_protobuf_go_features_proto = "google/protobuf/go_features.proto" +const File_reflect_protodesc_proto_go_features_proto = "reflect/protodesc/proto/go_features.proto" // Names for google.protobuf.GoFeatures. const ( diff --git a/vendor/google.golang.org/protobuf/internal/impl/api_export.go b/vendor/google.golang.org/protobuf/internal/impl/api_export.go index 5d5771c2..a371f98d 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/api_export.go +++ b/vendor/google.golang.org/protobuf/internal/impl/api_export.go @@ -22,13 +22,13 @@ type Export struct{} // NewError formats a string according to the format specifier and arguments and // returns an error that has a "proto" prefix. -func (Export) NewError(f string, x ...any) error { +func (Export) NewError(f string, x ...interface{}) error { return errors.New(f, x...) } // enum is any enum type generated by protoc-gen-go // and must be a named int32 type. -type enum = any +type enum = interface{} // EnumOf returns the protoreflect.Enum interface over e. // It returns nil if e is nil. @@ -81,7 +81,7 @@ func (Export) EnumStringOf(ed protoreflect.EnumDescriptor, n protoreflect.EnumNu // message is any message type generated by protoc-gen-go // and must be a pointer to a named struct type. -type message = any +type message = interface{} // legacyMessageWrapper wraps a v2 message as a v1 message. type legacyMessageWrapper struct{ m protoreflect.ProtoMessage } diff --git a/vendor/google.golang.org/protobuf/internal/impl/checkinit.go b/vendor/google.golang.org/protobuf/internal/impl/checkinit.go index f29e6a8f..bff041ed 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/checkinit.go +++ b/vendor/google.golang.org/protobuf/internal/impl/checkinit.go @@ -68,7 +68,7 @@ func (mi *MessageInfo) isInitExtensions(ext *map[int32]ExtensionField) error { } for _, x := range *ext { ei := getExtensionFieldInfo(x.Type()) - if ei.funcs.isInit == nil || x.isUnexpandedLazy() { + if ei.funcs.isInit == nil { continue } v := x.Value() diff --git a/vendor/google.golang.org/protobuf/internal/impl/codec_extension.go b/vendor/google.golang.org/protobuf/internal/impl/codec_extension.go index 4bb0a7a2..2b8f122c 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/codec_extension.go +++ b/vendor/google.golang.org/protobuf/internal/impl/codec_extension.go @@ -99,28 +99,6 @@ func (f *ExtensionField) canLazy(xt protoreflect.ExtensionType) bool { return false } -// isUnexpandedLazy returns true if the ExensionField is lazy and not -// yet expanded, which means it's present and already checked for -// initialized required fields. -func (f *ExtensionField) isUnexpandedLazy() bool { - return f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0 -} - -// lazyBuffer retrieves the buffer for a lazy extension if it's not yet expanded. -// -// The returned buffer has to be kept over whatever operation we're planning, -// as re-retrieving it will fail after the message is lazily decoded. -func (f *ExtensionField) lazyBuffer() []byte { - // This function might be in the critical path, so check the atomic without - // taking a look first, then only take the lock if needed. - if !f.isUnexpandedLazy() { - return nil - } - f.lazy.mu.Lock() - defer f.lazy.mu.Unlock() - return f.lazy.b -} - func (f *ExtensionField) lazyInit() { f.lazy.mu.Lock() defer f.lazy.mu.Unlock() diff --git a/vendor/google.golang.org/protobuf/internal/impl/codec_field.go b/vendor/google.golang.org/protobuf/internal/impl/codec_field.go index 78ee47e4..3fadd241 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/codec_field.go +++ b/vendor/google.golang.org/protobuf/internal/impl/codec_field.go @@ -233,15 +233,9 @@ func sizeMessageInfo(p pointer, f *coderFieldInfo, opts marshalOptions) int { } func appendMessageInfo(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) { - calculatedSize := f.mi.sizePointer(p.Elem(), opts) b = protowire.AppendVarint(b, f.wiretag) - b = protowire.AppendVarint(b, uint64(calculatedSize)) - before := len(b) - b, err := f.mi.marshalAppendPointer(b, p.Elem(), opts) - if measuredSize := len(b) - before; calculatedSize != measuredSize && err == nil { - return nil, errors.MismatchedSizeCalculation(calculatedSize, measuredSize) - } - return b, err + b = protowire.AppendVarint(b, uint64(f.mi.sizePointer(p.Elem(), opts))) + return f.mi.marshalAppendPointer(b, p.Elem(), opts) } func consumeMessageInfo(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { @@ -268,21 +262,14 @@ func isInitMessageInfo(p pointer, f *coderFieldInfo) error { return f.mi.checkInitializedPointer(p.Elem()) } -func sizeMessage(m proto.Message, tagsize int, opts marshalOptions) int { - return protowire.SizeBytes(opts.Options().Size(m)) + tagsize +func sizeMessage(m proto.Message, tagsize int, _ marshalOptions) int { + return protowire.SizeBytes(proto.Size(m)) + tagsize } func appendMessage(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) { - mopts := opts.Options() - calculatedSize := mopts.Size(m) b = protowire.AppendVarint(b, wiretag) - b = protowire.AppendVarint(b, uint64(calculatedSize)) - before := len(b) - b, err := mopts.MarshalAppend(b, m) - if measuredSize := len(b) - before; calculatedSize != measuredSize && err == nil { - return nil, errors.MismatchedSizeCalculation(calculatedSize, measuredSize) - } - return b, err + b = protowire.AppendVarint(b, uint64(proto.Size(m))) + return opts.Options().MarshalAppend(b, m) } func consumeMessage(b []byte, m proto.Message, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, err error) { @@ -418,8 +405,8 @@ func consumeGroupType(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInf return f.mi.unmarshalPointer(b, p.Elem(), f.num, opts) } -func sizeGroup(m proto.Message, tagsize int, opts marshalOptions) int { - return 2*tagsize + opts.Options().Size(m) +func sizeGroup(m proto.Message, tagsize int, _ marshalOptions) int { + return 2*tagsize + proto.Size(m) } func appendGroup(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) { @@ -495,14 +482,10 @@ func appendMessageSliceInfo(b []byte, p pointer, f *coderFieldInfo, opts marshal b = protowire.AppendVarint(b, f.wiretag) siz := f.mi.sizePointer(v, opts) b = protowire.AppendVarint(b, uint64(siz)) - before := len(b) b, err = f.mi.marshalAppendPointer(b, v, opts) if err != nil { return b, err } - if measuredSize := len(b) - before; siz != measuredSize { - return nil, errors.MismatchedSizeCalculation(siz, measuredSize) - } } return b, nil } @@ -537,34 +520,28 @@ func isInitMessageSliceInfo(p pointer, f *coderFieldInfo) error { return nil } -func sizeMessageSlice(p pointer, goType reflect.Type, tagsize int, opts marshalOptions) int { - mopts := opts.Options() +func sizeMessageSlice(p pointer, goType reflect.Type, tagsize int, _ marshalOptions) int { s := p.PointerSlice() n := 0 for _, v := range s { m := asMessage(v.AsValueOf(goType.Elem())) - n += protowire.SizeBytes(mopts.Size(m)) + tagsize + n += protowire.SizeBytes(proto.Size(m)) + tagsize } return n } func appendMessageSlice(b []byte, p pointer, wiretag uint64, goType reflect.Type, opts marshalOptions) ([]byte, error) { - mopts := opts.Options() s := p.PointerSlice() var err error for _, v := range s { m := asMessage(v.AsValueOf(goType.Elem())) b = protowire.AppendVarint(b, wiretag) - siz := mopts.Size(m) + siz := proto.Size(m) b = protowire.AppendVarint(b, uint64(siz)) - before := len(b) - b, err = mopts.MarshalAppend(b, m) + b, err = opts.Options().MarshalAppend(b, m) if err != nil { return b, err } - if measuredSize := len(b) - before; siz != measuredSize { - return nil, errors.MismatchedSizeCalculation(siz, measuredSize) - } } return b, nil } @@ -605,12 +582,11 @@ func isInitMessageSlice(p pointer, goType reflect.Type) error { // Slices of messages func sizeMessageSliceValue(listv protoreflect.Value, tagsize int, opts marshalOptions) int { - mopts := opts.Options() list := listv.List() n := 0 for i, llen := 0, list.Len(); i < llen; i++ { m := list.Get(i).Message().Interface() - n += protowire.SizeBytes(mopts.Size(m)) + tagsize + n += protowire.SizeBytes(proto.Size(m)) + tagsize } return n } @@ -621,17 +597,13 @@ func appendMessageSliceValue(b []byte, listv protoreflect.Value, wiretag uint64, for i, llen := 0, list.Len(); i < llen; i++ { m := list.Get(i).Message().Interface() b = protowire.AppendVarint(b, wiretag) - siz := mopts.Size(m) + siz := proto.Size(m) b = protowire.AppendVarint(b, uint64(siz)) - before := len(b) var err error b, err = mopts.MarshalAppend(b, m) if err != nil { return b, err } - if measuredSize := len(b) - before; siz != measuredSize { - return nil, errors.MismatchedSizeCalculation(siz, measuredSize) - } } return b, nil } @@ -679,12 +651,11 @@ var coderMessageSliceValue = valueCoderFuncs{ } func sizeGroupSliceValue(listv protoreflect.Value, tagsize int, opts marshalOptions) int { - mopts := opts.Options() list := listv.List() n := 0 for i, llen := 0, list.Len(); i < llen; i++ { m := list.Get(i).Message().Interface() - n += 2*tagsize + mopts.Size(m) + n += 2*tagsize + proto.Size(m) } return n } @@ -767,13 +738,12 @@ func makeGroupSliceFieldCoder(fd protoreflect.FieldDescriptor, ft reflect.Type) } } -func sizeGroupSlice(p pointer, messageType reflect.Type, tagsize int, opts marshalOptions) int { - mopts := opts.Options() +func sizeGroupSlice(p pointer, messageType reflect.Type, tagsize int, _ marshalOptions) int { s := p.PointerSlice() n := 0 for _, v := range s { m := asMessage(v.AsValueOf(messageType.Elem())) - n += 2*tagsize + mopts.Size(m) + n += 2*tagsize + proto.Size(m) } return n } diff --git a/vendor/google.golang.org/protobuf/internal/impl/codec_map.go b/vendor/google.golang.org/protobuf/internal/impl/codec_map.go index fb35f0ba..111b9d16 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/codec_map.go +++ b/vendor/google.golang.org/protobuf/internal/impl/codec_map.go @@ -9,7 +9,6 @@ import ( "sort" "google.golang.org/protobuf/encoding/protowire" - "google.golang.org/protobuf/internal/errors" "google.golang.org/protobuf/internal/genid" "google.golang.org/protobuf/reflect/protoreflect" ) @@ -241,16 +240,11 @@ func appendMapItem(b []byte, keyrv, valrv reflect.Value, mapi *mapInfo, f *coder size += mapi.keyFuncs.size(key.Value(), mapKeyTagSize, opts) size += mapi.valFuncs.size(val, mapValTagSize, opts) b = protowire.AppendVarint(b, uint64(size)) - before := len(b) b, err := mapi.keyFuncs.marshal(b, key.Value(), mapi.keyWiretag, opts) if err != nil { return nil, err } - b, err = mapi.valFuncs.marshal(b, val, mapi.valWiretag, opts) - if measuredSize := len(b) - before; size != measuredSize && err == nil { - return nil, errors.MismatchedSizeCalculation(size, measuredSize) - } - return b, err + return mapi.valFuncs.marshal(b, val, mapi.valWiretag, opts) } else { key := mapi.conv.keyConv.PBValueOf(keyrv).MapKey() val := pointerOfValue(valrv) @@ -265,12 +259,7 @@ func appendMapItem(b []byte, keyrv, valrv reflect.Value, mapi *mapInfo, f *coder } b = protowire.AppendVarint(b, mapi.valWiretag) b = protowire.AppendVarint(b, uint64(valSize)) - before := len(b) - b, err = f.mi.marshalAppendPointer(b, val, opts) - if measuredSize := len(b) - before; valSize != measuredSize && err == nil { - return nil, errors.MismatchedSizeCalculation(valSize, measuredSize) - } - return b, err + return f.mi.marshalAppendPointer(b, val, opts) } } diff --git a/vendor/google.golang.org/protobuf/internal/impl/codec_messageset.go b/vendor/google.golang.org/protobuf/internal/impl/codec_messageset.go index 7a16ec13..b7a23faf 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/codec_messageset.go +++ b/vendor/google.golang.org/protobuf/internal/impl/codec_messageset.go @@ -26,15 +26,6 @@ func sizeMessageSet(mi *MessageInfo, p pointer, opts marshalOptions) (size int) } num, _ := protowire.DecodeTag(xi.wiretag) size += messageset.SizeField(num) - if fullyLazyExtensions(opts) { - // Don't expand the extension, instead use the buffer to calculate size - if lb := x.lazyBuffer(); lb != nil { - // We got hold of the buffer, so it's still lazy. - // Don't count the tag size in the extension buffer, it's already added. - size += protowire.SizeTag(messageset.FieldMessage) + len(lb) - xi.tagsize - continue - } - } size += xi.funcs.size(x.Value(), protowire.SizeTag(messageset.FieldMessage), opts) } @@ -94,19 +85,6 @@ func marshalMessageSetField(mi *MessageInfo, b []byte, x ExtensionField, opts ma xi := getExtensionFieldInfo(x.Type()) num, _ := protowire.DecodeTag(xi.wiretag) b = messageset.AppendFieldStart(b, num) - - if fullyLazyExtensions(opts) { - // Don't expand the extension if it's still in wire format, instead use the buffer content. - if lb := x.lazyBuffer(); lb != nil { - // The tag inside the lazy buffer is a different tag (the extension - // number), but what we need here is the tag for FieldMessage: - b = protowire.AppendVarint(b, protowire.EncodeTag(messageset.FieldMessage, protowire.BytesType)) - b = append(b, lb[xi.tagsize:]...) - b = messageset.AppendFieldEnd(b) - return b, nil - } - } - b, err := xi.funcs.marshal(b, x.Value(), protowire.EncodeTag(messageset.FieldMessage, protowire.BytesType), opts) if err != nil { return b, err diff --git a/vendor/google.golang.org/protobuf/internal/impl/convert.go b/vendor/google.golang.org/protobuf/internal/impl/convert.go index e06ece55..185ef2ef 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/convert.go +++ b/vendor/google.golang.org/protobuf/internal/impl/convert.go @@ -14,7 +14,7 @@ import ( // unwrapper unwraps the value to the underlying value. // This is implemented by List and Map. type unwrapper interface { - protoUnwrap() any + protoUnwrap() interface{} } // A Converter coverts to/from Go reflect.Value types and protobuf protoreflect.Value types. diff --git a/vendor/google.golang.org/protobuf/internal/impl/convert_list.go b/vendor/google.golang.org/protobuf/internal/impl/convert_list.go index 18cb96fd..f8913651 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/convert_list.go +++ b/vendor/google.golang.org/protobuf/internal/impl/convert_list.go @@ -136,6 +136,6 @@ func (ls *listReflect) NewElement() protoreflect.Value { func (ls *listReflect) IsValid() bool { return !ls.v.IsNil() } -func (ls *listReflect) protoUnwrap() any { +func (ls *listReflect) protoUnwrap() interface{} { return ls.v.Interface() } diff --git a/vendor/google.golang.org/protobuf/internal/impl/convert_map.go b/vendor/google.golang.org/protobuf/internal/impl/convert_map.go index 304244a6..f30b0a05 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/convert_map.go +++ b/vendor/google.golang.org/protobuf/internal/impl/convert_map.go @@ -116,6 +116,6 @@ func (ms *mapReflect) NewValue() protoreflect.Value { func (ms *mapReflect) IsValid() bool { return !ms.v.IsNil() } -func (ms *mapReflect) protoUnwrap() any { +func (ms *mapReflect) protoUnwrap() interface{} { return ms.v.Interface() } diff --git a/vendor/google.golang.org/protobuf/internal/impl/encode.go b/vendor/google.golang.org/protobuf/internal/impl/encode.go index febd2122..845c67d6 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/encode.go +++ b/vendor/google.golang.org/protobuf/internal/impl/encode.go @@ -49,11 +49,8 @@ func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) { return 0 } if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() { - // The size cache contains the size + 1, to allow the - // zero value to be invalid, while also allowing for a - // 0 size to be cached. - if size := atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()); size > 0 { - return int(size - 1) + if size := atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()); size >= 0 { + return int(size) } } return mi.sizePointerSlow(p, opts) @@ -63,7 +60,7 @@ func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int if flags.ProtoLegacy && mi.isMessageSet { size = sizeMessageSet(mi, p, opts) if mi.sizecacheOffset.IsValid() { - atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size+1)) + atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size)) } return size } @@ -87,16 +84,13 @@ func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int } } if mi.sizecacheOffset.IsValid() { - if size > (math.MaxInt32 - 1) { + if size > math.MaxInt32 { // The size is too large for the int32 sizecache field. // We will need to recompute the size when encoding; // unfortunately expensive, but better than invalid output. - atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), 0) + atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), -1) } else { - // The size cache contains the size + 1, to allow the - // zero value to be invalid, while also allowing for a - // 0 size to be cached. - atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size+1)) + atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size)) } } return size @@ -155,14 +149,6 @@ func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOpt return b, nil } -// fullyLazyExtensions returns true if we should attempt to keep extensions lazy over size and marshal. -func fullyLazyExtensions(opts marshalOptions) bool { - // When deterministic marshaling is requested, force an unmarshal for lazy - // extensions to produce a deterministic result, instead of passing through - // bytes lazily that may or may not match what Go Protobuf would produce. - return opts.flags&piface.MarshalDeterministic == 0 -} - func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) { if ext == nil { return 0 @@ -172,14 +158,6 @@ func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marsha if xi.funcs.size == nil { continue } - if fullyLazyExtensions(opts) { - // Don't expand the extension, instead use the buffer to calculate size - if lb := x.lazyBuffer(); lb != nil { - // We got hold of the buffer, so it's still lazy. - n += len(lb) - continue - } - } n += xi.funcs.size(x.Value(), xi.tagsize, opts) } return n @@ -198,13 +176,6 @@ func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, var err error for _, x := range *ext { xi := getExtensionFieldInfo(x.Type()) - if fullyLazyExtensions(opts) { - // Don't expand the extension if it's still in wire format, instead use the buffer content. - if lb := x.lazyBuffer(); lb != nil { - b = append(b, lb...) - continue - } - } b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts) } return b, err @@ -220,13 +191,6 @@ func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, for _, k := range keys { x := (*ext)[int32(k)] xi := getExtensionFieldInfo(x.Type()) - if fullyLazyExtensions(opts) { - // Don't expand the extension if it's still in wire format, instead use the buffer content. - if lb := x.lazyBuffer(); lb != nil { - b = append(b, lb...) - continue - } - } b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts) if err != nil { return b, err diff --git a/vendor/google.golang.org/protobuf/internal/impl/extension.go b/vendor/google.golang.org/protobuf/internal/impl/extension.go index e31249f6..cb25b0ba 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/extension.go +++ b/vendor/google.golang.org/protobuf/internal/impl/extension.go @@ -53,7 +53,7 @@ type ExtensionInfo struct { // type returned by InterfaceOf may not be identical. // // Deprecated: Use InterfaceOf(xt.Zero()) instead. - ExtensionType any + ExtensionType interface{} // Field is the field number of the extension. // @@ -95,16 +95,16 @@ func (xi *ExtensionInfo) New() protoreflect.Value { func (xi *ExtensionInfo) Zero() protoreflect.Value { return xi.lazyInit().Zero() } -func (xi *ExtensionInfo) ValueOf(v any) protoreflect.Value { +func (xi *ExtensionInfo) ValueOf(v interface{}) protoreflect.Value { return xi.lazyInit().PBValueOf(reflect.ValueOf(v)) } -func (xi *ExtensionInfo) InterfaceOf(v protoreflect.Value) any { +func (xi *ExtensionInfo) InterfaceOf(v protoreflect.Value) interface{} { return xi.lazyInit().GoValueOf(v).Interface() } func (xi *ExtensionInfo) IsValidValue(v protoreflect.Value) bool { return xi.lazyInit().IsValidPB(v) } -func (xi *ExtensionInfo) IsValidInterface(v any) bool { +func (xi *ExtensionInfo) IsValidInterface(v interface{}) bool { return xi.lazyInit().IsValidGo(reflect.ValueOf(v)) } func (xi *ExtensionInfo) TypeDescriptor() protoreflect.ExtensionTypeDescriptor { diff --git a/vendor/google.golang.org/protobuf/internal/impl/legacy_enum.go b/vendor/google.golang.org/protobuf/internal/impl/legacy_enum.go index 81b2b1a7..c2a803bb 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/legacy_enum.go +++ b/vendor/google.golang.org/protobuf/internal/impl/legacy_enum.go @@ -97,7 +97,7 @@ func (e *legacyEnumWrapper) Number() protoreflect.EnumNumber { func (e *legacyEnumWrapper) ProtoReflect() protoreflect.Enum { return e } -func (e *legacyEnumWrapper) protoUnwrap() any { +func (e *legacyEnumWrapper) protoUnwrap() interface{} { v := reflect.New(e.goTyp).Elem() v.SetInt(int64(e.num)) return v.Interface() @@ -167,7 +167,6 @@ func aberrantLoadEnumDesc(t reflect.Type) protoreflect.EnumDescriptor { ed := &filedesc.Enum{L2: new(filedesc.EnumL2)} ed.L0.FullName = AberrantDeriveFullName(t) // e.g., github_com.user.repo.MyEnum ed.L0.ParentFile = filedesc.SurrogateProto3 - ed.L1.EditionFeatures = ed.L0.ParentFile.L1.EditionFeatures ed.L2.Values.List = append(ed.L2.Values.List, filedesc.EnumValue{}) // TODO: Use the presence of a UnmarshalJSON method to determine proto2? diff --git a/vendor/google.golang.org/protobuf/internal/impl/legacy_extension.go b/vendor/google.golang.org/protobuf/internal/impl/legacy_extension.go index 6e8677ee..87b30d05 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/legacy_extension.go +++ b/vendor/google.golang.org/protobuf/internal/impl/legacy_extension.go @@ -118,7 +118,7 @@ func (xi *ExtensionInfo) initFromLegacy() { xd.L1.Number = protoreflect.FieldNumber(xi.Field) xd.L1.Cardinality = fd.L1.Cardinality xd.L1.Kind = fd.L1.Kind - xd.L1.EditionFeatures = fd.L1.EditionFeatures + xd.L2.IsPacked = fd.L1.IsPacked xd.L2.Default = fd.L1.Default xd.L1.Extendee = Export{}.MessageDescriptorOf(xi.ExtendedType) xd.L2.Enum = ed diff --git a/vendor/google.golang.org/protobuf/internal/impl/legacy_file.go b/vendor/google.golang.org/protobuf/internal/impl/legacy_file.go index b649f112..9ab09108 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/legacy_file.go +++ b/vendor/google.golang.org/protobuf/internal/impl/legacy_file.go @@ -7,7 +7,7 @@ package impl import ( "bytes" "compress/gzip" - "io" + "io/ioutil" "sync" "google.golang.org/protobuf/internal/filedesc" @@ -51,7 +51,7 @@ func legacyLoadFileDesc(b []byte) protoreflect.FileDescriptor { if err != nil { panic(err) } - b2, err := io.ReadAll(zr) + b2, err := ioutil.ReadAll(zr) if err != nil { panic(err) } diff --git a/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go b/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go index bf0b6049..2ab2c629 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go +++ b/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go @@ -204,7 +204,6 @@ func aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName } } - md.L1.EditionFeatures = md.L0.ParentFile.L1.EditionFeatures // Obtain a list of oneof wrapper types. var oneofWrappers []reflect.Type methods := make([]reflect.Method, 0, 2) @@ -216,7 +215,7 @@ func aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName } for _, fn := range methods { for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { - if vs, ok := v.Interface().([]any); ok { + if vs, ok := v.Interface().([]interface{}); ok { for _, v := range vs { oneofWrappers = append(oneofWrappers, reflect.TypeOf(v)) } @@ -251,7 +250,6 @@ func aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName od := &md.L2.Oneofs.List[n] od.L0.FullName = md.FullName().Append(protoreflect.Name(tag)) od.L0.ParentFile = md.L0.ParentFile - od.L1.EditionFeatures = md.L1.EditionFeatures od.L0.Parent = md od.L0.Index = n @@ -262,7 +260,6 @@ func aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName aberrantAppendField(md, f.Type, tag, "", "") fd := &md.L2.Fields.List[len(md.L2.Fields.List)-1] fd.L1.ContainingOneof = od - fd.L1.EditionFeatures = od.L1.EditionFeatures od.L1.Fields.List = append(od.L1.Fields.List, fd) } } @@ -310,14 +307,14 @@ func aberrantAppendField(md *filedesc.Message, goType reflect.Type, tag, tagKey, fd.L0.Parent = md fd.L0.Index = n - if fd.L1.IsWeak || fd.L1.EditionFeatures.IsPacked { + if fd.L1.IsWeak || fd.L1.HasPacked { fd.L1.Options = func() protoreflect.ProtoMessage { opts := descopts.Field.ProtoReflect().New() if fd.L1.IsWeak { opts.Set(opts.Descriptor().Fields().ByName("weak"), protoreflect.ValueOfBool(true)) } - if fd.L1.EditionFeatures.IsPacked { - opts.Set(opts.Descriptor().Fields().ByName("packed"), protoreflect.ValueOfBool(fd.L1.EditionFeatures.IsPacked)) + if fd.L1.HasPacked { + opts.Set(opts.Descriptor().Fields().ByName("packed"), protoreflect.ValueOfBool(fd.L1.IsPacked)) } return opts.Interface() } @@ -347,7 +344,6 @@ func aberrantAppendField(md *filedesc.Message, goType reflect.Type, tag, tagKey, md2.L0.ParentFile = md.L0.ParentFile md2.L0.Parent = md md2.L0.Index = n - md2.L1.EditionFeatures = md.L1.EditionFeatures md2.L1.IsMapEntry = true md2.L2.Options = func() protoreflect.ProtoMessage { @@ -567,6 +563,6 @@ func (m aberrantMessage) IsValid() bool { func (m aberrantMessage) ProtoMethods() *protoiface.Methods { return aberrantProtoMethods } -func (m aberrantMessage) protoUnwrap() any { +func (m aberrantMessage) protoUnwrap() interface{} { return m.v.Interface() } diff --git a/vendor/google.golang.org/protobuf/internal/impl/message.go b/vendor/google.golang.org/protobuf/internal/impl/message.go index 019399d4..629bacdc 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/message.go +++ b/vendor/google.golang.org/protobuf/internal/impl/message.go @@ -35,7 +35,7 @@ type MessageInfo struct { Exporter exporter // OneofWrappers is list of pointers to oneof wrapper struct types. - OneofWrappers []any + OneofWrappers []interface{} initMu sync.Mutex // protects all unexported fields initDone uint32 @@ -47,7 +47,7 @@ type MessageInfo struct { // exporter is a function that returns a reference to the ith field of v, // where v is a pointer to a struct. It returns nil if it does not support // exporting the requested field (e.g., already exported). -type exporter func(v any, i int) any +type exporter func(v interface{}, i int) interface{} // getMessageInfo returns the MessageInfo for any message type that // is generated by our implementation of protoc-gen-go (for v2 and on). @@ -201,7 +201,7 @@ fieldLoop: } for _, fn := range methods { for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { - if vs, ok := v.Interface().([]any); ok { + if vs, ok := v.Interface().([]interface{}); ok { oneofWrappers = vs } } @@ -256,7 +256,7 @@ func (mi *MessageInfo) Message(i int) protoreflect.MessageType { type mapEntryType struct { desc protoreflect.MessageDescriptor - valType any // zero value of enum or message type + valType interface{} // zero value of enum or message type } func (mt mapEntryType) New() protoreflect.Message { diff --git a/vendor/google.golang.org/protobuf/internal/impl/message_reflect.go b/vendor/google.golang.org/protobuf/internal/impl/message_reflect.go index ecb4623d..d9ea010b 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/message_reflect.go +++ b/vendor/google.golang.org/protobuf/internal/impl/message_reflect.go @@ -20,7 +20,7 @@ type reflectMessageInfo struct { // fieldTypes contains the zero value of an enum or message field. // For lists, it contains the element type. // For maps, it contains the entry value type. - fieldTypes map[protoreflect.FieldNumber]any + fieldTypes map[protoreflect.FieldNumber]interface{} // denseFields is a subset of fields where: // 0 < fieldDesc.Number() < len(denseFields) @@ -28,7 +28,7 @@ type reflectMessageInfo struct { denseFields []*fieldInfo // rangeInfos is a list of all fields (not belonging to a oneof) and oneofs. - rangeInfos []any // either *fieldInfo or *oneofInfo + rangeInfos []interface{} // either *fieldInfo or *oneofInfo getUnknown func(pointer) protoreflect.RawFields setUnknown func(pointer, protoreflect.RawFields) @@ -224,7 +224,7 @@ func (mi *MessageInfo) makeFieldTypes(si structInfo) { } if ft != nil { if mi.fieldTypes == nil { - mi.fieldTypes = make(map[protoreflect.FieldNumber]any) + mi.fieldTypes = make(map[protoreflect.FieldNumber]interface{}) } mi.fieldTypes[fd.Number()] = reflect.Zero(ft).Interface() } @@ -247,39 +247,39 @@ func (m *extensionMap) Range(f func(protoreflect.FieldDescriptor, protoreflect.V } } } -func (m *extensionMap) Has(xd protoreflect.ExtensionTypeDescriptor) (ok bool) { +func (m *extensionMap) Has(xt protoreflect.ExtensionType) (ok bool) { if m == nil { return false } + xd := xt.TypeDescriptor() x, ok := (*m)[int32(xd.Number())] if !ok { return false } - if x.isUnexpandedLazy() { - // Avoid calling x.Value(), which triggers a lazy unmarshal. - return true - } switch { case xd.IsList(): return x.Value().List().Len() > 0 case xd.IsMap(): return x.Value().Map().Len() > 0 + case xd.Message() != nil: + return x.Value().Message().IsValid() } return true } -func (m *extensionMap) Clear(xd protoreflect.ExtensionTypeDescriptor) { - delete(*m, int32(xd.Number())) +func (m *extensionMap) Clear(xt protoreflect.ExtensionType) { + delete(*m, int32(xt.TypeDescriptor().Number())) } -func (m *extensionMap) Get(xd protoreflect.ExtensionTypeDescriptor) protoreflect.Value { +func (m *extensionMap) Get(xt protoreflect.ExtensionType) protoreflect.Value { + xd := xt.TypeDescriptor() if m != nil { if x, ok := (*m)[int32(xd.Number())]; ok { return x.Value() } } - return xd.Type().Zero() + return xt.Zero() } -func (m *extensionMap) Set(xd protoreflect.ExtensionTypeDescriptor, v protoreflect.Value) { - xt := xd.Type() +func (m *extensionMap) Set(xt protoreflect.ExtensionType, v protoreflect.Value) { + xd := xt.TypeDescriptor() isValid := true switch { case !xt.IsValidValue(v): @@ -292,7 +292,7 @@ func (m *extensionMap) Set(xd protoreflect.ExtensionTypeDescriptor, v protorefle isValid = v.Message().IsValid() } if !isValid { - panic(fmt.Sprintf("%v: assigning invalid value", xd.FullName())) + panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName())) } if *m == nil { @@ -302,15 +302,16 @@ func (m *extensionMap) Set(xd protoreflect.ExtensionTypeDescriptor, v protorefle x.Set(xt, v) (*m)[int32(xd.Number())] = x } -func (m *extensionMap) Mutable(xd protoreflect.ExtensionTypeDescriptor) protoreflect.Value { +func (m *extensionMap) Mutable(xt protoreflect.ExtensionType) protoreflect.Value { + xd := xt.TypeDescriptor() if xd.Kind() != protoreflect.MessageKind && xd.Kind() != protoreflect.GroupKind && !xd.IsList() && !xd.IsMap() { panic("invalid Mutable on field with non-composite type") } if x, ok := (*m)[int32(xd.Number())]; ok { return x.Value() } - v := xd.Type().New() - m.Set(xd, v) + v := xt.New() + m.Set(xt, v) return v } @@ -393,7 +394,7 @@ var ( // MessageOf returns a reflective view over a message. The input must be a // pointer to a named Go struct. If the provided type has a ProtoReflect method, // it must be implemented by calling this method. -func (mi *MessageInfo) MessageOf(m any) protoreflect.Message { +func (mi *MessageInfo) MessageOf(m interface{}) protoreflect.Message { if reflect.TypeOf(m) != mi.GoReflectType { panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType)) } @@ -421,13 +422,13 @@ func (m *messageIfaceWrapper) Reset() { func (m *messageIfaceWrapper) ProtoReflect() protoreflect.Message { return (*messageReflectWrapper)(m) } -func (m *messageIfaceWrapper) protoUnwrap() any { +func (m *messageIfaceWrapper) protoUnwrap() interface{} { return m.p.AsIfaceOf(m.mi.GoReflectType.Elem()) } // checkField verifies that the provided field descriptor is valid. // Exactly one of the returned values is populated. -func (mi *MessageInfo) checkField(fd protoreflect.FieldDescriptor) (*fieldInfo, protoreflect.ExtensionTypeDescriptor) { +func (mi *MessageInfo) checkField(fd protoreflect.FieldDescriptor) (*fieldInfo, protoreflect.ExtensionType) { var fi *fieldInfo if n := fd.Number(); 0 < n && int(n) < len(mi.denseFields) { fi = mi.denseFields[n] @@ -456,7 +457,7 @@ func (mi *MessageInfo) checkField(fd protoreflect.FieldDescriptor) (*fieldInfo, if !ok { panic(fmt.Sprintf("extension %v does not implement protoreflect.ExtensionTypeDescriptor", fd.FullName())) } - return nil, xtd + return nil, xtd.Type() } panic(fmt.Sprintf("field %v is invalid", fd.FullName())) } diff --git a/vendor/google.golang.org/protobuf/internal/impl/message_reflect_gen.go b/vendor/google.golang.org/protobuf/internal/impl/message_reflect_gen.go index 99dc23c6..741d6e5b 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/message_reflect_gen.go +++ b/vendor/google.golang.org/protobuf/internal/impl/message_reflect_gen.go @@ -23,13 +23,12 @@ func (m *messageState) New() protoreflect.Message { func (m *messageState) Interface() protoreflect.ProtoMessage { return m.protoUnwrap().(protoreflect.ProtoMessage) } -func (m *messageState) protoUnwrap() any { +func (m *messageState) protoUnwrap() interface{} { return m.pointer().AsIfaceOf(m.messageInfo().GoReflectType.Elem()) } func (m *messageState) ProtoMethods() *protoiface.Methods { - mi := m.messageInfo() - mi.init() - return &mi.methods + m.messageInfo().init() + return &m.messageInfo().methods } // ProtoMessageInfo is a pseudo-internal API for allowing the v1 code @@ -42,9 +41,8 @@ func (m *messageState) ProtoMessageInfo() *MessageInfo { } func (m *messageState) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { - mi := m.messageInfo() - mi.init() - for _, ri := range mi.rangeInfos { + m.messageInfo().init() + for _, ri := range m.messageInfo().rangeInfos { switch ri := ri.(type) { case *fieldInfo: if ri.has(m.pointer()) { @@ -54,86 +52,77 @@ func (m *messageState) Range(f func(protoreflect.FieldDescriptor, protoreflect.V } case *oneofInfo: if n := ri.which(m.pointer()); n > 0 { - fi := mi.fields[n] + fi := m.messageInfo().fields[n] if !f(fi.fieldDesc, fi.get(m.pointer())) { return } } } } - mi.extensionMap(m.pointer()).Range(f) + m.messageInfo().extensionMap(m.pointer()).Range(f) } func (m *messageState) Has(fd protoreflect.FieldDescriptor) bool { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.has(m.pointer()) } else { - return mi.extensionMap(m.pointer()).Has(xd) + return m.messageInfo().extensionMap(m.pointer()).Has(xt) } } func (m *messageState) Clear(fd protoreflect.FieldDescriptor) { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { fi.clear(m.pointer()) } else { - mi.extensionMap(m.pointer()).Clear(xd) + m.messageInfo().extensionMap(m.pointer()).Clear(xt) } } func (m *messageState) Get(fd protoreflect.FieldDescriptor) protoreflect.Value { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.get(m.pointer()) } else { - return mi.extensionMap(m.pointer()).Get(xd) + return m.messageInfo().extensionMap(m.pointer()).Get(xt) } } func (m *messageState) Set(fd protoreflect.FieldDescriptor, v protoreflect.Value) { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { fi.set(m.pointer(), v) } else { - mi.extensionMap(m.pointer()).Set(xd, v) + m.messageInfo().extensionMap(m.pointer()).Set(xt, v) } } func (m *messageState) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.mutable(m.pointer()) } else { - return mi.extensionMap(m.pointer()).Mutable(xd) + return m.messageInfo().extensionMap(m.pointer()).Mutable(xt) } } func (m *messageState) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.newField() } else { - return xd.Type().New() + return xt.New() } } func (m *messageState) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { - mi := m.messageInfo() - mi.init() - if oi := mi.oneofs[od.Name()]; oi != nil && oi.oneofDesc == od { + m.messageInfo().init() + if oi := m.messageInfo().oneofs[od.Name()]; oi != nil && oi.oneofDesc == od { return od.Fields().ByNumber(oi.which(m.pointer())) } panic("invalid oneof descriptor " + string(od.FullName()) + " for message " + string(m.Descriptor().FullName())) } func (m *messageState) GetUnknown() protoreflect.RawFields { - mi := m.messageInfo() - mi.init() - return mi.getUnknown(m.pointer()) + m.messageInfo().init() + return m.messageInfo().getUnknown(m.pointer()) } func (m *messageState) SetUnknown(b protoreflect.RawFields) { - mi := m.messageInfo() - mi.init() - mi.setUnknown(m.pointer(), b) + m.messageInfo().init() + m.messageInfo().setUnknown(m.pointer(), b) } func (m *messageState) IsValid() bool { return !m.pointer().IsNil() @@ -154,13 +143,12 @@ func (m *messageReflectWrapper) Interface() protoreflect.ProtoMessage { } return (*messageIfaceWrapper)(m) } -func (m *messageReflectWrapper) protoUnwrap() any { +func (m *messageReflectWrapper) protoUnwrap() interface{} { return m.pointer().AsIfaceOf(m.messageInfo().GoReflectType.Elem()) } func (m *messageReflectWrapper) ProtoMethods() *protoiface.Methods { - mi := m.messageInfo() - mi.init() - return &mi.methods + m.messageInfo().init() + return &m.messageInfo().methods } // ProtoMessageInfo is a pseudo-internal API for allowing the v1 code @@ -173,9 +161,8 @@ func (m *messageReflectWrapper) ProtoMessageInfo() *MessageInfo { } func (m *messageReflectWrapper) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { - mi := m.messageInfo() - mi.init() - for _, ri := range mi.rangeInfos { + m.messageInfo().init() + for _, ri := range m.messageInfo().rangeInfos { switch ri := ri.(type) { case *fieldInfo: if ri.has(m.pointer()) { @@ -185,86 +172,77 @@ func (m *messageReflectWrapper) Range(f func(protoreflect.FieldDescriptor, proto } case *oneofInfo: if n := ri.which(m.pointer()); n > 0 { - fi := mi.fields[n] + fi := m.messageInfo().fields[n] if !f(fi.fieldDesc, fi.get(m.pointer())) { return } } } } - mi.extensionMap(m.pointer()).Range(f) + m.messageInfo().extensionMap(m.pointer()).Range(f) } func (m *messageReflectWrapper) Has(fd protoreflect.FieldDescriptor) bool { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.has(m.pointer()) } else { - return mi.extensionMap(m.pointer()).Has(xd) + return m.messageInfo().extensionMap(m.pointer()).Has(xt) } } func (m *messageReflectWrapper) Clear(fd protoreflect.FieldDescriptor) { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { fi.clear(m.pointer()) } else { - mi.extensionMap(m.pointer()).Clear(xd) + m.messageInfo().extensionMap(m.pointer()).Clear(xt) } } func (m *messageReflectWrapper) Get(fd protoreflect.FieldDescriptor) protoreflect.Value { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.get(m.pointer()) } else { - return mi.extensionMap(m.pointer()).Get(xd) + return m.messageInfo().extensionMap(m.pointer()).Get(xt) } } func (m *messageReflectWrapper) Set(fd protoreflect.FieldDescriptor, v protoreflect.Value) { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { fi.set(m.pointer(), v) } else { - mi.extensionMap(m.pointer()).Set(xd, v) + m.messageInfo().extensionMap(m.pointer()).Set(xt, v) } } func (m *messageReflectWrapper) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.mutable(m.pointer()) } else { - return mi.extensionMap(m.pointer()).Mutable(xd) + return m.messageInfo().extensionMap(m.pointer()).Mutable(xt) } } func (m *messageReflectWrapper) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { - mi := m.messageInfo() - mi.init() - if fi, xd := mi.checkField(fd); fi != nil { + m.messageInfo().init() + if fi, xt := m.messageInfo().checkField(fd); fi != nil { return fi.newField() } else { - return xd.Type().New() + return xt.New() } } func (m *messageReflectWrapper) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { - mi := m.messageInfo() - mi.init() - if oi := mi.oneofs[od.Name()]; oi != nil && oi.oneofDesc == od { + m.messageInfo().init() + if oi := m.messageInfo().oneofs[od.Name()]; oi != nil && oi.oneofDesc == od { return od.Fields().ByNumber(oi.which(m.pointer())) } panic("invalid oneof descriptor " + string(od.FullName()) + " for message " + string(m.Descriptor().FullName())) } func (m *messageReflectWrapper) GetUnknown() protoreflect.RawFields { - mi := m.messageInfo() - mi.init() - return mi.getUnknown(m.pointer()) + m.messageInfo().init() + return m.messageInfo().getUnknown(m.pointer()) } func (m *messageReflectWrapper) SetUnknown(b protoreflect.RawFields) { - mi := m.messageInfo() - mi.init() - mi.setUnknown(m.pointer(), b) + m.messageInfo().init() + m.messageInfo().setUnknown(m.pointer(), b) } func (m *messageReflectWrapper) IsValid() bool { return !m.pointer().IsNil() diff --git a/vendor/google.golang.org/protobuf/internal/impl/pointer_reflect.go b/vendor/google.golang.org/protobuf/internal/impl/pointer_reflect.go index da685e8a..517e9443 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/pointer_reflect.go +++ b/vendor/google.golang.org/protobuf/internal/impl/pointer_reflect.go @@ -16,7 +16,7 @@ import ( const UnsafeEnabled = false // Pointer is an opaque pointer type. -type Pointer any +type Pointer interface{} // offset represents the offset to a struct field, accessible from a pointer. // The offset is the field index into a struct. @@ -62,7 +62,7 @@ func pointerOfValue(v reflect.Value) pointer { } // pointerOfIface returns the pointer portion of an interface. -func pointerOfIface(v any) pointer { +func pointerOfIface(v interface{}) pointer { return pointer{v: reflect.ValueOf(v)} } @@ -93,7 +93,7 @@ func (p pointer) AsValueOf(t reflect.Type) reflect.Value { // AsIfaceOf treats p as a pointer to an object of type t and returns the value. // It is equivalent to p.AsValueOf(t).Interface() -func (p pointer) AsIfaceOf(t reflect.Type) any { +func (p pointer) AsIfaceOf(t reflect.Type) interface{} { return p.AsValueOf(t).Interface() } diff --git a/vendor/google.golang.org/protobuf/internal/impl/pointer_unsafe.go b/vendor/google.golang.org/protobuf/internal/impl/pointer_unsafe.go index 5f20ca5d..4b020e31 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/pointer_unsafe.go +++ b/vendor/google.golang.org/protobuf/internal/impl/pointer_unsafe.go @@ -50,7 +50,7 @@ func pointerOfValue(v reflect.Value) pointer { } // pointerOfIface returns the pointer portion of an interface. -func pointerOfIface(v any) pointer { +func pointerOfIface(v interface{}) pointer { type ifaceHeader struct { Type unsafe.Pointer Data unsafe.Pointer @@ -80,7 +80,7 @@ func (p pointer) AsValueOf(t reflect.Type) reflect.Value { // AsIfaceOf treats p as a pointer to an object of type t and returns the value. // It is equivalent to p.AsValueOf(t).Interface() -func (p pointer) AsIfaceOf(t reflect.Type) any { +func (p pointer) AsIfaceOf(t reflect.Type) interface{} { // TODO: Use tricky unsafe magic to directly create ifaceHeader. return p.AsValueOf(t).Interface() } diff --git a/vendor/google.golang.org/protobuf/internal/order/range.go b/vendor/google.golang.org/protobuf/internal/order/range.go index a1f09162..1665a68e 100644 --- a/vendor/google.golang.org/protobuf/internal/order/range.go +++ b/vendor/google.golang.org/protobuf/internal/order/range.go @@ -18,7 +18,7 @@ type messageField struct { } var messageFieldPool = sync.Pool{ - New: func() any { return new([]messageField) }, + New: func() interface{} { return new([]messageField) }, } type ( @@ -69,7 +69,7 @@ type mapEntry struct { } var mapEntryPool = sync.Pool{ - New: func() any { return new([]mapEntry) }, + New: func() interface{} { return new([]mapEntry) }, } type ( diff --git a/vendor/google.golang.org/protobuf/internal/version/version.go b/vendor/google.golang.org/protobuf/internal/version/version.go index dbbf1f68..a50fcfb4 100644 --- a/vendor/google.golang.org/protobuf/internal/version/version.go +++ b/vendor/google.golang.org/protobuf/internal/version/version.go @@ -51,8 +51,8 @@ import ( // 10. Send out the CL for review and submit it. const ( Major = 1 - Minor = 34 - Patch = 2 + Minor = 33 + Patch = 0 PreRelease = "" ) diff --git a/vendor/google.golang.org/protobuf/proto/decode.go b/vendor/google.golang.org/protobuf/proto/decode.go index d75a6534..e5b03b56 100644 --- a/vendor/google.golang.org/protobuf/proto/decode.go +++ b/vendor/google.golang.org/protobuf/proto/decode.go @@ -51,8 +51,6 @@ type UnmarshalOptions struct { // Unmarshal parses the wire-format message in b and places the result in m. // The provided message must be mutable (e.g., a non-nil pointer to a message). -// -// See the [UnmarshalOptions] type if you need more control. func Unmarshal(b []byte, m Message) error { _, err := UnmarshalOptions{RecursionLimit: protowire.DefaultRecursionLimit}.unmarshal(b, m.ProtoReflect()) return err diff --git a/vendor/google.golang.org/protobuf/proto/encode.go b/vendor/google.golang.org/protobuf/proto/encode.go index 1f847bcc..4fed202f 100644 --- a/vendor/google.golang.org/protobuf/proto/encode.go +++ b/vendor/google.golang.org/protobuf/proto/encode.go @@ -5,17 +5,12 @@ package proto import ( - "errors" - "fmt" - "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/internal/encoding/messageset" "google.golang.org/protobuf/internal/order" "google.golang.org/protobuf/internal/pragma" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/runtime/protoiface" - - protoerrors "google.golang.org/protobuf/internal/errors" ) // MarshalOptions configures the marshaler. @@ -75,32 +70,7 @@ type MarshalOptions struct { UseCachedSize bool } -// flags turns the specified MarshalOptions (user-facing) into -// protoiface.MarshalInputFlags (used internally by the marshaler). -// -// See impl.marshalOptions.Options for the inverse operation. -func (o MarshalOptions) flags() protoiface.MarshalInputFlags { - var flags protoiface.MarshalInputFlags - - // Note: o.AllowPartial is always forced to true by MarshalOptions.marshal, - // which is why it is not a part of MarshalInputFlags. - - if o.Deterministic { - flags |= protoiface.MarshalDeterministic - } - - if o.UseCachedSize { - flags |= protoiface.MarshalUseCachedSize - } - - return flags -} - // Marshal returns the wire-format encoding of m. -// -// This is the most common entry point for encoding a Protobuf message. -// -// See the [MarshalOptions] type if you need more control. func Marshal(m Message) ([]byte, error) { // Treat nil message interface as an empty message; nothing to output. if m == nil { @@ -146,9 +116,6 @@ func emptyBytesForMessage(m Message) []byte { // MarshalAppend appends the wire-format encoding of m to b, // returning the result. -// -// This is a less common entry point than [Marshal], which is only needed if you -// need to supply your own buffers for performance reasons. func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) { // Treat nil message interface as an empty message; nothing to append. if m == nil { @@ -178,7 +145,12 @@ func (o MarshalOptions) marshal(b []byte, m protoreflect.Message) (out protoifac in := protoiface.MarshalInput{ Message: m, Buf: b, - Flags: o.flags(), + } + if o.Deterministic { + in.Flags |= protoiface.MarshalDeterministic + } + if o.UseCachedSize { + in.Flags |= protoiface.MarshalUseCachedSize } if methods.Size != nil { sout := methods.Size(protoiface.SizeInput{ @@ -196,10 +168,6 @@ func (o MarshalOptions) marshal(b []byte, m protoreflect.Message) (out protoifac out.Buf, err = o.marshalMessageSlow(b, m) } if err != nil { - var mismatch *protoerrors.SizeMismatchError - if errors.As(err, &mismatch) { - return out, fmt.Errorf("marshaling %s: %v", string(m.Descriptor().FullName()), err) - } return out, err } if allowPartial { diff --git a/vendor/google.golang.org/protobuf/proto/extension.go b/vendor/google.golang.org/protobuf/proto/extension.go index d248f292..17899a3a 100644 --- a/vendor/google.golang.org/protobuf/proto/extension.go +++ b/vendor/google.golang.org/protobuf/proto/extension.go @@ -11,21 +11,18 @@ import ( // HasExtension reports whether an extension field is populated. // It returns false if m is invalid or if xt does not extend m. func HasExtension(m Message, xt protoreflect.ExtensionType) bool { - // Treat nil message interface or descriptor as an empty message; no populated - // fields. - if m == nil || xt == nil { + // Treat nil message interface as an empty message; no populated fields. + if m == nil { return false } // As a special-case, we reports invalid or mismatching descriptors // as always not being populated (since they aren't). - mr := m.ProtoReflect() - xd := xt.TypeDescriptor() - if mr.Descriptor() != xd.ContainingMessage() { + if xt == nil || m.ProtoReflect().Descriptor() != xt.TypeDescriptor().ContainingMessage() { return false } - return mr.Has(xd) + return m.ProtoReflect().Has(xt.TypeDescriptor()) } // ClearExtension clears an extension field such that subsequent @@ -39,7 +36,7 @@ func ClearExtension(m Message, xt protoreflect.ExtensionType) { // If the field is unpopulated, it returns the default value for // scalars and an immutable, empty value for lists or messages. // It panics if xt does not extend m. -func GetExtension(m Message, xt protoreflect.ExtensionType) any { +func GetExtension(m Message, xt protoreflect.ExtensionType) interface{} { // Treat nil message interface as an empty message; return the default. if m == nil { return xt.InterfaceOf(xt.Zero()) @@ -51,7 +48,7 @@ func GetExtension(m Message, xt protoreflect.ExtensionType) any { // SetExtension stores the value of an extension field. // It panics if m is invalid, xt does not extend m, or if type of v // is invalid for the specified extension field. -func SetExtension(m Message, xt protoreflect.ExtensionType, v any) { +func SetExtension(m Message, xt protoreflect.ExtensionType, v interface{}) { xd := xt.TypeDescriptor() pv := xt.ValueOf(v) @@ -78,7 +75,7 @@ func SetExtension(m Message, xt protoreflect.ExtensionType, v any) { // It returns immediately if f returns false. // While iterating, mutating operations may only be performed // on the current extension field. -func RangeExtensions(m Message, f func(protoreflect.ExtensionType, any) bool) { +func RangeExtensions(m Message, f func(protoreflect.ExtensionType, interface{}) bool) { // Treat nil message interface as an empty message; nothing to range over. if m == nil { return diff --git a/vendor/google.golang.org/protobuf/proto/messageset.go b/vendor/google.golang.org/protobuf/proto/messageset.go index 575d1483..312d5d45 100644 --- a/vendor/google.golang.org/protobuf/proto/messageset.go +++ b/vendor/google.golang.org/protobuf/proto/messageset.go @@ -47,16 +47,11 @@ func (o MarshalOptions) marshalMessageSet(b []byte, m protoreflect.Message) ([]b func (o MarshalOptions) marshalMessageSetField(b []byte, fd protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) { b = messageset.AppendFieldStart(b, fd.Number()) b = protowire.AppendTag(b, messageset.FieldMessage, protowire.BytesType) - calculatedSize := o.Size(value.Message().Interface()) - b = protowire.AppendVarint(b, uint64(calculatedSize)) - before := len(b) + b = protowire.AppendVarint(b, uint64(o.Size(value.Message().Interface()))) b, err := o.marshalMessage(b, value.Message()) if err != nil { return b, err } - if measuredSize := len(b) - before; calculatedSize != measuredSize { - return nil, errors.MismatchedSizeCalculation(calculatedSize, measuredSize) - } b = messageset.AppendFieldEnd(b) return b, nil } diff --git a/vendor/google.golang.org/protobuf/proto/size.go b/vendor/google.golang.org/protobuf/proto/size.go index 052fb5ae..f1692b49 100644 --- a/vendor/google.golang.org/protobuf/proto/size.go +++ b/vendor/google.golang.org/protobuf/proto/size.go @@ -34,7 +34,6 @@ func (o MarshalOptions) size(m protoreflect.Message) (size int) { if methods != nil && methods.Size != nil { out := methods.Size(protoiface.SizeInput{ Message: m, - Flags: o.flags(), }) return out.Size } @@ -43,7 +42,6 @@ func (o MarshalOptions) size(m protoreflect.Message) (size int) { // This case is mainly used for legacy types with a Marshal method. out, _ := methods.Marshal(protoiface.MarshalInput{ Message: m, - Flags: o.flags(), }) return len(out.Buf) } diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/proto.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/proto.go index c85bfaa5..00b01fbd 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/proto.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/proto.go @@ -161,7 +161,7 @@ const ( // IsValid reports whether the syntax is valid. func (s Syntax) IsValid() bool { switch s { - case Proto2, Proto3, Editions: + case Proto2, Proto3: return true default: return false diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go index ea154eec..7dcc2ff0 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go @@ -373,8 +373,6 @@ func (p *SourcePath) appendFieldOptions(b []byte) []byte { b = p.appendRepeatedField(b, "edition_defaults", (*SourcePath).appendFieldOptions_EditionDefault) case 21: b = p.appendSingularField(b, "features", (*SourcePath).appendFeatureSet) - case 22: - b = p.appendSingularField(b, "feature_support", (*SourcePath).appendFieldOptions_FeatureSupport) case 999: b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption) } @@ -485,8 +483,6 @@ func (p *SourcePath) appendEnumValueOptions(b []byte) []byte { b = p.appendSingularField(b, "features", (*SourcePath).appendFeatureSet) case 3: b = p.appendSingularField(b, "debug_redact", nil) - case 4: - b = p.appendSingularField(b, "feature_support", (*SourcePath).appendFieldOptions_FeatureSupport) case 999: b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption) } @@ -523,23 +519,6 @@ func (p *SourcePath) appendFieldOptions_EditionDefault(b []byte) []byte { return b } -func (p *SourcePath) appendFieldOptions_FeatureSupport(b []byte) []byte { - if len(*p) == 0 { - return b - } - switch (*p)[0] { - case 1: - b = p.appendSingularField(b, "edition_introduced", nil) - case 2: - b = p.appendSingularField(b, "edition_deprecated", nil) - case 3: - b = p.appendSingularField(b, "deprecation_warning", nil) - case 4: - b = p.appendSingularField(b, "edition_removed", nil) - } - return b -} - func (p *SourcePath) appendUninterpretedOption_NamePart(b []byte) []byte { if len(*p) == 0 { return b diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/type.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/type.go index cd8fadba..60ff62b4 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/type.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/type.go @@ -510,7 +510,7 @@ type ExtensionType interface { // // ValueOf is more extensive than protoreflect.ValueOf for a given field's // value as it has more type information available. - ValueOf(any) Value + ValueOf(interface{}) Value // InterfaceOf completely unwraps the Value to the underlying Go type. // InterfaceOf panics if the input is nil or does not represent the @@ -519,13 +519,13 @@ type ExtensionType interface { // // InterfaceOf is able to unwrap the Value further than Value.Interface // as it has more type information available. - InterfaceOf(Value) any + InterfaceOf(Value) interface{} // IsValidValue reports whether the Value is valid to assign to the field. IsValidValue(Value) bool // IsValidInterface reports whether the input is valid to assign to the field. - IsValidInterface(any) bool + IsValidInterface(interface{}) bool } // EnumDescriptor describes an enum and @@ -544,12 +544,6 @@ type EnumDescriptor interface { // ReservedRanges is a list of reserved ranges of enum numbers. ReservedRanges() EnumRanges - // IsClosed reports whether this enum uses closed semantics. - // See https://protobuf.dev/programming-guides/enum/#definitions. - // Note: the Go protobuf implementation is not spec compliant and treats - // all enums as open enums. - IsClosed() bool - isEnumDescriptor } type isEnumDescriptor interface{ ProtoType(EnumDescriptor) } diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go index 75f83a2a..7ced876f 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go @@ -32,11 +32,11 @@ const ( type value struct { pragma.DoNotCompare // 0B - typ valueType // 8B - num uint64 // 8B - str string // 16B - bin []byte // 24B - iface any // 16B + typ valueType // 8B + num uint64 // 8B + str string // 16B + bin []byte // 24B + iface interface{} // 16B } func valueOfString(v string) Value { @@ -45,7 +45,7 @@ func valueOfString(v string) Value { func valueOfBytes(v []byte) Value { return Value{typ: bytesType, bin: v} } -func valueOfIface(v any) Value { +func valueOfIface(v interface{}) Value { return Value{typ: ifaceType, iface: v} } @@ -55,6 +55,6 @@ func (v Value) getString() string { func (v Value) getBytes() []byte { return v.bin } -func (v Value) getIface() any { +func (v Value) getIface() interface{} { return v.iface } diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_union.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_union.go index 9fe83cef..16030973 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_union.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_union.go @@ -69,8 +69,8 @@ import ( // composite Value. Modifying an empty, read-only value panics. type Value value -// The protoreflect API uses a custom Value union type instead of any -// to keep the future open for performance optimizations. Using an any +// The protoreflect API uses a custom Value union type instead of interface{} +// to keep the future open for performance optimizations. Using an interface{} // always incurs an allocation for primitives (e.g., int64) since it needs to // be boxed on the heap (as interfaces can only contain pointers natively). // Instead, we represent the Value union as a flat struct that internally keeps @@ -85,7 +85,7 @@ type Value value // ValueOf returns a Value initialized with the concrete value stored in v. // This panics if the type does not match one of the allowed types in the // Value union. -func ValueOf(v any) Value { +func ValueOf(v interface{}) Value { switch v := v.(type) { case nil: return Value{} @@ -192,10 +192,10 @@ func (v Value) IsValid() bool { return v.typ != nilType } -// Interface returns v as an any. +// Interface returns v as an interface{}. // // Invariant: v == ValueOf(v).Interface() -func (v Value) Interface() any { +func (v Value) Interface() interface{} { switch v.typ { case nilType: return nil @@ -406,8 +406,8 @@ func (k MapKey) IsValid() bool { return Value(k).IsValid() } -// Interface returns k as an any. -func (k MapKey) Interface() any { +// Interface returns k as an interface{}. +func (k MapKey) Interface() interface{} { return Value(k).Interface() } diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go index 7f3583ea..b1fdbe3e 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go @@ -45,7 +45,7 @@ var ( // typeOf returns a pointer to the Go type information. // The pointer is comparable and equal if and only if the types are identical. -func typeOf(t any) unsafe.Pointer { +func typeOf(t interface{}) unsafe.Pointer { return (*ifaceHeader)(unsafe.Pointer(&t)).Type } @@ -80,7 +80,7 @@ func valueOfBytes(v []byte) Value { p := (*sliceHeader)(unsafe.Pointer(&v)) return Value{typ: bytesType, ptr: p.Data, num: uint64(len(v))} } -func valueOfIface(v any) Value { +func valueOfIface(v interface{}) Value { p := (*ifaceHeader)(unsafe.Pointer(&v)) return Value{typ: p.Type, ptr: p.Data} } @@ -93,7 +93,7 @@ func (v Value) getBytes() (x []byte) { *(*sliceHeader)(unsafe.Pointer(&x)) = sliceHeader{Data: v.ptr, Len: int(v.num), Cap: int(v.num)} return x } -func (v Value) getIface() (x any) { +func (v Value) getIface() (x interface{}) { *(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr} return x } diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go index f7d38699..43547011 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go +++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go @@ -15,7 +15,7 @@ import ( type ( ifaceHeader struct { - _ [0]any // if interfaces have greater alignment than unsafe.Pointer, this will enforce it. + _ [0]interface{} // if interfaces have greater alignment than unsafe.Pointer, this will enforce it. Type unsafe.Pointer Data unsafe.Pointer } @@ -37,7 +37,7 @@ var ( // typeOf returns a pointer to the Go type information. // The pointer is comparable and equal if and only if the types are identical. -func typeOf(t any) unsafe.Pointer { +func typeOf(t interface{}) unsafe.Pointer { return (*ifaceHeader)(unsafe.Pointer(&t)).Type } @@ -70,7 +70,7 @@ func valueOfString(v string) Value { func valueOfBytes(v []byte) Value { return Value{typ: bytesType, ptr: unsafe.Pointer(unsafe.SliceData(v)), num: uint64(len(v))} } -func valueOfIface(v any) Value { +func valueOfIface(v interface{}) Value { p := (*ifaceHeader)(unsafe.Pointer(&v)) return Value{typ: p.Type, ptr: p.Data} } @@ -81,7 +81,7 @@ func (v Value) getString() string { func (v Value) getBytes() []byte { return unsafe.Slice((*byte)(v.ptr), v.num) } -func (v Value) getIface() (x any) { +func (v Value) getIface() (x interface{}) { *(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr} return x } diff --git a/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go b/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go index de177733..6267dc52 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go +++ b/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go @@ -95,7 +95,7 @@ type Files struct { // multiple files. Only top-level declarations are registered. // Note that enum values are in the top-level since that are in the same // scope as the parent enum. - descsByName map[protoreflect.FullName]any + descsByName map[protoreflect.FullName]interface{} filesByPath map[string][]protoreflect.FileDescriptor numFiles int } @@ -117,7 +117,7 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error { defer globalMutex.Unlock() } if r.descsByName == nil { - r.descsByName = map[protoreflect.FullName]any{ + r.descsByName = map[protoreflect.FullName]interface{}{ "": &packageDescriptor{}, } r.filesByPath = make(map[string][]protoreflect.FileDescriptor) @@ -485,7 +485,7 @@ type Types struct { } type ( - typesByName map[protoreflect.FullName]any + typesByName map[protoreflect.FullName]interface{} extensionsByMessage map[protoreflect.FullName]extensionsByNumber extensionsByNumber map[protoreflect.FieldNumber]protoreflect.ExtensionType ) @@ -570,7 +570,7 @@ func (r *Types) RegisterExtension(xt protoreflect.ExtensionType) error { return nil } -func (r *Types) register(kind string, desc protoreflect.Descriptor, typ any) error { +func (r *Types) register(kind string, desc protoreflect.Descriptor, typ interface{}) error { name := desc.FullName() prev := r.typesByName[name] if prev != nil { @@ -841,7 +841,7 @@ func (r *Types) RangeExtensionsByMessage(message protoreflect.FullName, f func(p } } -func typeName(t any) string { +func typeName(t interface{}) string { switch t.(type) { case protoreflect.EnumType: return "enum" @@ -854,7 +854,7 @@ func typeName(t any) string { } } -func amendErrorWithCaller(err error, prev, curr any) error { +func amendErrorWithCaller(err error, prev, curr interface{}) error { prevPkg := goPackage(prev) currPkg := goPackage(curr) if prevPkg == "" || currPkg == "" || prevPkg == currPkg { @@ -863,7 +863,7 @@ func amendErrorWithCaller(err error, prev, curr any) error { return errors.New("%s\n\tpreviously from: %q\n\tcurrently from: %q", err, prevPkg, currPkg) } -func goPackage(v any) string { +func goPackage(v interface{}) string { switch d := v.(type) { case protoreflect.EnumType: v = d.Descriptor() diff --git a/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go b/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go index 83a5a645..81511a33 100644 --- a/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go +++ b/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go @@ -332,7 +332,7 @@ func file_google_protobuf_timestamp_proto_rawDescGZIP() []byte { } var file_google_protobuf_timestamp_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_google_protobuf_timestamp_proto_goTypes = []any{ +var file_google_protobuf_timestamp_proto_goTypes = []interface{}{ (*Timestamp)(nil), // 0: google.protobuf.Timestamp } var file_google_protobuf_timestamp_proto_depIdxs = []int32{ @@ -349,7 +349,7 @@ func file_google_protobuf_timestamp_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_google_protobuf_timestamp_proto_msgTypes[0].Exporter = func(v any, i int) any { + file_google_protobuf_timestamp_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Timestamp); i { case 0: return &v.state diff --git a/vendor/modules.txt b/vendor/modules.txt index 9880cda5..03cf0f3c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,5 +1,5 @@ -# github.com/DataDog/zstd v1.5.5 -## explicit; go 1.14 +# github.com/DataDog/zstd v1.4.5 +## explicit github.com/DataDog/zstd # github.com/DeOne4eg/eth-unit-converter v0.2.0 ## explicit; go 1.16 @@ -14,6 +14,9 @@ github.com/Microsoft/go-winio/pkg/guid # github.com/OneOfOne/xxhash v1.2.8 ## explicit; go 1.11 github.com/OneOfOne/xxhash +# github.com/StackExchange/wmi v1.2.1 +## explicit; go 1.13 +github.com/StackExchange/wmi # github.com/VictoriaMetrics/fastcache v1.12.2 ## explicit; go 1.13 github.com/VictoriaMetrics/fastcache @@ -40,10 +43,10 @@ github.com/arl/statsviz/internal/static # github.com/beorn7/perks v1.0.1 ## explicit; go 1.11 github.com/beorn7/perks/quantile -# github.com/bits-and-blooms/bitset v1.13.0 +# github.com/bits-and-blooms/bitset v1.10.0 ## explicit; go 1.16 github.com/bits-and-blooms/bitset -# github.com/btcsuite/btcd/btcec/v2 v2.3.3 +# github.com/btcsuite/btcd/btcec/v2 v2.2.0 ## explicit; go 1.17 github.com/btcsuite/btcd/btcec/v2 github.com/btcsuite/btcd/btcec/v2/ecdsa @@ -71,7 +74,7 @@ github.com/cockroachdb/errors/secondary github.com/cockroachdb/errors/stdstrings github.com/cockroachdb/errors/telemetrykeys github.com/cockroachdb/errors/withstack -# github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a +# github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce ## explicit; go 1.20 github.com/cockroachdb/fifo # github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b @@ -169,11 +172,11 @@ github.com/davecgh/go-spew/spew # github.com/deckarep/golang-set/v2 v2.6.0 ## explicit; go 1.18 github.com/deckarep/golang-set/v2 -# github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 -## explicit; go 1.17 +# github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 +## explicit; go 1.16 github.com/decred/dcrd/dcrec/secp256k1/v4 github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa -# github.com/ethereum/c-kzg-4844 v1.0.2 +# github.com/ethereum/c-kzg-4844 v1.0.0 ## explicit; go 1.19 github.com/ethereum/c-kzg-4844/bindings/go # github.com/ethereum/go-ethereum v1.14.7 @@ -292,16 +295,16 @@ github.com/fjl/memsize/memsizeui # github.com/fsnotify/fsnotify v1.7.0 ## explicit; go 1.17 github.com/fsnotify/fsnotify -# github.com/gabriel-vasile/mimetype v1.4.4 +# github.com/gabriel-vasile/mimetype v1.4.3 ## explicit; go 1.20 github.com/gabriel-vasile/mimetype github.com/gabriel-vasile/mimetype/internal/charset github.com/gabriel-vasile/mimetype/internal/json github.com/gabriel-vasile/mimetype/internal/magic -# github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 +# github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff ## explicit github.com/gballet/go-libpcsclite -# github.com/gdamore/encoding v1.0.1 +# github.com/gdamore/encoding v1.0.0 ## explicit; go 1.9 github.com/gdamore/encoding # github.com/gdamore/tcell/v2 v2.7.4 @@ -343,7 +346,7 @@ github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi github.com/gdamore/tcell/v2/terminfo/x/xfce github.com/gdamore/tcell/v2/terminfo/x/xterm github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty -# github.com/getsentry/sentry-go v0.28.1 +# github.com/getsentry/sentry-go v0.27.0 ## explicit; go 1.18 github.com/getsentry/sentry-go github.com/getsentry/sentry-go/internal/debug @@ -395,8 +398,8 @@ github.com/gobwas/glob/syntax/ast github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings -# github.com/gofrs/flock v0.12.0 -## explicit; go 1.21.0 +# github.com/gofrs/flock v0.8.1 +## explicit github.com/gofrs/flock # github.com/gogo/protobuf v1.3.2 ## explicit; go 1.15 @@ -420,11 +423,11 @@ github.com/gorilla/mux # github.com/gorilla/websocket v1.5.3 ## explicit; go 1.12 github.com/gorilla/websocket -# github.com/hashicorp/go-bexpr v0.1.14 -## explicit; go 1.18 +# github.com/hashicorp/go-bexpr v0.1.10 +## explicit; go 1.14 github.com/hashicorp/go-bexpr github.com/hashicorp/go-bexpr/grammar -# github.com/holiman/billy v0.0.0-20240322075458-72a4e81ec6da +# github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 ## explicit; go 1.18 github.com/holiman/billy # github.com/holiman/bloomfilter/v2 v2.0.3 @@ -448,7 +451,7 @@ github.com/inconshreveable/mousetrap # github.com/jackc/pgpassfile v1.0.0 ## explicit; go 1.12 github.com/jackc/pgpassfile -# github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 +# github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a ## explicit; go 1.14 github.com/jackc/pgservicefile # github.com/jackc/pgx/v5 v5.6.0 @@ -476,8 +479,8 @@ github.com/jackpal/go-nat-pmp ## explicit; go 1.10 github.com/jmoiron/sqlx github.com/jmoiron/sqlx/reflectx -# github.com/klauspost/compress v1.17.9 -## explicit; go 1.20 +# github.com/klauspost/compress v1.17.0 +## explicit; go 1.18 github.com/klauspost/compress github.com/klauspost/compress/fse github.com/klauspost/compress/huff0 @@ -504,13 +507,13 @@ github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.20 ## explicit; go 1.15 github.com/mattn/go-isatty -# github.com/mattn/go-runewidth v0.0.15 +# github.com/mattn/go-runewidth v0.0.16 ## explicit; go 1.9 github.com/mattn/go-runewidth # github.com/mitchellh/mapstructure v1.5.0 ## explicit; go 1.14 github.com/mitchellh/mapstructure -# github.com/mitchellh/pointerstructure v1.2.1 +# github.com/mitchellh/pointerstructure v1.2.0 ## explicit; go 1.13 github.com/mitchellh/pointerstructure # github.com/mmcloughlin/addchain v0.4.0 @@ -537,9 +540,6 @@ github.com/mmcloughlin/addchain/internal/container/heap github.com/mmcloughlin/addchain/internal/errutil github.com/mmcloughlin/addchain/internal/print github.com/mmcloughlin/addchain/meta -# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 -## explicit -github.com/munnerz/goautoneg # github.com/olekukonko/tablewriter v0.0.5 ## explicit; go 1.12 github.com/olekukonko/tablewriter @@ -642,32 +642,32 @@ github.com/prometheus/client_golang/prometheus/internal # github.com/prometheus/client_model v0.6.1 ## explicit; go 1.19 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.55.0 +# github.com/prometheus/common v0.48.0 ## explicit; go 1.20 github.com/prometheus/common/expfmt +github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model -# github.com/prometheus/procfs v0.15.1 -## explicit; go 1.20 +# github.com/prometheus/procfs v0.12.0 +## explicit; go 1.19 github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util -# github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 +# github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 ## explicit github.com/rcrowley/go-metrics -# github.com/rivo/uniseg v0.4.7 +# github.com/rivo/uniseg v0.4.3 ## explicit; go 1.18 github.com/rivo/uniseg -# github.com/rogpeppe/go-internal v1.12.0 -## explicit; go 1.20 +# github.com/rogpeppe/go-internal v1.11.0 +## explicit; go 1.19 github.com/rogpeppe/go-internal/fmtsort -# github.com/rs/cors v1.11.0 -## explicit; go 1.13 +# github.com/rs/cors v1.7.0 +## explicit github.com/rs/cors -github.com/rs/cors/internal # github.com/russross/blackfriday/v2 v2.1.0 ## explicit github.com/russross/blackfriday/v2 -# github.com/shirou/gopsutil v3.21.11+incompatible +# github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible ## explicit github.com/shirou/gopsutil/cpu github.com/shirou/gopsutil/internal/common @@ -680,10 +680,10 @@ github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 ## explicit; go 1.12 github.com/spf13/pflag -# github.com/status-im/keycard-go v0.3.2 +# github.com/status-im/keycard-go v0.2.0 ## explicit; go 1.17 github.com/status-im/keycard-go/derivationpath -# github.com/supranational/blst v0.3.12 +# github.com/supranational/blst v0.3.11 ## explicit; go 1.11 github.com/supranational/blst/bindings/go # github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 @@ -703,17 +703,17 @@ github.com/syndtr/goleveldb/leveldb/util # github.com/tchap/go-patricia/v2 v2.3.1 ## explicit; go 1.16 github.com/tchap/go-patricia/v2/patricia -# github.com/tklauser/go-sysconf v0.3.14 -## explicit; go 1.18 +# github.com/tklauser/go-sysconf v0.3.12 +## explicit; go 1.13 github.com/tklauser/go-sysconf -# github.com/tklauser/numcpus v0.8.0 -## explicit; go 1.18 +# github.com/tklauser/numcpus v0.6.1 +## explicit; go 1.13 github.com/tklauser/numcpus # github.com/tyler-smith/go-bip39 v1.1.0 ## explicit; go 1.14 github.com/tyler-smith/go-bip39 github.com/tyler-smith/go-bip39/wordlists -# github.com/urfave/cli/v2 v2.27.2 +# github.com/urfave/cli/v2 v2.25.7 ## explicit; go 1.18 github.com/urfave/cli/v2 # github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb @@ -722,17 +722,14 @@ github.com/xeipuuv/gojsonpointer # github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 ## explicit github.com/xeipuuv/gojsonreference -# github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 -## explicit; go 1.15 +# github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 +## explicit github.com/xrash/smetrics # github.com/yashtewari/glob-intersection v0.2.0 ## explicit; go 1.17 github.com/yashtewari/glob-intersection -# github.com/yusufpapurcu/wmi v1.2.4 -## explicit; go 1.16 -github.com/yusufpapurcu/wmi -# go.opentelemetry.io/otel v1.28.0 -## explicit; go 1.21 +# go.opentelemetry.io/otel v1.21.0 +## explicit; go 1.20 go.opentelemetry.io/otel go.opentelemetry.io/otel/attribute go.opentelemetry.io/otel/baggage @@ -742,37 +739,37 @@ go.opentelemetry.io/otel/internal/attribute go.opentelemetry.io/otel/internal/baggage go.opentelemetry.io/otel/internal/global go.opentelemetry.io/otel/propagation -go.opentelemetry.io/otel/semconv/v1.26.0 -# go.opentelemetry.io/otel/metric v1.28.0 -## explicit; go 1.21 +go.opentelemetry.io/otel/semconv/v1.21.0 +# go.opentelemetry.io/otel/metric v1.21.0 +## explicit; go 1.20 go.opentelemetry.io/otel/metric go.opentelemetry.io/otel/metric/embedded -# go.opentelemetry.io/otel/sdk v1.28.0 -## explicit; go 1.21 +# go.opentelemetry.io/otel/sdk v1.21.0 +## explicit; go 1.20 go.opentelemetry.io/otel/sdk go.opentelemetry.io/otel/sdk/instrumentation +go.opentelemetry.io/otel/sdk/internal go.opentelemetry.io/otel/sdk/internal/env -go.opentelemetry.io/otel/sdk/internal/x go.opentelemetry.io/otel/sdk/resource go.opentelemetry.io/otel/sdk/trace -# go.opentelemetry.io/otel/trace v1.28.0 -## explicit; go 1.21 +# go.opentelemetry.io/otel/trace v1.21.0 +## explicit; go 1.20 go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/noop -# golang.org/x/crypto v0.25.0 -## explicit; go 1.20 +# golang.org/x/crypto v0.24.0 +## explicit; go 1.18 golang.org/x/crypto/hkdf golang.org/x/crypto/pbkdf2 golang.org/x/crypto/ripemd160 golang.org/x/crypto/scrypt golang.org/x/crypto/sha3 -# golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 +# golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa ## explicit; go 1.20 golang.org/x/exp/constraints golang.org/x/exp/maps golang.org/x/exp/rand -# golang.org/x/net v0.27.0 +# golang.org/x/net v0.26.0 ## explicit; go 1.18 golang.org/x/net/html golang.org/x/net/html/atom @@ -781,7 +778,7 @@ golang.org/x/net/html/atom golang.org/x/sync/errgroup golang.org/x/sync/semaphore golang.org/x/sync/singleflight -# golang.org/x/sys v0.22.0 +# golang.org/x/sys v0.21.0 ## explicit; go 1.18 golang.org/x/sys/cpu golang.org/x/sys/execabs @@ -789,7 +786,7 @@ golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows golang.org/x/sys/windows/registry -# golang.org/x/term v0.22.0 +# golang.org/x/term v0.21.0 ## explicit; go 1.18 golang.org/x/term # golang.org/x/text v0.16.0 @@ -816,8 +813,8 @@ golang.org/x/time/rate ## explicit; go 1.19 # google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 ## explicit; go 1.19 -# google.golang.org/protobuf v1.34.2 -## explicit; go 1.20 +# google.golang.org/protobuf v1.33.0 +## explicit; go 1.17 google.golang.org/protobuf/encoding/protodelim google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/protowire diff --git a/zarf/docker/dockerfile.engine b/zarf/docker/dockerfile.engine index 4f8bd141..fe6842ec 100644 --- a/zarf/docker/dockerfile.engine +++ b/zarf/docker/dockerfile.engine @@ -1,6 +1,6 @@ # Build the Go Binary. -FROM golang:1.22 as build_engine -ENV CGO_ENABLED 0 +FROM golang:1.22 AS build_engine +ENV CGO_ENABLED=0 ARG BUILD_REF # Copy the source code into the container. @@ -16,7 +16,7 @@ RUN go build -ldflags "-X main.build=${BUILD_REF}" # Run the Go Binary in Alpine. -FROM alpine:3.19 +FROM alpine:3.20 ARG BUILD_DATE ARG BUILD_REF RUN addgroup -g 1000 -S engine && \