Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions docs/enum_bitfiled.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@

## Overview

The `enum_bitfield_t` is a size adaptive bitfiled strage with using enumeration as an indexing type for bitfields
storage type depends on value of enum_size_v<> for enum selecting minimal suitable unisgned intergral

The `enum_bitfield_t` is a size adaptive bitfiled storage with using enumeration as an indexing type for bitfields.
Include the `simple_enum/enum_bitfield.h` in your project to use `enum_bitfield_t`

## `enum_bitfield_t` Interface
Storage type depends on value of enum_size_v<> for enum selecting minimal suitable unisgned intergral.
First lowest bit of bitfield is mapped into first valid enumeration value.
Bitfields support sparse enumerations in the way that some bits that are not mapped by then enumeration are always set to 0.

In below enumeration
- read is mapped into bit 0
- write is mapped into bit 3
- execute is mapped into bit 4

```cpp
enum struct permission_t { read = -1, write = 2, execute = 3, first = read, last = execute };
```

## `enum_bitfield_t` Interface

```cpp

Expand Down Expand Up @@ -47,8 +57,13 @@ enum_bitfield_t support class template argument deducation when using arguments
}
```

operators |, &, |=, &=, ~, ^, ^=
examples from tests using different enumerations

```cpp
// operators |, &, |=, &=, ~, ^, ^=
{
enum struct large_enum_t { v0, v1, v2, v3 ... v39};

static_assert((enum_bitfield_t{v16, v21} | enum_bitfield_t{v31, v5})
== enum_bitfield_t{v21, v16, v5, v31});
static_assert((enum_bitfield_t{v16, v21, v34, v1} & enum_bitfield_t{v16, v21, v5})
Expand All @@ -61,9 +76,13 @@ enum_bitfield_t support class template argument deducation when using arguments
enum_bitfield_t b{v16, v21};
b |= enum_bitfield_t{v31, v5};
expect(b == enum_bitfield_t{v21, v16, v5, v31});

}
// ~ operator handles the case of sparse enumeration and is not setting dead bit of v2
{
enum struct medium_enum_t { v0 = 5, v1, /*v2,*/ v3 =8, v4, v5, v6, v7, v8, first = v0, last = v8 };
expect((enum_bitfield_t{v1, v2, v5, v6, v7} ^ enum_bitfield_t{v2, v5, v6}) == enum_bitfield_t{v1, v7});

static_assert((~enum_bitfield_t{v1, v2, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
}
```

40 changes: 0 additions & 40 deletions include/simple_enum/simple_enum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,33 +120,6 @@ inline constexpr char end_of_enumeration_name = '>';
#error "supply information to author about Your compiler"
#endif

#ifdef SIMPLE_ENUM_OPT_IN_STATIC_ASSERTS
// OPT IN TESTING CODE
enum struct verify_ennum_
{
v1
};

constexpr size_t find_enumeration_offset()
{
auto const func{std::string_view{f<verify_ennum_::v1>()}};
#if defined(_MSC_VER) and not defined(__clang__)
size_t pos = func.find('<');
if(pos == std::string_view::npos)
throw;
return pos;
#else
size_t pos = func.find("enumeration =");
if(pos == std::string_view::npos)
throw;
return pos + 12 + 1;
#endif
}

auto constexpr verify_offset() -> bool { return find_enumeration_offset() == initial_offset; }

static_assert(verify_offset());
#endif
} // namespace se

namespace simple_enum::inline v0_9
Expand Down Expand Up @@ -174,19 +147,6 @@ namespace detail
meta_name enumeration_name;
};

constexpr char const * find_sentinel(char const * str)
{
#ifdef __clang__
#pragma clang unsafe_buffer_usage begin
#endif
while(*str != ':' && *str != ')')
++str;
#ifdef __clang__
#pragma clang unsafe_buffer_usage end
#endif
return str;
}

