diff --git a/cpp/arcticdb/CMakeLists.txt b/cpp/arcticdb/CMakeLists.txt index abb6d9eadfb..f716edd388d 100644 --- a/cpp/arcticdb/CMakeLists.txt +++ b/cpp/arcticdb/CMakeLists.txt @@ -464,7 +464,7 @@ set(arcticdb_srcs version/version_utils.cpp version/symbol_list.cpp version/version_map_batch_methods.cpp -) + util/enumerate.hpp) if(${ARCTICDB_INCLUDE_ROCKSDB}) list (APPEND arcticdb_srcs @@ -815,7 +815,7 @@ if(${TEST}) version/test/test_sorting_info_state_machine.cpp version/test/version_map_model.hpp storage/test/common.hpp - ) + util/test/test_enumerate.cpp) set(EXECUTABLE_PERMS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # 755 diff --git a/cpp/arcticdb/util/enumerate.hpp b/cpp/arcticdb/util/enumerate.hpp new file mode 100644 index 00000000000..ce9477ee1df --- /dev/null +++ b/cpp/arcticdb/util/enumerate.hpp @@ -0,0 +1,114 @@ +#pragma once + +// An internal implementation of folly's enumerate: https://github.com/facebook/folly/blob/main/folly/container/Enumerate.h + +#include +#include + +#include + +namespace arcticdb { + +namespace detail { + +template +struct MakeConst { + using type = const T; +}; +template +struct MakeConst { + using type = const T&; +}; +template +struct MakeConst { + using type = const T*; +}; + +template +class Enumerator { +public: + constexpr explicit Enumerator(Iterator it) : it_(std::move(it)) {} + + class Proxy { + public: + using difference_type = ssize_t; + using value_type = typename std::iterator_traits::value_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + using iterator_category = std::input_iterator_tag; + + ARCTICDB_FORCE_INLINE constexpr explicit Proxy(const Enumerator& enumerator) + : index(enumerator.idx_), element(*enumerator.it_) {} + + ARCTICDB_FORCE_INLINE constexpr reference operator*() { return element; } + ARCTICDB_FORCE_INLINE constexpr pointer operator->() { + return std::addressof(element); + } + + ARCTICDB_FORCE_INLINE constexpr typename MakeConst::type + operator*() const { + return element; + } + ARCTICDB_FORCE_INLINE constexpr typename MakeConst::type operator->() + const { + return std::addressof(element); + } + + public: + const size_t index; + reference element; + }; + + ARCTICDB_FORCE_INLINE constexpr Proxy operator*() const { return Proxy(*this); } + + ARCTICDB_FORCE_INLINE constexpr Enumerator& operator++() { + ++it_; + ++idx_; + return *this; + } + + template + ARCTICDB_FORCE_INLINE constexpr bool operator==( + const Enumerator& rhs) const { + return it_ == rhs.it_; + } + + template + ARCTICDB_FORCE_INLINE constexpr bool operator!=( + const Enumerator& rhs) const { + return !(it_ == rhs.it_); + } + +private: + template + friend class Enumerator; + + Iterator it_; + size_t idx_ = 0; +}; + +template +class RangeEnumerator { + RangeType r_; + using BeginIteratorType = decltype(std::declval().begin()); + using EndIteratorType = decltype(std::declval().end()); + +public: + constexpr explicit RangeEnumerator(RangeType&& r) : r_(std::forward(r)) {} + + constexpr Enumerator begin() { + return Enumerator(r_.begin()); + } + constexpr Enumerator end() { + return Enumerator(r_.end()); + } +}; + +} // namespace detail + +template +constexpr detail::RangeEnumerator enumerate(RangeType&& r) { + return detail::RangeEnumerator(std::forward(r)); +} + +} // namespace arcticdb \ No newline at end of file diff --git a/cpp/arcticdb/util/preprocess.hpp b/cpp/arcticdb/util/preprocess.hpp index 416bd4e9242..6b879ac00b8 100644 --- a/cpp/arcticdb/util/preprocess.hpp +++ b/cpp/arcticdb/util/preprocess.hpp @@ -26,3 +26,9 @@ #define ARCTICDB_LIKELY #define ARCTICDB_UNLIKELY #endif + +#ifdef _MSC_VER +#define ARCTICDB_FORCE_INLINE __forceinline +#elif defined(__GNUC__) +#define ARCTICDB_FORCE_INLINE inline __attribute__((__always_inline__)) +#else \ No newline at end of file diff --git a/cpp/arcticdb/util/test/test_enumerate.cpp b/cpp/arcticdb/util/test/test_enumerate.cpp new file mode 100644 index 00000000000..88900a1c71c --- /dev/null +++ b/cpp/arcticdb/util/test/test_enumerate.cpp @@ -0,0 +1,14 @@ +#include +#include +#include + +TEST(Enumerate, Vector) { + std::vector vec = {1, 2, 3, 4}; + + using namespace arcticdb; + + for(auto&& [thing, index] : enumerate(vec)) { + arcticdb::log::version().info("{} : {}", thing, index); + } +} +