Unverified Commit 16f48056 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #865

Add byte and span replacements
parents b5a8c4bc c8ac82b3
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <cstdint>
#include <type_traits>
#include "caf/detail/type_traits.hpp"
#pragma once
namespace caf {
/// A C++11/14 drop-in replacement for C++17's `std::byte`.
enum class byte : uint8_t {};
template <class IntegerType,
class = detail::enable_if_tt<std::is_integral<IntegerType>>>
constexpr IntegerType to_integer(byte x) noexcept {
return static_cast<IntegerType>(x);
}
template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>>
constexpr byte& operator<<=(byte& x, IntegerType shift) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) << shift);
}
template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>>
constexpr byte operator<<(byte x, IntegerType shift) noexcept {
return static_cast<byte>(to_integer<uint8_t>(x) << shift);
}
template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>>
constexpr byte& operator>>=(byte& x, IntegerType shift) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) >> shift);
}
template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>>
constexpr byte operator>>(byte x, IntegerType shift) noexcept {
return static_cast<byte>(static_cast<unsigned char>(x) >> shift);
}
inline byte& operator|=(byte& x, byte y) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) | to_integer<uint8_t>(y));
}
constexpr byte operator|(byte x, byte y) noexcept {
return static_cast<byte>(to_integer<uint8_t>(x) | to_integer<uint8_t>(y));
}
inline byte& operator&=(byte& x, byte y) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) & to_integer<uint8_t>(y));
}
constexpr byte operator&(byte x, byte y) noexcept {
return static_cast<byte>(to_integer<uint8_t>(x) & to_integer<uint8_t>(y));
}
inline byte& operator^=(byte& x, byte y) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) ^ to_integer<uint8_t>(y));
}
constexpr byte operator^(byte x, byte y) noexcept {
return static_cast<byte>(to_integer<uint8_t>(x) ^ to_integer<uint8_t>(y));
}
constexpr byte operator~(byte x) noexcept {
return static_cast<byte>(~to_integer<uint8_t>(x));
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <array>
#include <type_traits>
#include "caf/byte.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
/// A C++11/14 drop-in replacement for C++20's `std::span` without support for
/// static extents.
template <class T>
class span {
public:
// -- member types -----------------------------------------------------------
using element_type = T;
using value_type = typename std::remove_cv<T>::type;
using index_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = T&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
// -- constructors, destructors, and assignment operators --------------------
constexpr span() noexcept : begin_(nullptr), size_(0) {
// nop
}
constexpr span(pointer ptr, size_t size) : begin_(ptr), size_(size) {
// nop
}
constexpr span(pointer first, pointer last)
: begin_(first), size_(static_cast<size_t>(last - first)) {
// nop
}
template <size_t Size>
constexpr span(element_type (&arr)[Size]) noexcept
: begin_(arr), size_(Size) {
// nop
}
template <class C,
class E = detail::enable_if_t<detail::has_data_member<C>::value>>
span(C& xs) noexcept : begin_(xs.data()), size_(xs.size()) {
// nop
}
constexpr span(const span&) noexcept = default;
span& operator=(const span&) noexcept = default;
// -- iterators --------------------------------------------------------------
constexpr iterator begin() const noexcept {
return begin_;
}
constexpr const_iterator cbegin() const noexcept {
return begin_;
}
constexpr iterator end() const noexcept {
return begin() + size_;
}
constexpr const_iterator cend() const noexcept {
return cbegin() + size_;
}
constexpr reverse_iterator rbegin() const noexcept {
return reverse_iterator{end()};
}
constexpr const_reverse_iterator crbegin() const noexcept {
return const_reverse_iterator{end()};
}
constexpr reverse_iterator rend() const noexcept {
return reverse_iterator{begin()};
}
constexpr const_reverse_iterator crend() const noexcept {
return const_reverse_iterator{begin()};
}
// -- element access ---------------------------------------------------------
constexpr reference operator[](size_t index) const noexcept {
return begin_[index];
}
constexpr reference front() const noexcept {
return *begin_;
}
constexpr reference back() const noexcept {
return (*this)[size_ - 1];
}
// -- properties -------------------------------------------------------------
constexpr size_t size() const noexcept {
return size_;
}
constexpr size_t size_bytes() const noexcept {
return size_ * sizeof(element_type);
}
constexpr bool empty() const noexcept {
return size_ == 0;
}
constexpr pointer data() const noexcept {
return begin_;
}
// -- subviews ---------------------------------------------------------------
constexpr span subspan(size_t offset, size_t num_bytes) const {
return {begin_ + offset, num_bytes};
}
constexpr span first(size_t num_bytes) const {
return {begin_, num_bytes};
}
constexpr span last(size_t num_bytes) const {
return subspan(size_ - num_bytes, num_bytes);
}
private:
// -- member variables -------------------------------------------------------
/// Points to the first element in the contiguous memory block.
pointer begin_;
/// Stores the number of elements in the contiguous memory block.
size_t size_;
};
template <class T>
auto begin(const span<T>& xs) -> decltype(xs.begin()) {
return xs.begin();
}
template <class T>
auto cbegin(const span<T>& xs) -> decltype(xs.cbegin()) {
return xs.cbegin();
}
template <class T>
auto end(const span<T>& xs) -> decltype(xs.end()) {
return xs.end();
}
template <class T>
auto cend(const span<T>& xs) -> decltype(xs.cend()) {
return xs.cend();
}
template <class T>
span<const byte> as_bytes(span<T> xs) {
return {reinterpret_cast<const byte*>(xs.data()), xs.size_bytes()};
}
template <class T>
span<byte> as_writable_bytes(span<T> xs) {
return {reinterpret_cast<byte*>(xs.data()), xs.size_bytes()};
}
/// Convenience function to make using `caf::span` more convenient without the
/// deduction guides.
template <class T>
auto make_span(T& xs) -> span<detail::decay_t<decltype(xs[0])>> {
return {xs.data(), xs.size()};
}
/// Convenience function to make using `caf::span` more convenient without the
/// deduction guides.
template <class T>
span<T> make_span(T* first, size_t size) {
return {first, size};
}
/// Convenience function to make using `caf::span` more convenient without the
/// deduction guides.
template <class T>
span<T> make_span(T* first, T* last) {
return {first, last};
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE byte
#include "caf/byte.hpp"
#include "caf/test/dsl.hpp"
#include <cstdint>
#include "caf/detail/parser/add_ascii.hpp"
using namespace caf;
namespace {
byte operator"" _b(const char* str, size_t n) {
size_t consumed = 0;
uint8_t result = 0;
for (size_t i = 0; i < n; ++i) {
if (str[i] != '\'') {
if (!detail::parser::add_ascii<2>(result, str[i]))
throw std::logic_error("invalid character or over-/underflow");
else
++consumed;
}
}
if (consumed != 8)
throw std::logic_error("too few digits, expected exactly 8");
return static_cast<byte>(result);
}
struct fixture {
fixture() {
// Sanity checks.
if ("0001'1100"_b != static_cast<byte>(0x1C))
CAF_FAIL("operator \"\"_b broken");
if ("1000'0001"_b != static_cast<byte>(0x81))
CAF_FAIL("operator \"\"_b broken");
}
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(byte_tests, fixture)
CAF_TEST(to integer) {
CAF_CHECK_EQUAL(to_integer<int>("0110'1001"_b), 0x69);
}
CAF_TEST(left shift) {
auto x = "0000'0001"_b;
x <<= 1;
CAF_CHECK_EQUAL(x, "0000'0010"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 1, "0000'0100"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 2, "0000'1000"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 3, "0001'0000"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 4, "0010'0000"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 5, "0100'0000"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 6, "1000'0000"_b);
CAF_CHECK_EQUAL("0000'0010"_b << 7, "0000'0000"_b);
}
CAF_TEST(right shift) {
auto x = "0100'0000"_b;
x >>= 1;
CAF_CHECK_EQUAL(x, "0010'0000"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 1, "0010'0000"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 2, "0001'0000"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 3, "0000'1000"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 4, "0000'0100"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 5, "0000'0010"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 6, "0000'0001"_b);
CAF_CHECK_EQUAL("0100'0000"_b >> 7, "0000'0000"_b);
}
CAF_TEST(bitwise or) {
auto x = "0001'1110"_b;
x |= "0111'1000"_b;
CAF_CHECK_EQUAL(x, "0111'1110"_b);
CAF_CHECK_EQUAL("0001'1110"_b | "0111'1000"_b, "0111'1110"_b);
}
CAF_TEST(bitwise and) {
auto x = "0001'1110"_b;
x &= "0111'1000"_b;
CAF_CHECK_EQUAL(x, "0001'1000"_b);
CAF_CHECK_EQUAL("0001'1110"_b & "0111'1000"_b, "0001'1000"_b);
}
CAF_TEST(bitwise xor) {
auto x = "0001'1110"_b;
x ^= "0111'1000"_b;
CAF_CHECK_EQUAL(x, "0110'0110"_b);
CAF_CHECK_EQUAL("0001'1110"_b ^ "0111'1000"_b, "0110'0110"_b);
}
CAF_TEST(bitwise not) {
CAF_CHECK_EQUAL(~"0111'1110"_b, "1000'0001"_b);
}
CAF_TEST_FIXTURE_SCOPE_END()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE span
#include "caf/span.hpp"
#include "caf/test/dsl.hpp"
#include <algorithm>
using namespace caf;
namespace {
using i8_list = std::vector<int8_t>;
using i16_list = std::vector<int16_t>;
template <class T, class U>
bool equal(const T& xs, const U& ys) {
return xs.size() == ys.size() && std::equal(xs.begin(), xs.end(), ys.begin());
}
struct fixture {
i8_list chars{'a', 'b', 'c', 'd', 'e', 'f'};
i8_list rchars{'f', 'e', 'd', 'c', 'b', 'a'};
i16_list shorts{1, 2, 4, 8, 16, 32, 64};
i16_list rshorts{64, 32, 16, 8, 4, 2, 1};
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(span_tests, fixture)
CAF_TEST(default construction) {
span<int> xs;
CAF_CHECK_EQUAL(xs.size(), 0u);
CAF_CHECK_EQUAL(xs.empty(), true);
CAF_CHECK_EQUAL(xs.data(), nullptr);
CAF_CHECK_EQUAL(xs.size_bytes(), 0u);
CAF_CHECK_EQUAL(xs.begin(), xs.end());
CAF_CHECK_EQUAL(xs.cbegin(), xs.cend());
CAF_CHECK_EQUAL(xs.rbegin(), xs.rend());
CAF_CHECK_EQUAL(xs.crbegin(), xs.crend());
CAF_CHECK_EQUAL(as_bytes(xs).size_bytes(), 0u);
CAF_CHECK_EQUAL(as_writable_bytes(xs).size_bytes(), 0u);
}
CAF_TEST(iterators) {
auto xs = make_span(chars);
CAF_CHECK(std::equal(xs.begin(), xs.end(), chars.begin()));
CAF_CHECK(std::equal(xs.rbegin(), xs.rend(), rchars.begin()));
auto ys = make_span(shorts);
CAF_CHECK(std::equal(ys.begin(), ys.end(), shorts.begin()));
CAF_CHECK(std::equal(ys.rbegin(), ys.rend(), rshorts.begin()));
}
CAF_TEST(subspans) {
auto xs = make_span(chars);
CAF_CHECK(equal(xs.first(6), xs));
CAF_CHECK(equal(xs.last(6), xs));
CAF_CHECK(equal(xs.subspan(0, 6), xs));
CAF_CHECK(equal(xs.first(3), i8_list({'a', 'b', 'c'})));
CAF_CHECK(equal(xs.last(3), i8_list({'d', 'e', 'f'})));
CAF_CHECK(equal(xs.subspan(2, 2), i8_list({'c', 'd'})));
}
CAF_TEST(free iterator functions) {
auto xs = make_span(chars);
CAF_CHECK_EQUAL(xs.begin(), begin(xs));
CAF_CHECK_EQUAL(xs.cbegin(), cbegin(xs));
CAF_CHECK_EQUAL(xs.end(), end(xs));
CAF_CHECK_EQUAL(xs.cend(), cend(xs));
}
CAF_TEST(as bytes) {
auto xs = make_span(chars);
auto ys = make_span(shorts);
CAF_CHECK_EQUAL(as_bytes(xs).size(), chars.size());
CAF_CHECK_EQUAL(as_bytes(ys).size(), shorts.size() * 2);
CAF_CHECK_EQUAL(as_writable_bytes(xs).size(), chars.size());
CAF_CHECK_EQUAL(as_writable_bytes(ys).size(), shorts.size() * 2);
}
CAF_TEST(make_span) {
auto xs = make_span(chars);
auto ys = make_span(chars.data(), chars.size());
auto zs = make_span(chars.data(), chars.data() + chars.size());
CAF_CHECK(std::equal(xs.begin(), xs.end(), chars.begin()));
CAF_CHECK(std::equal(ys.begin(), ys.end(), chars.begin()));
CAF_CHECK(std::equal(zs.begin(), zs.end(), chars.begin()));
CAF_CHECK_EQUAL(end(xs), end(ys));
CAF_CHECK_EQUAL(end(ys), end(zs));
CAF_CHECK_EQUAL(begin(xs), begin(ys));
CAF_CHECK_EQUAL(begin(ys), begin(zs));
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment