diff --git a/configure.ac b/configure.ac index d66f26a7a16..d1012d4b3e8 100644 --- a/configure.ac +++ b/configure.ac @@ -857,6 +857,7 @@ case $host_os_def in debug_opt="-g $common_opt" release_opt="-g $common_opt $optimization_flags -axsse4.2 -fno-strict-aliasing" cxx_opt="-Wno-invalid-offsetof" + TS_ADDTO([AM_LDFLAGS], [-Wl,-lstdc++]) ]) AS_IF([test "x$ax_cv_c_compiler_vendor" = "xclang"], [ diff --git a/include/tscore/ConsistentHash.h b/include/tscore/ConsistentHash.h index 9946776cc61..692672bd7ec 100644 --- a/include/tscore/ConsistentHash.h +++ b/include/tscore/ConsistentHash.h @@ -21,10 +21,11 @@ #pragma once -#include "Hash.h" +#include "tscpp/util/Hash.h" #include #include #include +#include /* Helper class to be extended to make ring nodes. @@ -46,17 +47,17 @@ typedef std::map::iterator ATSConsistentHashI */ struct ATSConsistentHash { - ATSConsistentHash(int r = 1024, ATSHash64 *h = nullptr); - void insert(ATSConsistentHashNode *node, float weight = 1.0, ATSHash64 *h = nullptr); + ATSConsistentHash(int r = 1024, ts::Hash64Functor *h = nullptr); + void insert(ATSConsistentHashNode *node, float weight = 1.0, ts::Hash64Functor *h = nullptr); ATSConsistentHashNode *lookup(const char *url = nullptr, ATSConsistentHashIter *i = nullptr, bool *w = nullptr, - ATSHash64 *h = nullptr); + ts::Hash64Functor *h = nullptr); ATSConsistentHashNode *lookup_available(const char *url = nullptr, ATSConsistentHashIter *i = nullptr, bool *w = nullptr, - ATSHash64 *h = nullptr); + ts::Hash64Functor *h = nullptr); ATSConsistentHashNode *lookup_by_hashval(uint64_t hashval, ATSConsistentHashIter *i = nullptr, bool *w = nullptr); ~ATSConsistentHash(); private: int replicas; - ATSHash64 *hash; + std::unique_ptr hash; std::map NodeMap; }; diff --git a/include/tscore/EnumDescriptor.h b/include/tscore/EnumDescriptor.h index 485a5c3db59..446ee5785ed 100644 --- a/include/tscore/EnumDescriptor.h +++ b/include/tscore/EnumDescriptor.h @@ -22,15 +22,13 @@ #include #include -#include "tscore/HashFNV.h" +#include "tscpp/util/HashFNV.h" /// Hash functor for @c string_view inline size_t TsLuaConfigSVHash(std::string_view const &sv) { - ATSHash64FNV1a h; - h.update(sv.data(), sv.size()); - return h.get(); + return ts::Hash64FNV1a().hash_immediate(sv); } class TsEnumDescriptor diff --git a/include/tscore/Hash.h b/include/tscore/Hash.h deleted file mode 100644 index 68879a93951..00000000000 --- a/include/tscore/Hash.h +++ /dev/null @@ -1,65 +0,0 @@ -/** @file - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#pragma once - -#include -#include -#include - -struct ATSHashBase { - virtual void update(const void *, size_t) = 0; - virtual void final(void) = 0; - virtual void clear(void) = 0; - virtual ~ATSHashBase(); -}; - -struct ATSHash : ATSHashBase { - struct nullxfrm { - uint8_t - operator()(uint8_t byte) const - { - return byte; - } - }; - - struct nocase { - uint8_t - operator()(uint8_t byte) const - { - return toupper(byte); - } - }; - - virtual const void *get(void) const = 0; - virtual size_t size(void) const = 0; - virtual bool operator==(const ATSHash &) const; -}; - -struct ATSHash32 : ATSHashBase { - virtual uint32_t get(void) const = 0; - virtual bool operator==(const ATSHash32 &) const; -}; - -struct ATSHash64 : ATSHashBase { - virtual uint64_t get(void) const = 0; - virtual bool operator==(const ATSHash64 &) const; -}; diff --git a/include/tscore/HashFNV.h b/include/tscore/HashFNV.h deleted file mode 100644 index e113d0cd012..00000000000 --- a/include/tscore/HashFNV.h +++ /dev/null @@ -1,93 +0,0 @@ -/** @file - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -/* - http://www.isthe.com/chongo/tech/comp/fnv/ - - Currently implemented FNV-1a 32bit and FNV-1a 64bit - */ - -#pragma once - -#include "tscore/Hash.h" -#include - -struct ATSHash32FNV1a : ATSHash32 { - ATSHash32FNV1a(void); - - template void update(const void *data, size_t len, Transform xfrm); - void - update(const void *data, size_t len) override - { - update(data, len, ATSHash::nullxfrm()); - } - - void final(void) override; - uint32_t get(void) const override; - void clear(void) override; - -private: - uint32_t hval; -}; - -template -void -ATSHash32FNV1a::update(const void *data, size_t len, Transform xfrm) -{ - uint8_t *bp = (uint8_t *)data; - uint8_t *be = bp + len; - - for (; bp < be; ++bp) { - hval ^= (uint32_t)xfrm(*bp); - hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); - } -} - -struct ATSHash64FNV1a : ATSHash64 { - ATSHash64FNV1a(void); - - template void update(const void *data, size_t len, Transform xfrm); - void - update(const void *data, size_t len) override - { - update(data, len, ATSHash::nullxfrm()); - } - - void final(void) override; - uint64_t get(void) const override; - void clear(void) override; - -private: - uint64_t hval; -}; - -template -void -ATSHash64FNV1a::update(const void *data, size_t len, Transform xfrm) -{ - uint8_t *bp = (uint8_t *)data; - uint8_t *be = bp + len; - - for (; bp < be; ++bp) { - hval ^= (uint64_t)xfrm(*bp); - hval += (hval << 1) + (hval << 4) + (hval << 5) + (hval << 7) + (hval << 8) + (hval << 40); - } -} diff --git a/include/tscore/HashMD5.h b/include/tscore/HashMD5.h index bad5a90cc80..72ffd2e5e59 100644 --- a/include/tscore/HashMD5.h +++ b/include/tscore/HashMD5.h @@ -21,21 +21,31 @@ #pragma once -#include "tscore/Hash.h" +#include "tscpp/util/Hash.h" #include -struct ATSHashMD5 : ATSHash { - ATSHashMD5(void); - void update(const void *data, size_t len) override; - void final(void) override; - const void *get(void) const override; - size_t size(void) const override; - void clear(void) override; - ~ATSHashMD5() override; +namespace ts +{ +struct HashMD5 : HashFunctor { + HashMD5(); + + HashMD5 &update(std::string_view const &data) override; + + HashMD5 & final() override; + + bool get(MemSpan dst) const override; + + size_t size() const override; + + HashMD5 &clear() override; + + ~HashMD5() override; private: - EVP_MD_CTX *ctx; + EVP_MD_CTX *ctx{nullptr}; unsigned char md_value[EVP_MAX_MD_SIZE]; - unsigned int md_len; - bool finalized; + unsigned int md_len{0}; + bool finalized{false}; }; + +} // namespace ts diff --git a/include/tscpp/util/Hash.h b/include/tscpp/util/Hash.h new file mode 100644 index 00000000000..5a2829f3e08 --- /dev/null +++ b/include/tscpp/util/Hash.h @@ -0,0 +1,153 @@ +/** @file Basic hash function support. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + +#pragma once + +#include +#include +#include +#include "tscpp/util/MemSpan.h" +#include "tscpp/util/TextView.h" + +namespace ts +{ +/** Base protocol class for hash functors. + * + * Each specific hash function embedded in a hash functor is a subclass of this class and + * follows this API. Subclasses should override the return type to return the subclass type. + * + * The main purpose of this is to allow run time changes in hashing, which is required in various + * circumstances. + */ +struct HashFunctor { + using self_type = HashFunctor; ///< Self reference type. + + /// Pass @a data to the hashing function. + virtual self_type &update(std::string_view const &data) = 0; + + /// Finalize the hash function output. + virtual self_type & final() = 0; + + /// Reset the hash function state. + virtual self_type &clear() = 0; + + /// Get the size of the resulting hash value. + virtual size_t size() const = 0; + + /// Copy the result to @a dst. + /// @a dst must be at least @c result_size bytes long. + /// @return @c true if the result was copied to @a data, @c false otherwise. + virtual bool get(MemSpan dst) const = 0; + + virtual ~HashFunctor() = default; ///< Force virtual destructor. +}; + +/// A hash function that returns a 32 bit result. +struct Hash32Functor : HashFunctor { +protected: + using self_type = Hash32Functor; + +public: + using value_type = uint32_t; + + // Co-vary the return type. + self_type &update(std::string_view const &data) override = 0; + + self_type & final() override = 0; + + self_type &clear() override = 0; + + virtual value_type get() const = 0; + + /// Get the size of the resulting hash value. + size_t size() const override; + + bool get(MemSpan dst) const override; + + /** Immediately produce a hash value from @a data. + * + * @param data Hash input + * @return Hash value. + * + * This is a convenience method for when all the data to hash is already available. + */ + value_type hash_immediate(std::string_view const &data); +}; + +struct Hash64Functor : HashFunctor { +protected: + using self_type = Hash64Functor; + +public: + using value_type = uint64_t; + + // Co-vary the return type. + self_type &update(std::string_view const &data) override = 0; + + self_type & final() override = 0; + + self_type &clear() override = 0; + + virtual value_type get() const = 0; + + /// Get the size of the resulting hash value. + size_t size() const override; + + bool get(MemSpan dst) const override; + + /** Immediately produce a hash value from @a data. + * + * @param data hash input + * @return Hash value. + * + * This is a convenience method for when all the data to hash is already available. + */ + value_type hash_immediate(std::string_view const &data); +}; + +// ---- +// Implementation + +inline auto +Hash32Functor::hash_immediate(std::string_view const &data) -> value_type +{ + return this->update(data).final().get(); +} + +inline size_t +Hash32Functor::size() const +{ + return sizeof(value_type); +} + +inline auto +Hash64Functor::hash_immediate(std::string_view const &data) -> value_type +{ + return this->update(data).final().get(); +} + +inline size_t +Hash64Functor::size() const +{ + return sizeof(value_type); +} + +} // namespace ts diff --git a/include/tscpp/util/HashFNV.h b/include/tscpp/util/HashFNV.h new file mode 100644 index 00000000000..1ffc1607d77 --- /dev/null +++ b/include/tscpp/util/HashFNV.h @@ -0,0 +1,177 @@ +/** @file + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. + See the NOTICE file distributed with this work for additional information regarding copyright + ownership. The ASF licenses this file to you 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. + */ + +/* + http://www.isthe.com/chongo/tech/comp/fnv/ + + Currently implemented FNV-1a 32bit and FNV-1a 64bit + */ + +#pragma once + +#include +#include "tscpp/util/Hash.h" + +namespace ts +{ +struct Hash32FNV1a : Hash32Functor { +protected: + using self_type = Hash32FNV1a; + using super_type = Hash32Functor; + static constexpr uint32_t INIT = 0x811c9dc5u; + +public: + Hash32FNV1a() = default; + + self_type &update(std::string_view const &data) override; + + self_type & final() override; + + value_type get() const override; + + self_type &clear() override; + + template self_type &update(TransformView view); + + template value_type hash_immediate(TransformView const &view); + using super_type::hash_immediate; + +private: + value_type hval{INIT}; +}; + +struct Hash64FNV1a : Hash64Functor { +protected: + using self_type = Hash64FNV1a; + using super_type = Hash64Functor; + static constexpr uint64_t INIT = 0xcbf29ce484222325ull; + +public: + Hash64FNV1a() = default; + + self_type &update(std::string_view const &data) override; + + self_type & final() override; + + value_type get() const override; + + self_type &clear() override; + + template self_type &update(TransformView view); + + template value_type hash_immediate(TransformView const &view); + using super_type::hash_immediate; + +private: + value_type hval{INIT}; +}; + +// ---------- +// Implementation + +// -- 32 -- + +inline auto +Hash32FNV1a::clear() -> self_type & +{ + hval = INIT; + return *this; +} + +template +auto +Hash32FNV1a::update(TransformView view) -> self_type & +{ + for (; view; ++view) { + hval ^= static_cast(*view); + hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); + } + return *this; +} + +inline auto +Hash32FNV1a::update(std::string_view const &data) -> self_type & +{ + return this->update(transform_view_of(data)); +} + +inline auto +Hash32FNV1a::final() -> self_type & +{ + return *this; +} + +inline auto +Hash32FNV1a::get() const -> value_type +{ + return hval; +} + +template +auto +Hash32FNV1a::hash_immediate(ts::TransformView const &view) -> value_type +{ + return this->update(view).get(); +} + +// -- 64 -- + +inline auto +Hash64FNV1a::clear() -> self_type & +{ + hval = INIT; + return *this; +} + +template +auto +Hash64FNV1a::update(TransformView view) -> self_type & +{ + for (; view; ++view) { + hval ^= static_cast(*view); + hval += (hval << 1) + (hval << 4) + (hval << 5) + (hval << 7) + (hval << 8) + (hval << 40); + } + return *this; +} + +inline auto +Hash64FNV1a::update(std::string_view const &data) -> self_type & +{ + return this->update(transform_view_of(data)); +} + +inline auto +Hash64FNV1a::final() -> self_type & +{ + return *this; +} + +inline auto +Hash64FNV1a::get() const -> value_type +{ + return hval; +} + +template +auto +Hash64FNV1a::hash_immediate(ts::TransformView const &view) -> value_type +{ + return this->update(view).final().get(); +} + +} // namespace ts diff --git a/include/tscore/HashSip.h b/include/tscpp/util/HashSip.h similarity index 51% rename from include/tscore/HashSip.h rename to include/tscpp/util/HashSip.h index 837289848dc..dd780b5595d 100644 --- a/include/tscore/HashSip.h +++ b/include/tscpp/util/HashSip.h @@ -21,9 +21,11 @@ #pragma once -#include "tscore/Hash.h" +#include "tscpp/util/Hash.h" #include +namespace ts +{ /* Siphash is a Hash Message Authentication Code and can take a key. @@ -31,25 +33,36 @@ a zero key for you. */ -struct ATSHash64Sip24 : ATSHash64 { - ATSHash64Sip24(void); - ATSHash64Sip24(const unsigned char key[16]); - ATSHash64Sip24(std::uint64_t key0, std::uint64_t key1); - void update(const void *data, std::size_t len) override; - void final(void) override; - std::uint64_t get(void) const override; - void clear(void) override; +struct Hash64Sip24 : public Hash64Functor { + static constexpr size_t KEY_SIZE = 16; + + Hash64Sip24(); + + Hash64Sip24(const unsigned char key[KEY_SIZE]); + + Hash64Sip24(std::uint64_t key0, std::uint64_t key1); + + Hash64Sip24 &update(std::string_view const &data) override; + + Hash64Sip24 & final() override; + + value_type get() const override; + + Hash64Sip24 &clear() override; private: - unsigned char block_buffer[8] = {0}; - std::uint8_t block_buffer_len = 0; - std::uint64_t k0 = 0; - std::uint64_t k1 = 0; - std::uint64_t v0 = 0; - std::uint64_t v1 = 0; - std::uint64_t v2 = 0; - std::uint64_t v3 = 0; - std::uint64_t hfinal = 0; - std::size_t total_len = 0; - bool finalized = false; + static constexpr size_t BLOCK_SIZE = 8; + unsigned char block_buffer[BLOCK_SIZE] = {0}; + std::uint8_t block_buffer_len = 0; + std::uint64_t k0 = 0; + std::uint64_t k1 = 0; + std::uint64_t v0 = 0; + std::uint64_t v1 = 0; + std::uint64_t v2 = 0; + std::uint64_t v3 = 0; + std::uint64_t hfinal = 0; + std::size_t total_len = 0; + bool finalized = false; }; + +} // namespace ts diff --git a/include/tscpp/util/Makefile.am b/include/tscpp/util/Makefile.am index 5fea12cd2d1..72463525e3f 100644 --- a/include/tscpp/util/Makefile.am +++ b/include/tscpp/util/Makefile.am @@ -19,6 +19,9 @@ library_includedir=$(includedir)/tscpp/util library_include_HEADERS = \ - IntrusiveDList.h \ + Hash.h \ + HashFNV.h \ + HashSip.h \ + IntrusiveDList.h \ PostScript.h \ TextView.h diff --git a/include/tscpp/util/TextView.h b/include/tscpp/util/TextView.h index 0ac740d6517..0bdb600e333 100644 --- a/include/tscpp/util/TextView.h +++ b/include/tscpp/util/TextView.h @@ -27,6 +27,7 @@ #pragma once #include #include +#include #include #include #include @@ -1168,7 +1169,242 @@ TextView::stream_write(Stream &os, const TextView &b) const // Provide an instantiation for @c std::ostream as it's likely this is the only one ever used. extern template std::ostream &TextView::stream_write(std::ostream &, const TextView &) const; -} // namespace ts +/** A transform view. + * + * @tparam X Transform functor type. + * @tparam V Source view type. + * + * A transform view acts like a view on the original source view @a V with each element transformed by + * @a X. + * + * This is used most commonly with @c std::string_view. For example, if the goal is to handle a + * piece of text as if it were lower case without changing the actual text, the following would + * make that possible. + * @code + * std:::string_view source; // original text. + * TransformView xv(&tolower, source); + * @endcode + * + * To avoid having to figure out the exact signature of the transform, the convenience function + * @c transform_view_of is provide. + * @code + * std::string_view source; // original text. + * auto xv = transform_view_of(&tolower, source); + * @endcode + */ +template class TransformView +{ + using self_type = TransformView; ///< Self reference type. + using iter = decltype(static_cast(nullptr)->begin()); + +public: + using transform_type = X; ///< Export transform functor type. + using source_view_type = V; ///< Export source view type. + using source_value_type = decltype(**static_cast(nullptr)); + /// Result type of calling the transform on an element of the source view. + using value_type = typename std::invoke_result::type; + + /** Construct a transform view using transform @a xf on source view @a v. + * + * @param xf Transform instance. + * @param v Source view. + */ + TransformView(transform_type &&xf, source_view_type const &v); + + /** Construct a transform view using transform @a xf on source view @a v. + * + * @param xf Transform instance. + * @param v Source view. + */ + TransformView(transform_type const &xf, source_view_type const &v); + + /// Copy constructor. + TransformView(self_type const &that) = default; + /// Move constructor. + TransformView(self_type &&that) = default; + + /// Copy assignment. + self_type &operator=(self_type const &that) = default; + /// Move assignment. + self_type &operator=(self_type &&that) = default; + + /// Equality. + bool operator==(self_type const &that) const; + /// Inequality. + bool operator!=(self_type const &that) const; + + /// Get the current element. + value_type operator*() const; + /// Move to next element. + self_type &operator++(); + /// Move to next element. + self_type operator++(int); + + /// Check if view is empty. + bool empty() const; + /// Check if bool is not empty. + explicit operator bool() const; + +protected: + transform_type _xf; + iter _spot; + iter _limit; +}; + +template +TransformView::TransformView(transform_type &&xf, source_view_type const &v) : _xf(xf), _spot(v.begin()), _limit(v.end()) +{ +} + +template +TransformView::TransformView(transform_type const &xf, source_view_type const &v) : _xf(xf), _spot(v.begin()), _limit(v.end()) +{ +} + +template auto TransformView::operator*() const -> value_type +{ + return _xf(*_spot); +} + +template +auto +TransformView::operator++() -> self_type & +{ + ++_spot; + return *this; +} + +template +auto +TransformView::operator++(int) -> self_type +{ + self_type zret{*this}; + ++_spot; + return zret; +} + +template +bool +TransformView::empty() const +{ + return _spot == _limit; +} + +template TransformView::operator bool() const +{ + return _spot != _limit; +} + +template +bool +TransformView::operator==(self_type const &that) const +{ + return _spot == that._spot && _limit == that._limit; +} + +template +bool +TransformView::operator!=(self_type const &that) const +{ + return _spot != that._spot || _limit != that._limit; +} + +template +TransformView +transform_view_of(X const &xf, V const &v) +{ + return TransformView(xf, v); +} + +// Specialization for identity transform. +template class TransformView +{ + using self_type = TransformView; ///< Self reference type. + using iter = decltype(static_cast(nullptr)->begin()); + +public: + using source_view_type = V; ///< Export source view type. + using source_value_type = decltype(**static_cast(nullptr)); + /// Result type of calling the transform on an element of the source view. + using value_type = source_value_type; + + /** Construct identity transform view from @a v. + * + * @param v Source view. + */ + TransformView(source_view_type const &v) : _spot(v.begin()), _limit(v.end()) {} + + /// Copy constructor. + TransformView(self_type const &that) = default; + /// Move constructor. + TransformView(self_type &&that) = default; + + /// Copy assignment. + self_type &operator=(self_type const &that) = default; + /// Move assignment. + self_type &operator=(self_type &&that) = default; + + /// Equality. + bool operator==(self_type const &that) const; + /// Inequality. + bool operator!=(self_type const &that) const; + + /// Get the current element. + value_type operator*() const { return *_spot; } + /// Move to next element. + self_type & + operator++() + { + ++_spot; + return *this; + } + /// Move to next element. + self_type + operator++(int) + { + auto zret{*this}; + ++*this; + return zret; + } + + /// Check if view is empty. + bool + empty() const + { + return _spot == _limit; + } + /// Check if bool is not empty. + explicit operator bool() const { return _spot != _limit; } + +protected: + iter _spot; + iter _limit; +}; + +template +TransformView +transform_view_of(V const &v) +{ + return TransformView(v); +} + +// Avoid complaints about no operator for cross type comparisons - just return false. If the +// types are the same the class method will be used. +template +bool +operator==(TransformView const &, TransformView const &) +{ + return false; +} + +template +bool +operator!=(TransformView const &, TransformView const &) +{ + return false; +} + +}; // namespace ts namespace std { @@ -1187,6 +1423,13 @@ template <> struct iterator_traits { using iterator_category = forward_iterator_tag; }; +template struct iterator_traits> { + using value_type = typename ts::TransformView::value_type; + using pointer_type = const value_type *; + using reference_type = const value_type &; + using difference_type = ssize_t; + using iterator_category = forward_iterator_tag; +}; } // namespace std // @c constexpr literal constructor for @c std::string_view diff --git a/iocore/hostdb/I_HostDBProcessor.h b/iocore/hostdb/I_HostDBProcessor.h index 3c4c64263cd..761b72cd403 100644 --- a/iocore/hostdb/I_HostDBProcessor.h +++ b/iocore/hostdb/I_HostDBProcessor.h @@ -23,7 +23,8 @@ #pragma once -#include "tscore/HashFNV.h" +#include +#include "tscpp/util/HashFNV.h" #include "tscore/ink_time.h" #include "tscore/CryptoHash.h" #include "tscore/ink_align.h" @@ -68,10 +69,7 @@ makeHostHash(const char *string) ink_assert(string && *string); if (string && *string) { - ATSHash32FNV1a fnv; - fnv.update(string, strlen(string), ATSHash::nocase()); - fnv.final(); - return fnv.get(); + return ts::Hash32FNV1a().hash_immediate(ts::transform_view_of(&tolower, std::string_view{string})); } return 0; diff --git a/mgmt/api/Makefile.am b/mgmt/api/Makefile.am index ae9fa950e7c..eff6c60f244 100644 --- a/mgmt/api/Makefile.am +++ b/mgmt/api/Makefile.am @@ -65,12 +65,12 @@ libtsmgmt_la_SOURCES = \ libmgmtapilocal_la_LIBADD = \ libmgmtapi.la \ + $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/src/tscore/libtscore.la libtsmgmt_la_LDFLAGS = -no-undefined -version-info @TS_LIBTOOL_VERSION@ libtsmgmt_la_LIBADD = @LIBOBJS@ \ libmgmtapi.la \ - $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/mgmt/utils/libutils_p.la if BUILD_TESTS @@ -78,11 +78,8 @@ traffic_api_cli_remote_SOURCES = APITestCliRemote.cc endif traffic_api_cli_remote_LDADD = \ - $(top_builddir)/src/tscpp/util/libtscpputil.la \ libtsmgmt.la \ - $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/src/tscore/libtscore.la \ - $(top_builddir)/src/tscpp/util/libtscpputil.la \ @LIBTCL@ @OPENSSL_LIBS@ clang-tidy-local: $(DIST_SOURCES) diff --git a/proxy/ParentConsistentHash.cc b/proxy/ParentConsistentHash.cc index b7466ca5869..b31dce42be4 100644 --- a/proxy/ParentConsistentHash.cc +++ b/proxy/ParentConsistentHash.cc @@ -20,8 +20,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include "HostStatus.h" #include "ParentConsistentHash.h" +#include "HostStatus.h" ParentConsistentHash::ParentConsistentHash(ParentRecord *parent_record) { @@ -37,7 +37,7 @@ ParentConsistentHash::ParentConsistentHash(ParentRecord *parent_record) chash[PRIMARY] = new ATSConsistentHash(); for (i = 0; i < parent_record->num_parents; i++) { - chash[PRIMARY]->insert(&(parent_record->parents[i]), parent_record->parents[i].weight, (ATSHash64 *)&hash[PRIMARY]); + chash[PRIMARY]->insert(&(parent_record->parents[i]), parent_record->parents[i].weight, (ts::Hash64Functor *)&hash[PRIMARY]); } if (parent_record->num_secondary_parents > 0) { @@ -46,7 +46,7 @@ ParentConsistentHash::ParentConsistentHash(ParentRecord *parent_record) for (i = 0; i < parent_record->num_secondary_parents; i++) { chash[SECONDARY]->insert(&(parent_record->secondary_parents[i]), parent_record->secondary_parents[i].weight, - (ATSHash64 *)&hash[SECONDARY]); + (ts::Hash64Functor *)&hash[SECONDARY]); } } else { chash[SECONDARY] = nullptr; @@ -62,7 +62,7 @@ ParentConsistentHash::~ParentConsistentHash() } uint64_t -ParentConsistentHash::getPathHash(HttpRequestData *hrdata, ATSHash64 *h) +ParentConsistentHash::getPathHash(HttpRequestData *hrdata, ts::Hash64Functor *h) { const char *url_string_ref = nullptr; int len; @@ -77,26 +77,24 @@ ParentConsistentHash::getPathHash(HttpRequestData *hrdata, ATSHash64 *h) if (url_string_ref && len > 0) { // Print the over-ride URL Debug("parent_select", "Using Over-Ride String='%.*s'.", len, url_string_ref); - h->update(url_string_ref, len); - h->final(); - return h->get(); + return h->update(std::string_view(url_string_ref, len)).final().get(); } } } // Always hash on '/' because paths returned by ATS are always stripped of it - h->update("/", 1); + h->update("/"_sv); url_string_ref = url->path_get(&len); if (url_string_ref) { - h->update(url_string_ref, len); + h->update(std::string_view(url_string_ref, len)); } if (!ignore_query) { url_string_ref = url->query_get(&len); if (url_string_ref) { - h->update("?", 1); - h->update(url_string_ref, len); + h->update("?"_sv); + h->update(std::string_view(url_string_ref, len)); } } @@ -108,7 +106,7 @@ ParentConsistentHash::getPathHash(HttpRequestData *hrdata, ATSHash64 *h) // Helper function to abstract calling ATSConsistentHash lookup_by_hashval() vs lookup(). static pRecord * chash_lookup(ATSConsistentHash *fhash, uint64_t path_hash, ATSConsistentHashIter *chashIter, bool *wrap_around, - ATSHash64Sip24 *hash, bool *chash_init) + ts::Hash64Sip24 *hash, bool *chash_init) { pRecord *prtmp; @@ -125,7 +123,7 @@ void ParentConsistentHash::selectParent(bool first_call, ParentResult *result, RequestData *rdata, unsigned int fail_threshold, unsigned int retry_time) { - ATSHash64Sip24 hash; + ts::Hash64Sip24 hash; ATSConsistentHash *fhash; HttpRequestData *request_info = static_cast(rdata); bool firstCall = first_call; @@ -184,7 +182,7 @@ ParentConsistentHash::selectParent(bool first_call, ParentResult *result, Reques } // Do the initial parent look-up. - path_hash = getPathHash(request_info, (ATSHash64 *)&hash); + path_hash = getPathHash(request_info, (ts::Hash64Functor *)&hash); fhash = chash[last_lookup]; do { // search until we've selected a different parent if !firstCall prtmp = (pRecord *)chash_lookup(fhash, path_hash, &result->chashIter[last_lookup], &wrap_around[last_lookup], &hash, diff --git a/proxy/ParentConsistentHash.h b/proxy/ParentConsistentHash.h index 3a8ee582789..14c962d9645 100644 --- a/proxy/ParentConsistentHash.h +++ b/proxy/ParentConsistentHash.h @@ -29,7 +29,7 @@ #pragma once -#include "tscore/HashSip.h" +#include "tscpp/util/HashSip.h" #include "ParentSelection.h" // @@ -40,7 +40,7 @@ class ParentConsistentHash : public ParentSelectionStrategy { // there are two hashes PRIMARY parents // and SECONDARY parents. - ATSHash64Sip24 hash[2]; + ts::Hash64Sip24 hash[2]; ATSConsistentHash *chash[2]; pRecord *parents[2]; bool foundParents[2][MAX_PARENTS]; @@ -57,7 +57,7 @@ class ParentConsistentHash : public ParentSelectionStrategy { return parents[result->last_lookup]; } - uint64_t getPathHash(HttpRequestData *hrdata, ATSHash64 *h); + uint64_t getPathHash(HttpRequestData *hrdata, ts::Hash64Functor *h); void selectParent(bool firstCall, ParentResult *result, RequestData *rdata, unsigned int fail_threshold, unsigned int retry_time) override; void markParentDown(ParentResult *result, unsigned int fail_threshold, unsigned int retry_time); diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc index df3f368ee95..72fee498370 100644 --- a/proxy/ParentSelection.cc +++ b/proxy/ParentSelection.cc @@ -20,6 +20,8 @@ See the License for the specific language governing permissions and limitations under the License. */ + +#include "tscpp/util/HashSip.h" #include "P_EventSystem.h" #include "ParentSelection.h" #include "ParentConsistentHash.h" diff --git a/proxy/hdrs/HdrToken.cc b/proxy/hdrs/HdrToken.cc index 55fe5200a6f..b4be7f9a437 100644 --- a/proxy/hdrs/HdrToken.cc +++ b/proxy/hdrs/HdrToken.cc @@ -22,7 +22,7 @@ */ #include "tscore/ink_platform.h" -#include "tscore/HashFNV.h" +#include "tscpp/util/HashFNV.h" #include "tscore/Diags.h" #include "tscore/ink_memory.h" #include @@ -282,12 +282,9 @@ hash_to_slot(uint32_t hash) } inline uint32_t -hdrtoken_hash(const unsigned char *string, unsigned int length) +hdrtoken_hash(const char *string, unsigned int length) { - ATSHash32FNV1a fnv; - fnv.update(string, length, ATSHash::nocase()); - fnv.final(); - return fnv.get(); + return ts::Hash32FNV1a().hash_immediate(ts::transform_view_of(&toupper, std::string_view(string, length))); } /*------------------------------------------------------------------------- @@ -375,9 +372,9 @@ hdrtoken_hash_init() for (i = 0; i < (int)SIZEOF(_hdrtoken_commonly_tokenized_strs); i++) { // convert the common string to the well-known token - unsigned const char *wks; - int wks_idx = hdrtoken_tokenize_dfa(_hdrtoken_commonly_tokenized_strs[i], (int)strlen(_hdrtoken_commonly_tokenized_strs[i]), - (const char **)&wks); + const char *wks; + int wks_idx = + hdrtoken_tokenize_dfa(_hdrtoken_commonly_tokenized_strs[i], int(strlen(_hdrtoken_commonly_tokenized_strs[i])), &wks); ink_release_assert(wks_idx >= 0); uint32_t hash = hdrtoken_hash(wks, hdrtoken_str_lengths[wks_idx]); @@ -558,7 +555,7 @@ hdrtoken_tokenize(const char *string, int string_len, const char **wks_string_ou return wks_idx; } - uint32_t hash = hdrtoken_hash((const unsigned char *)string, (unsigned int)string_len); + uint32_t hash = hdrtoken_hash(string, string_len); uint32_t slot = hash_to_slot(hash); bucket = &(hdrtoken_hash_table[slot]); diff --git a/src/traffic_logstats/logstats.cc b/src/traffic_logstats/logstats.cc index 72885e1bc65..b2a86b740f4 100644 --- a/src/traffic_logstats/logstats.cc +++ b/src/traffic_logstats/logstats.cc @@ -26,7 +26,7 @@ #include "tscore/ink_file.h" #include "tscore/I_Layout.h" #include "tscore/I_Version.h" -#include "tscore/HashFNV.h" +#include "tscpp/util/HashFNV.h" #include "tscore/ink_args.h" #include "tscore/MatcherUtils.h" #include "tscore/runroot.h" @@ -325,14 +325,13 @@ struct hash_fnv32 { inline uint32_t operator()(const char *s) const { - ATSHash32FNV1a fnv; + ts::Hash32FNV1a fnv; if (s) { - fnv.update(s, strlen(s)); + fnv.update(s); } - fnv.final(); - return fnv.get(); + return fnv.final().get(); } }; diff --git a/src/tscore/ConsistentHash.cc b/src/tscore/ConsistentHash.cc index 3d060d8cbd1..001634acb78 100644 --- a/src/tscore/ConsistentHash.cc +++ b/src/tscore/ConsistentHash.cc @@ -33,21 +33,21 @@ operator<<(std::ostream &os, ATSConsistentHashNode &thing) return os << thing.name; } -ATSConsistentHash::ATSConsistentHash(int r, ATSHash64 *h) : replicas(r), hash(h) {} +ATSConsistentHash::ATSConsistentHash(int r, ts::Hash64Functor *h) : replicas(r), hash(h) {} void -ATSConsistentHash::insert(ATSConsistentHashNode *node, float weight, ATSHash64 *h) +ATSConsistentHash::insert(ATSConsistentHashNode *node, float weight, ts::Hash64Functor *h) { int i; char numstr[256]; - ATSHash64 *thash; + ts::Hash64Functor *thash; std::ostringstream string_stream; std::string std_string; if (h) { thash = h; } else if (hash) { - thash = hash; + thash = hash.get(); } else { return; } @@ -57,26 +57,24 @@ ATSConsistentHash::insert(ATSConsistentHashNode *node, float weight, ATSHash64 * for (i = 0; i < (int)roundf(replicas * weight); i++) { snprintf(numstr, 256, "%d-", i); - thash->update(numstr, strlen(numstr)); - thash->update(std_string.c_str(), strlen(std_string.c_str())); - thash->final(); + thash->update(numstr).update(std_string).final(); NodeMap.insert(std::pair(thash->get(), node)); thash->clear(); } } ATSConsistentHashNode * -ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, ATSHash64 *h) +ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, ts::Hash64Functor *h) { uint64_t url_hash; ATSConsistentHashIter NodeMapIterUp, *iter; - ATSHash64 *thash; + ts::Hash64Functor *thash; bool *wptr, wrapped = false; if (h) { thash = h; } else if (hash) { - thash = hash; + thash = hash.get(); } else { return nullptr; } @@ -94,7 +92,7 @@ ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, AT } if (url) { - thash->update(url, strlen(url)); + thash->update(url); thash->final(); url_hash = thash->get(); thash->clear(); @@ -122,17 +120,17 @@ ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, AT } ATSConsistentHashNode * -ATSConsistentHash::lookup_available(const char *url, ATSConsistentHashIter *i, bool *w, ATSHash64 *h) +ATSConsistentHash::lookup_available(const char *url, ATSConsistentHashIter *i, bool *w, ts::Hash64Functor *h) { uint64_t url_hash; ATSConsistentHashIter NodeMapIterUp, *iter; - ATSHash64 *thash; + ts::Hash64Functor *thash; bool *wptr, wrapped = false; if (h) { thash = h; } else if (hash) { - thash = hash; + thash = hash.get(); } else { return nullptr; } @@ -150,7 +148,7 @@ ATSConsistentHash::lookup_available(const char *url, ATSConsistentHashIter *i, b } if (url) { - thash->update(url, strlen(url)); + thash->update(url); thash->final(); url_hash = thash->get(); thash->clear(); @@ -205,9 +203,4 @@ ATSConsistentHash::lookup_by_hashval(uint64_t hashval, ATSConsistentHashIter *i, return (*iter)->second; } -ATSConsistentHash::~ATSConsistentHash() -{ - if (hash) { - delete hash; - } -} +ATSConsistentHash::~ATSConsistentHash() {} diff --git a/src/tscore/HashFNV.cc b/src/tscore/HashFNV.cc deleted file mode 100644 index b060ab4205a..00000000000 --- a/src/tscore/HashFNV.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - This algorithm is in the public domain. This code was - derived from code in the public domain. - - http://www.isthe.com/chongo/tech/comp/fnv/ - - Currently implemented FNV-1a 32bit and FNV-1a 64bit - */ - -#include "tscore/HashFNV.h" - -static const uint32_t FNV_INIT_32 = 0x811c9dc5u; -static const uint64_t FNV_INIT_64 = 0xcbf29ce484222325ull; - -// FNV-1a 64bit -ATSHash32FNV1a::ATSHash32FNV1a() -{ - this->clear(); -} - -void -ATSHash32FNV1a::final() -{ -} - -uint32_t -ATSHash32FNV1a::get() const -{ - return hval; -} - -void -ATSHash32FNV1a::clear() -{ - hval = FNV_INIT_32; -} - -// FNV-1a 64bit -ATSHash64FNV1a::ATSHash64FNV1a() -{ - this->clear(); -} -void -ATSHash64FNV1a::final() -{ -} - -uint64_t -ATSHash64FNV1a::get() const -{ - return hval; -} - -void -ATSHash64FNV1a::clear() -{ - hval = FNV_INIT_64; -} diff --git a/src/tscore/HashMD5.cc b/src/tscore/HashMD5.cc index 7f1dedc1b80..770a1f6b5a1 100644 --- a/src/tscore/HashMD5.cc +++ b/src/tscore/HashMD5.cc @@ -23,66 +23,74 @@ #include "tscore/ink_config.h" #include "tscore/HashMD5.h" -ATSHashMD5::ATSHashMD5() : md_len(0), finalized(false) +namespace ts +{ +HashMD5::HashMD5() : ctx(EVP_MD_CTX_new()) { - ctx = EVP_MD_CTX_new(); int ret = EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); ink_assert(ret == 1); } -void -ATSHashMD5::update(const void *data, size_t len) +HashMD5 & +HashMD5::update(std::string_view const &data) { if (!finalized) { - int ret = EVP_DigestUpdate(ctx, data, len); + int ret = EVP_DigestUpdate(ctx, data.data(), data.size()); ink_assert(ret == 1); } + return *this; } -void -ATSHashMD5::final() +HashMD5 & +HashMD5::final() { if (!finalized) { int ret = EVP_DigestFinal_ex(ctx, md_value, &md_len); ink_assert(ret == 1); finalized = true; } + return *this; } -const void * -ATSHashMD5::get() const +bool +HashMD5::get(MemSpan dst) const { - if (finalized) { - return (void *)md_value; + bool zret = true; + if (finalized && dst.size() > this->size()) { + memcpy(dst.data(), md_value, this->size()); } else { - return nullptr; + zret = false; } + return zret; } size_t -ATSHashMD5::size() const +HashMD5::size() const { return EVP_MD_CTX_size(ctx); } -void -ATSHashMD5::clear() +HashMD5 & +HashMD5::clear() { + int ret = 1; #ifndef OPENSSL_IS_BORINGSSL - int ret = EVP_MD_CTX_reset(ctx); + ret = EVP_MD_CTX_reset(ctx); + ink_assert(ret == 1); #else // OpenSSL's EVP_MD_CTX_reset always returns 1 - int ret = 1; EVP_MD_CTX_reset(ctx); #endif - ink_assert(ret == 1); ret = EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); ink_assert(ret == 1); md_len = 0; finalized = false; + return *this; } -ATSHashMD5::~ATSHashMD5() +HashMD5::~HashMD5() { EVP_MD_CTX_free(ctx); } + +} // namespace ts diff --git a/src/tscore/Makefile.am b/src/tscore/Makefile.am index 367cf8e900f..8fdffc6672f 100644 --- a/src/tscore/Makefile.am +++ b/src/tscore/Makefile.am @@ -76,14 +76,8 @@ libtscore_la_SOURCES = \ Extendible.h \ fastlz.c \ fastlz.h \ - Hash.cc \ - HashFNV.cc \ - HashFNV.h \ - Hash.h \ HashMD5.cc \ HashMD5.h \ - HashSip.cc \ - HashSip.h \ History.h \ HostLookup.cc \ HostLookup.h \ @@ -229,7 +223,7 @@ ParseRulesCType: CompileParseRules mkdfa_SOURCES = mkdfa.c test_atomic_SOURCES = test_atomic.cc -test_atomic_LDADD = libtscore.la $(top_builddir)/src/tscpp/util/libtscpputil.la @LIBTCL@ @LIBPCRE@ +test_atomic_LDADD = libtscore.la @LIBTCL@ @LIBPCRE@ test_freelist_SOURCES = test_freelist.cc test_freelist_LDADD = libtscore.la $(top_builddir)/src/tscpp/util/libtscpputil.la @LIBTCL@ @LIBPCRE@ diff --git a/src/tscore/Hash.cc b/src/tscpp/util/Hash.cc similarity index 65% rename from src/tscore/Hash.cc rename to src/tscpp/util/Hash.cc index 5a34377b133..31df14c47dc 100644 --- a/src/tscore/Hash.cc +++ b/src/tscpp/util/Hash.cc @@ -19,32 +19,30 @@ limitations under the License. */ -#include "tscore/Hash.h" -#include - -ATSHashBase::~ATSHashBase() {} +#include "tscpp/util/Hash.h" bool -ATSHash::operator==(const ATSHash &other) const +ts::Hash32Functor::get(MemSpan dst) const { - if (this->size() != other.size()) { - return false; - } - if (memcmp(this->get(), other.get(), this->size()) == 0) { - return true; + bool zret = true; + if (dst.size() >= this->size()) { + auto v{this->get()}; + memcpy(dst.data(), &v, sizeof(v)); } else { - return false; + zret = false; } + return zret; } bool -ATSHash32::operator==(const ATSHash32 &other) const -{ - return this->get() == other.get(); -} - -bool -ATSHash64::operator==(const ATSHash64 &other) const +ts::Hash64Functor::get(MemSpan dst) const { - return this->get() == other.get(); + bool zret = true; + if (dst.size() >= this->size()) { + auto v{this->get()}; + memcpy(dst.data(), &v, sizeof(v)); + } else { + zret = false; + } + return zret; } diff --git a/src/tscore/HashSip.cc b/src/tscpp/util/HashSip.cc similarity index 68% rename from src/tscore/HashSip.cc rename to src/tscpp/util/HashSip.cc index bc0db100556..b5a03fd6fd3 100644 --- a/src/tscore/HashSip.cc +++ b/src/tscpp/util/HashSip.cc @@ -8,16 +8,24 @@ Based off of implementation: */ -#include "tscore/HashSip.h" +#include "tscpp/util/HashSip.h" #include using namespace std; -#define SIP_BLOCK_SIZE 8 - -#define ROTL64(a, b) (((a) << (b)) | ((a) >> (64 - b))) +namespace +{ +inline uint64_t +ROTL64(uint64_t a, uint64_t b) +{ + return ((a) << (b)) | ((a) >> (64 - b)); +} -#define U8TO64_LE(p) *(const uint64_t *)(p) +inline uint64_t +U8TO64_LE(unsigned char const *p) +{ + return *reinterpret_cast(p); +} #define SIPCOMPRESS(x0, x1, x2, x3) \ x0 += x1; \ @@ -35,39 +43,43 @@ using namespace std; x3 ^= x0; \ x2 = ROTL64(x2, 32); -ATSHash64Sip24::ATSHash64Sip24() +} // namespace + +namespace ts +{ +Hash64Sip24::Hash64Sip24() { this->clear(); } -ATSHash64Sip24::ATSHash64Sip24(const unsigned char key[16]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0))) +Hash64Sip24::Hash64Sip24(const unsigned char key[KEY_SIZE]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0))) { this->clear(); } -ATSHash64Sip24::ATSHash64Sip24(uint64_t key0, uint64_t key1) : k0(key0), k1(key1) +Hash64Sip24::Hash64Sip24(uint64_t key0, uint64_t key1) : k0(key0), k1(key1) { this->clear(); } -void -ATSHash64Sip24::update(const void *data, size_t len) +Hash64Sip24 & +Hash64Sip24::update(std::string_view const &data) { size_t i, blocks; - unsigned char *m; uint64_t mi; uint8_t block_off = 0; if (!finalized) { - m = (unsigned char *)data; + auto len = data.size(); + auto m = reinterpret_cast(data.data()); total_len += len; - if (len + block_buffer_len < SIP_BLOCK_SIZE) { + if (len + block_buffer_len < BLOCK_SIZE) { memcpy(block_buffer + block_buffer_len, m, len); block_buffer_len += len; } else { if (block_buffer_len > 0) { - block_off = SIP_BLOCK_SIZE - block_buffer_len; + block_off = BLOCK_SIZE - block_buffer_len; memcpy(block_buffer + block_buffer_len, m, block_off); mi = U8TO64_LE(block_buffer); @@ -77,7 +89,7 @@ ATSHash64Sip24::update(const void *data, size_t len) v0 ^= mi; } - for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1)); i < blocks; i += SIP_BLOCK_SIZE) { + for (i = block_off, blocks = ((len - block_off) & ~(BLOCK_SIZE - 1)); i < blocks; i += BLOCK_SIZE) { mi = U8TO64_LE(m + i); v3 ^= mi; SIPCOMPRESS(v0, v1, v2, v3); @@ -85,14 +97,15 @@ ATSHash64Sip24::update(const void *data, size_t len) v0 ^= mi; } - block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1); + block_buffer_len = (len - block_off) & (BLOCK_SIZE - 1); memcpy(block_buffer, m + block_off + blocks, block_buffer_len); } } + return *this; } -void -ATSHash64Sip24::final() +Hash64Sip24 & +Hash64Sip24::final() { uint64_t last7; int i; @@ -116,20 +129,17 @@ ATSHash64Sip24::final() hfinal = v0 ^ v1 ^ v2 ^ v3; finalized = true; } + return *this; } uint64_t -ATSHash64Sip24::get() const +Hash64Sip24::get() const { - if (finalized) { - return hfinal; - } else { - return 0; - } + return finalized ? hfinal : 0; } -void -ATSHash64Sip24::clear() +Hash64Sip24 & +Hash64Sip24::clear() { v0 = k0 ^ 0x736f6d6570736575ull; v1 = k1 ^ 0x646f72616e646f6dull; @@ -138,4 +148,7 @@ ATSHash64Sip24::clear() finalized = false; total_len = 0; block_buffer_len = 0; + return *this; } + +} // namespace ts diff --git a/src/tscpp/util/Makefile.am b/src/tscpp/util/Makefile.am index 8f0f4428aa8..002bcd0d0d1 100644 --- a/src/tscpp/util/Makefile.am +++ b/src/tscpp/util/Makefile.am @@ -28,6 +28,11 @@ libtscpputil_la_LDFLAGS = -no-undefined -version-info @TS_LIBTOOL_VERSION@ libtscpputil_la_SOURCES = \ IntrusiveDList.h \ + Hash.cc \ + Hash.h \ + HashFNV.h \ + HashSip.cc \ + HashSip.h \ PostScript.h \ TextView.h TextView.cc diff --git a/src/tscpp/util/unit_tests/test_TextView.cc b/src/tscpp/util/unit_tests/test_TextView.cc index d9ce540b1c8..de9cd8a2fd1 100644 --- a/src/tscpp/util/unit_tests/test_TextView.cc +++ b/src/tscpp/util/unit_tests/test_TextView.cc @@ -315,3 +315,39 @@ TEST_CASE("TextView Conversions", "[libts][TextView]") REQUIRE(25 == svtoi(n3)); REQUIRE(31 == svtoi(n3, nullptr, 10)); } + +TEST_CASE("TransformView", "[libts][TransformView]") +{ + std::string_view source{"Evil Dave Rulz"}; + ts::TransformView xv1(&tolower, source); + // clang and gnu differ on the type of tolower wrt "noexcept". This makes xv1 a different type + // from xv2 (or not) depending on the compiler. Therefore we need xv3 to test the equality operator. + auto xv2 = ts::transform_view_of(&tolower, source); + auto xv3 = ts::transform_view_of(&tolower, source); + TextView tv{source}; + + bool match_p = true; + while (xv1) { + if (*xv1 != tolower(*tv)) { + match_p = false; + break; + } + ++xv1; + ++tv; + } + REQUIRE(match_p); + + REQUIRE(xv2 == xv3); + tv = source; + match_p = true; + while (xv2) { + if (*xv2 != tolower(*tv)) { + match_p = false; + break; + } + ++xv2; + ++tv; + } + REQUIRE(match_p); + REQUIRE(xv2 != xv3); +};