template<char end_of_enum = ']'>
constexpr void parse_enumeration_name(char const * str, meta_name & result) noexcept
{
Expand Down
30 changes: 15 additions & 15 deletions tests/enum_bitfield_ut.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enum struct color_t { red, green, blue, yellow, first = red, last = yellow };
enum struct permission_t { read = 4, write = 8, execute = 16, first = read, last = execute };

// Enum that should use uint16_t (9 values)
enum struct medium_enum_t { v0 = 5, v1, v2, v3, v4, v5, v6, v7, v8, first = v0, last = v8 };
enum struct medium_enum_t { v0 = 5, v1, /*v2,*/ v3 =8, v4, v5, v6, v7, v8, first = v0, last = v8 };

// Enum that should use uint64_t (40 values)
enum struct large_enum_t {
Expand Down Expand Up @@ -198,47 +198,47 @@ int main()
}
{
using enum medium_enum_t;
expect((~enum_bitfield_t{v1, v2, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
static_assert((~enum_bitfield_t{v1, v2, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
expect((~enum_bitfield_t{v1, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
static_assert((~enum_bitfield_t{v1, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
}
};

"operator ^"_test = []
{
using enum medium_enum_t;
expect((enum_bitfield_t{v1, v2, v5, v6, v7} ^ enum_bitfield_t{v2, v5, v6}) == enum_bitfield_t{v1, v7});
expect((enum_bitfield_t{v1, v2} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v2, v5, v6});
expect((enum_bitfield_t{v1, v5, v6, v7} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v7});
expect((enum_bitfield_t{v1, v3} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v3, v5, v6});

static_assert((enum_bitfield_t{v1, v2, v5, v6, v7} ^ enum_bitfield_t{v2, v5, v6}) == enum_bitfield_t{v1, v7});
static_assert((enum_bitfield_t{v1, v2} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v2, v5, v6});
static_assert((enum_bitfield_t{v1, v3, v5, v6, v7} ^ enum_bitfield_t{v3, v5, v6}) == enum_bitfield_t{v1, v7});
static_assert((enum_bitfield_t{v1, v3} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v3, v5, v6});
};

"operator ^="_test = []
{
using enum medium_enum_t;
enum_bitfield_t a{v1, v2, v5, v6, v7};
a ^= enum_bitfield_t{v2, v5, v6};
enum_bitfield_t a{v1, v5, v6, v7};
a ^= enum_bitfield_t{v5, v6};
expect(a == enum_bitfield_t{v1, v7});

enum_bitfield_t b{v1, v2};
enum_bitfield_t b{v1};
b ^= enum_bitfield_t{v5, v6};
expect(b == enum_bitfield_t{v1, v2, v5, v6});
expect(b == enum_bitfield_t{v1, v5, v6});

auto constexpr fn_a = []()
{
enum_bitfield_t x{v1, v2, v5, v6, v7};
x ^= enum_bitfield_t{v2, v5, v6};
enum_bitfield_t x{v1, v3, v5, v6, v7};
x ^= enum_bitfield_t{v3, v5, v6};
return x;
};
static_assert(fn_a() == enum_bitfield_t{v1, v7});

auto constexpr fn_b = []()
{
enum_bitfield_t x{v1, v2};
enum_bitfield_t x{v1, v3};
x ^= enum_bitfield_t{v5, v6};
return x;
};
static_assert(fn_b() == enum_bitfield_t{v1, v2, v5, v6});
static_assert(fn_b() == enum_bitfield_t{v1, v3, v5, v6});
};

"operator |"_test = []
Expand Down
30 changes: 30 additions & 0 deletions tests/test_simple_enum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@
#endif
#include "simple_enum_tests.hpp"

#ifndef SIMPLE_ENUM_CXX_MODULE
namespace se
{
// OPT IN TESTING CODE
enum struct verify_ennum_
{
v1
};

constexpr size_t find_enumeration_offset()
{
auto const func{std::string_view{f<verify_ennum_::v1>()}};
#if defined(_MSC_VER) and not defined(__clang__)
size_t pos = func.find('<');
if(pos == std::string_view::npos)
throw;
return pos;
#else
size_t pos = func.find("enumeration =");
if(pos == std::string_view::npos)
throw;
return pos + 12 + 1;
#endif
}

auto constexpr verify_offset() -> bool { return find_enumeration_offset() == initial_offset; }

static_assert(verify_offset());
} // namespace se
#endif
// TODO chck impact of clang-18 attribute
// enum E { Apple, Orange, Pear };
// struct S {
Expand Down