mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[kernel] Move page mapping into vm_space
vm_space no longer relies on page_manager to map pages during a page fault. Other changes that come with this commit: - C++ standard has been changed to C++17 - enum bitfield operators became constexpr - enum bifrield operators can take a mix of ints and enum arguments - added page table flags enum instead of relying on ints - remove page_table::unmap_table and page_table::unmap_pages
This commit is contained in:
@@ -51,7 +51,7 @@ asflags = $
|
|||||||
-I${srcroot}/src/include
|
-I${srcroot}/src/include
|
||||||
|
|
||||||
cflags = -std=c11
|
cflags = -std=c11
|
||||||
cxxflags = -std=c++14
|
cxxflags = -std=c++17
|
||||||
libs =
|
libs =
|
||||||
|
|
||||||
rule c
|
rule c
|
||||||
|
|||||||
@@ -76,84 +76,6 @@ page_manager::map_pages(uintptr_t address, size_t count, bool user, page_table *
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
page_manager::unmap_table(page_table *table, page_table::level lvl, bool free, page_table_indices index)
|
|
||||||
{
|
|
||||||
const int max =
|
|
||||||
lvl == page_table::level::pml4
|
|
||||||
? pml4e_kernel
|
|
||||||
: table_entries;
|
|
||||||
|
|
||||||
uintptr_t free_start = 0;
|
|
||||||
uintptr_t free_start_virt = 0;
|
|
||||||
uintptr_t free_count = 0;
|
|
||||||
|
|
||||||
size_t size =
|
|
||||||
lvl == page_table::level::pdp ? (1<<30) :
|
|
||||||
lvl == page_table::level::pd ? (1<<21) :
|
|
||||||
lvl == page_table::level::pt ? (1<<12) :
|
|
||||||
0;
|
|
||||||
|
|
||||||
for (int i = 0; i < max; ++i) {
|
|
||||||
if (!table->is_present(i)) continue;
|
|
||||||
|
|
||||||
index[lvl] = i;
|
|
||||||
|
|
||||||
bool is_page =
|
|
||||||
lvl == page_table::level::pt ||
|
|
||||||
table->is_large_page(lvl, i);
|
|
||||||
|
|
||||||
if (is_page) {
|
|
||||||
uintptr_t frame = table->entries[i] & ~0xfffull;
|
|
||||||
if (!free_count || frame != free_start + free_count * size) {
|
|
||||||
if (free_count && free) {
|
|
||||||
log::debug(logs::paging,
|
|
||||||
" freeing v:%016lx-%016lx p:%016lx-%016lx",
|
|
||||||
free_start_virt, free_start_virt + free_count * frame_size,
|
|
||||||
free_start, free_start + free_count * frame_size);
|
|
||||||
|
|
||||||
m_frames.free(free_start, (free_count * size) / frame_size);
|
|
||||||
free_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!free_count) {
|
|
||||||
free_start = frame;
|
|
||||||
free_start_virt = index.addr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_count += 1;
|
|
||||||
} else {
|
|
||||||
page_table *next = table->get(i);
|
|
||||||
unmap_table(next, page_table::deeper(lvl), free, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (free_count && free) {
|
|
||||||
log::debug(logs::paging,
|
|
||||||
" freeing v:%016lx-%016lx p:%016lx-%016lx",
|
|
||||||
free_start_virt, free_start_virt + free_count * frame_size,
|
|
||||||
free_start, free_start + free_count * frame_size);
|
|
||||||
|
|
||||||
m_frames.free(free_start, (free_count * size) / frame_size);
|
|
||||||
}
|
|
||||||
page_table::free_table_page(table);
|
|
||||||
|
|
||||||
log::debug(logs::paging, "Unmapped%s lv %d table at %016lx",
|
|
||||||
free ? " (and freed)" : "", lvl, table);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
page_manager::unmap_pages(void* address, size_t count, page_table *pml4)
|
|
||||||
{
|
|
||||||
if (!pml4)
|
|
||||||
pml4 = get_pml4();
|
|
||||||
|
|
||||||
uintptr_t iaddr = reinterpret_cast<uintptr_t>(address);
|
|
||||||
|
|
||||||
page_out(pml4, iaddr, count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
page_manager::check_needs_page(page_table *table, unsigned index, bool user)
|
page_manager::check_needs_page(page_table *table, unsigned index, bool user)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,12 +57,6 @@ public:
|
|||||||
/// \returns A pointer to the start of the mapped region
|
/// \returns A pointer to the start of the mapped region
|
||||||
void * map_pages(uintptr_t address, size_t count, bool user = false, page_table *pml4 = nullptr);
|
void * map_pages(uintptr_t address, size_t count, bool user = false, page_table *pml4 = nullptr);
|
||||||
|
|
||||||
/// Unmap and free existing pages from memory.
|
|
||||||
/// \arg address The virtual address of the memory to unmap
|
|
||||||
/// \arg count The number of pages to unmap
|
|
||||||
/// \arg pml4 The pml4 to unmap from - null for the current one
|
|
||||||
void unmap_pages(void *address, size_t count, page_table *pml4 = nullptr);
|
|
||||||
|
|
||||||
/// Dump the given or current PML4 to the console
|
/// Dump the given or current PML4 to the console
|
||||||
/// \arg pml4 The page table to use, null for the current one
|
/// \arg pml4 The page table to use, null for the current one
|
||||||
/// \arg recurse Whether to print sub-tables
|
/// \arg recurse Whether to print sub-tables
|
||||||
@@ -110,10 +104,6 @@ private:
|
|||||||
size_t count,
|
size_t count,
|
||||||
bool free = false);
|
bool free = false);
|
||||||
|
|
||||||
/// Low-level routine for unmapping an entire table of memory at once
|
|
||||||
void unmap_table(page_table *table, page_table::level lvl, bool free,
|
|
||||||
page_table_indices index = {});
|
|
||||||
|
|
||||||
page_table *m_kernel_pml4; ///< The PML4 of just kernel pages
|
page_table *m_kernel_pml4; ///< The PML4 of just kernel pages
|
||||||
|
|
||||||
frame_allocator &m_frames;
|
frame_allocator &m_frames;
|
||||||
|
|||||||
@@ -14,17 +14,10 @@ free_page_header * page_table::s_page_cache = nullptr;
|
|||||||
size_t page_table::s_cache_count = 0;
|
size_t page_table::s_cache_count = 0;
|
||||||
constexpr size_t page_table::entry_sizes[4];
|
constexpr size_t page_table::entry_sizes[4];
|
||||||
|
|
||||||
// Flags: 0 0 0 0 0 0 0 0 0 0 1 1 = 0x0003
|
|
||||||
// IGNORED | | | | | | | +- Present
|
constexpr page_table::flag table_flags =
|
||||||
// | | | | | | +--- Writeable
|
page_table::flag::present |
|
||||||
// | | | | | +----- Usermode access (Supervisor only)
|
page_table::flag::write;
|
||||||
// | | | | +------- PWT (determining memory type for pdpt)
|
|
||||||
// | | | +---------- PCD (determining memory type for pdpt)
|
|
||||||
// | | +------------ Accessed flag (not accessed yet)
|
|
||||||
// | +-------------- Ignored
|
|
||||||
// +---------------- Reserved 0 (Table pointer, not page)
|
|
||||||
/// Page table entry flags for entries pointing at another table
|
|
||||||
constexpr uint16_t table_flags = 0x003;
|
|
||||||
|
|
||||||
|
|
||||||
page_table::iterator::iterator(uintptr_t virt, page_table *pml4) :
|
page_table::iterator::iterator(uintptr_t virt, page_table *pml4) :
|
||||||
@@ -114,7 +107,7 @@ page_table::iterator::allowed() const
|
|||||||
{
|
{
|
||||||
level d = depth();
|
level d = depth();
|
||||||
while (true) {
|
while (true) {
|
||||||
if (entry(d) & flag_allowed) return true;
|
if (entry(d) & flag::allowed) return true;
|
||||||
else if (d == level::pml4) return false;
|
else if (d == level::pml4) return false;
|
||||||
--d;
|
--d;
|
||||||
}
|
}
|
||||||
@@ -126,8 +119,8 @@ page_table::iterator::allow(level at, bool allowed)
|
|||||||
for (level l = level::pdp; l <= at; ++l)
|
for (level l = level::pdp; l <= at; ++l)
|
||||||
ensure_table(l);
|
ensure_table(l);
|
||||||
|
|
||||||
if (allowed) entry(at) |= flag_allowed;
|
if (allowed) entry(at) |= flag::allowed;
|
||||||
else entry(at) &= ~flag_allowed;
|
else entry(at) &= ~flag::allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -169,8 +162,9 @@ page_table::iterator::ensure_table(level l)
|
|||||||
kassert(n, "Failed to allocate a page table");
|
kassert(n, "Failed to allocate a page table");
|
||||||
|
|
||||||
uint64_t &parent = entry(l - 1);
|
uint64_t &parent = entry(l - 1);
|
||||||
uint64_t flags = table_flags |
|
flag flags = table_flags | (parent & flag::allowed);
|
||||||
(parent & flag_allowed) ? flag_allowed : 0;
|
if (m_index[0] < memory::pml4e_kernel)
|
||||||
|
flags |= flag::user;
|
||||||
|
|
||||||
m_table[unsigned(l)] = reinterpret_cast<page_table*>(phys | page_offset);
|
m_table[unsigned(l)] = reinterpret_cast<page_table*>(phys | page_offset);
|
||||||
parent = (reinterpret_cast<uintptr_t>(phys) & ~0xfffull) | flags;
|
parent = (reinterpret_cast<uintptr_t>(phys) & ~0xfffull) | flags;
|
||||||
@@ -193,7 +187,7 @@ page_table::get(int i, uint16_t *flags) const
|
|||||||
void
|
void
|
||||||
page_table::set(int i, page_table *p, uint16_t flags)
|
page_table::set(int i, page_table *p, uint16_t flags)
|
||||||
{
|
{
|
||||||
if (entries[i] & flag_allowed) flags |= flag_allowed;
|
if (entries[i] & flag::allowed) flags |= flag::allowed;
|
||||||
entries[i] =
|
entries[i] =
|
||||||
(reinterpret_cast<uint64_t>(p) - page_offset) |
|
(reinterpret_cast<uint64_t>(p) - page_offset) |
|
||||||
(flags & 0xfff);
|
(flags & 0xfff);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/// Helper structures for dealing with page tables.
|
/// Helper structures for dealing with page tables.
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "kutil/enum_bitfields.h"
|
||||||
#include "kernel_memory.h"
|
#include "kernel_memory.h"
|
||||||
|
|
||||||
struct free_page_header;
|
struct free_page_header;
|
||||||
@@ -14,6 +15,26 @@ struct page_table
|
|||||||
/// Enum representing the table levels in 4-level paging
|
/// Enum representing the table levels in 4-level paging
|
||||||
enum class level : unsigned { pml4, pdp, pd, pt, page };
|
enum class level : unsigned { pml4, pdp, pd, pt, page };
|
||||||
|
|
||||||
|
/// Page entry flags
|
||||||
|
enum class flag : uint64_t
|
||||||
|
{
|
||||||
|
none = 0x0000,
|
||||||
|
present = 0x0001, /// Entry is present in the table
|
||||||
|
write = 0x0002, /// Section may be written
|
||||||
|
user = 0x0004, /// User-accessible
|
||||||
|
mtrr0 = 0x0008, /// MTRR selector bit 0
|
||||||
|
mtrr1 = 0x0010, /// MTRR selector bit 1
|
||||||
|
accessed = 0x0020, /// Entry has been accessed
|
||||||
|
dirty = 0x0040, /// Page has been written to
|
||||||
|
page = 0x0080, /// Entry is a large page
|
||||||
|
pte_mtrr2 = 0x0080, /// MTRR selector bit 2 on PT entries
|
||||||
|
global = 0x0100, /// Entry is not PCID-specific
|
||||||
|
mtrr2 = 0x1000, /// MTRR selector bit 2 on PD and PDP entries
|
||||||
|
|
||||||
|
// jsix-defined
|
||||||
|
allowed = 0x0800 /// Allocation here is allowed
|
||||||
|
};
|
||||||
|
|
||||||
/// Helper for getting the next level value
|
/// Helper for getting the next level value
|
||||||
inline static level deeper(level l) {
|
inline static level deeper(level l) {
|
||||||
return static_cast<level>(static_cast<unsigned>(l) + 1);
|
return static_cast<level>(static_cast<unsigned>(l) + 1);
|
||||||
@@ -25,9 +46,6 @@ struct page_table
|
|||||||
0x200000, // PD entry: 2 MiB
|
0x200000, // PD entry: 2 MiB
|
||||||
0x1000}; // PT entry: 4 KiB
|
0x1000}; // PT entry: 4 KiB
|
||||||
|
|
||||||
/// Flag marking unused space as allowed for allocation
|
|
||||||
static constexpr uint64_t flag_allowed = (1ull << 11);
|
|
||||||
|
|
||||||
/// Iterator over page table entries.
|
/// Iterator over page table entries.
|
||||||
class iterator
|
class iterator
|
||||||
{
|
{
|
||||||
@@ -197,3 +215,5 @@ inline bool operator<(page_table::level a, page_table::level b) {
|
|||||||
|
|
||||||
inline page_table::level& operator++(page_table::level& l) { l = l + 1; return l; }
|
inline page_table::level& operator++(page_table::level& l) { l = l + 1; return l; }
|
||||||
inline page_table::level& operator--(page_table::level& l) { l = l - 1; return l; }
|
inline page_table::level& operator--(page_table::level& l) { l = l - 1; return l; }
|
||||||
|
|
||||||
|
IS_BITFIELD(page_table::flag);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "frame_allocator.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
@@ -5,6 +6,8 @@
|
|||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
#include "vm_space.h"
|
#include "vm_space.h"
|
||||||
|
|
||||||
|
extern frame_allocator &g_frame_allocator;
|
||||||
|
|
||||||
int
|
int
|
||||||
vm_space::area::compare(const vm_space::area &o) const
|
vm_space::area::compare(const vm_space::area &o) const
|
||||||
{
|
{
|
||||||
@@ -152,17 +155,26 @@ vm_space::handle_fault(uintptr_t addr, fault_type fault)
|
|||||||
|
|
||||||
page_table::iterator it {addr, m_pml4};
|
page_table::iterator it {addr, m_pml4};
|
||||||
|
|
||||||
|
// TODO: Handle more fult types
|
||||||
|
if (fault && fault_type::present)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!it.allowed())
|
if (!it.allowed())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: pull this out of PM
|
uintptr_t phys = 0;
|
||||||
page_manager::get()->map_pages(page, 1, m_pml4);
|
size_t n = g_frame_allocator.allocate(1, &phys);
|
||||||
|
kassert(n, "Failed to allocate a new page during page fault");
|
||||||
|
|
||||||
/* TODO: Tell the VMA if there is one
|
page_table::flag flags =
|
||||||
uintptr_t base = 0;
|
page_table::flag::present |
|
||||||
vm_area *area = get(addr, &base);
|
page_table::flag::write |
|
||||||
*/
|
page_table::flag::allowed |
|
||||||
|
(is_kernel()
|
||||||
|
? page_table::flag::global
|
||||||
|
: page_table::flag::user);
|
||||||
|
|
||||||
|
it.entry(page_table::level::pt) = phys | flags;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,104 +8,130 @@ struct is_enum_bitfield { static constexpr bool value = false; };
|
|||||||
#define IS_BITFIELD(name) \
|
#define IS_BITFIELD(name) \
|
||||||
template<> struct ::is_enum_bitfield<name> {static constexpr bool value=true;}
|
template<> struct ::is_enum_bitfield<name> {static constexpr bool value=true;}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
struct enum_or_int {
|
||||||
|
static constexpr bool value =
|
||||||
|
std::disjunction< is_enum_bitfield<E>, std::is_integral<E> >::value;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
struct both_enum_or_int {
|
||||||
|
static constexpr bool value =
|
||||||
|
std::conjunction< enum_or_int<E>, enum_or_int<F> >::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
struct integral { using type = typename std::underlying_type<E>::type; };
|
||||||
|
|
||||||
|
template <> struct integral<char> { using type = char; };
|
||||||
|
template <> struct integral<unsigned char> { using type = unsigned char; };
|
||||||
|
template <> struct integral<short> { using type = short; };
|
||||||
|
template <> struct integral<unsigned short> { using type = unsigned short; };
|
||||||
|
template <> struct integral<int> { using type = int; };
|
||||||
|
template <> struct integral<unsigned int> { using type = unsigned int; };
|
||||||
|
template <> struct integral<long> { using type = long; };
|
||||||
|
template <> struct integral<unsigned long> { using type = unsigned long; };
|
||||||
|
template <> struct integral<long long> { using type = long long; };
|
||||||
|
template <> struct integral<unsigned long long> { using type = unsigned long long; };
|
||||||
|
|
||||||
|
template <typename E, typename F>
|
||||||
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type
|
||||||
operator & (E lhs, F rhs)
|
operator & (E lhs, F rhs)
|
||||||
{
|
{
|
||||||
return static_cast<E> (
|
return static_cast<E> (
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
static_cast<typename integral<E>::type>(lhs) &
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type
|
||||||
operator | (E lhs, F rhs)
|
operator | (E lhs, F rhs)
|
||||||
{
|
{
|
||||||
return static_cast<E> (
|
return static_cast<E> (
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
static_cast<typename integral<E>::type>(lhs) |
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type
|
||||||
operator ^ (E lhs, F rhs)
|
operator ^ (E lhs, F rhs)
|
||||||
{
|
{
|
||||||
return static_cast<E> (
|
return static_cast<E> (
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) ^
|
static_cast<typename integral<E>::type>(lhs) ^
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
constexpr typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||||
operator ~ (E rhs)
|
operator ~ (E rhs)
|
||||||
{
|
{
|
||||||
return static_cast<E>(~static_cast<typename std::underlying_type<E>::type>(rhs));
|
return static_cast<E>(~static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||||
operator |= (E &lhs, F rhs)
|
operator |= (E &lhs, F rhs)
|
||||||
{
|
{
|
||||||
lhs = static_cast<E>(
|
lhs = static_cast<E>(
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
static_cast<typename integral<E>::type>(lhs) |
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||||
operator &= (E &lhs, F rhs)
|
operator &= (E &lhs, F rhs)
|
||||||
{
|
{
|
||||||
lhs = static_cast<E>(
|
lhs = static_cast<E>(
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
static_cast<typename integral<E>::type>(lhs) &
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||||
operator ^= (E &lhs, F rhs)
|
operator ^= (E &lhs, F rhs)
|
||||||
{
|
{
|
||||||
lhs = static_cast<E>(
|
lhs = static_cast<E>(
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) ^
|
static_cast<typename integral<E>::type>(lhs) ^
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||||
operator -= (E &lhs, F rhs)
|
operator -= (E &lhs, F rhs)
|
||||||
{
|
{
|
||||||
lhs = static_cast<E>(
|
lhs = static_cast<E>(
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
static_cast<typename integral<E>::type>(lhs) &
|
||||||
~static_cast<typename std::underlying_type<E>::type>(rhs));
|
~static_cast<typename integral<F>::type>(rhs));
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename F>
|
template <typename E, typename F>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
constexpr typename std::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||||
operator += (E &lhs, F rhs)
|
operator += (E &lhs, F rhs)
|
||||||
{
|
{
|
||||||
lhs = static_cast<E>(
|
lhs = static_cast<E>(
|
||||||
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
static_cast<typename integral<E>::type>(lhs) |
|
||||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
static_cast<typename integral<F>::type>(rhs));
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
constexpr typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||||
operator ! (E rhs)
|
operator ! (E rhs)
|
||||||
{
|
{
|
||||||
return static_cast<typename std::underlying_type<E>::type>(rhs) == 0;
|
return static_cast<typename std::underlying_type<E>::type>(rhs) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
constexpr typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||||
bitfield_has(E set, E flag)
|
bitfield_has(E set, E flag)
|
||||||
{
|
{
|
||||||
return (set & flag) == flag;
|
return (set & flag) == flag;
|
||||||
@@ -113,7 +139,7 @@ bitfield_has(E set, E flag)
|
|||||||
|
|
||||||
// Overload the logical-and operator to be 'bitwise-and, bool-cast'
|
// Overload the logical-and operator to be 'bitwise-and, bool-cast'
|
||||||
template <typename E>
|
template <typename E>
|
||||||
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
constexpr typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||||
operator && (E set, E flag)
|
operator && (E set, E flag)
|
||||||
{
|
{
|
||||||
return (set & flag) == flag;
|
return (set & flag) == flag;
|
||||||
|
|||||||
Reference in New Issue
Block a user