diff options
Diffstat (limited to 'include/o3tl/typed_flags_set.hxx')
-rw-r--r-- | include/o3tl/typed_flags_set.hxx | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/include/o3tl/typed_flags_set.hxx b/include/o3tl/typed_flags_set.hxx new file mode 100644 index 000000000..413ee9579 --- /dev/null +++ b/include/o3tl/typed_flags_set.hxx @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_O3TL_TYPED_FLAGS_SET_HXX +#define INCLUDED_O3TL_TYPED_FLAGS_SET_HXX + +#include <sal/config.h> + +#include <cassert> +#include <type_traits> + +#include <o3tl/underlyingenumvalue.hxx> + +namespace o3tl { + +namespace detail { + +template<typename T> constexpr +typename std::enable_if<std::is_signed<T>::value, bool>::type isNonNegative( + T value) +{ + return value >= 0; +} + +template<typename T> constexpr +typename std::enable_if<std::is_unsigned<T>::value, bool>::type isNonNegative(T) +{ + return true; +} + +} + +template<typename T> struct typed_flags {}; + +/// Mark a (scoped) enumeration as a set of bit flags, with accompanying +/// operations. +/// +/// template<> +/// struct o3tl::typed_flags<TheE>: o3tl::is_typed_flags<TheE, TheM> {}; +/// +/// All relevant values must be non-negative. (Typically, the enumeration's +/// underlying type will either be fixed and unsigned, or it will be unfixed--- +/// and can thus default to a signed type---and all enumerators will have non- +/// negative values.) +/// +/// \param E the enumeration type. +/// \param M the all-bits-set value for the bit flags. +template<typename E, typename std::underlying_type<E>::type M> +struct is_typed_flags { + static_assert( + M >= 0, "is_typed_flags expects only non-negative bit values"); + + typedef E Self; + + class Wrap { + public: + typedef is_typed_flags Unwrapped; + + explicit constexpr Wrap(typename std::underlying_type<E>::type value): + value_(value) + { + assert(detail::isNonNegative(value)); + assert( + static_cast<typename std::underlying_type<E>::type>(~0) == M + // avoid "operands don't affect result" warnings when M + // covers all bits of the underlying type + || (value & ~M) == 0); + } + + constexpr operator E() const { return static_cast<E>(value_); } + + explicit constexpr operator typename std::underlying_type<E>::type() + const + { return value_; } + + explicit constexpr operator bool() const { return value_ != 0; } + + private: + typename std::underlying_type<E>::type value_; + }; + + static typename std::underlying_type<E>::type const mask = M; +}; + +} + +template<typename E> +constexpr typename o3tl::typed_flags<E>::Wrap operator ~(E rhs) { + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::typed_flags<E>::mask + & ~o3tl::to_underlying(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ~( + typename o3tl::typed_flags<E>::Wrap rhs) +{ + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::typed_flags<E>::mask + & ~o3tl::to_underlying<E>(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^( + E lhs, E rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying(lhs) + ^ o3tl::to_underlying(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^( + E lhs, typename o3tl::typed_flags<E>::Wrap rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying(lhs) + ^ o3tl::to_underlying<E>(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^( + typename o3tl::typed_flags<E>::Wrap lhs, E rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying<E>(lhs) + ^ o3tl::to_underlying(rhs)); +} + +template<typename W> constexpr +typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator ^( + W lhs, W rhs) +{ + return static_cast<W>( + o3tl::to_underlying<typename W::Unwrapped::Self>(lhs) + ^ o3tl::to_underlying<typename W::Unwrapped::Self>(rhs)); +} + +template<typename E> +constexpr typename o3tl::typed_flags<E>::Wrap operator &(E lhs, E rhs) { + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying(lhs) + & o3tl::to_underlying(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator &( + E lhs, typename o3tl::typed_flags<E>::Wrap rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying(lhs) + & o3tl::to_underlying<E>(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator &( + typename o3tl::typed_flags<E>::Wrap lhs, E rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying<E>(lhs) + & o3tl::to_underlying(rhs)); +} + +template<typename W> constexpr +typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator &( + W lhs, W rhs) +{ + return static_cast<W>( + o3tl::to_underlying<typename W::Unwrapped::Self>(lhs) + & o3tl::to_underlying<typename W::Unwrapped::Self>(rhs)); +} + +template<typename E> +constexpr typename o3tl::typed_flags<E>::Wrap operator |(E lhs, E rhs) { + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying(lhs) + | o3tl::to_underlying(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator |( + E lhs, typename o3tl::typed_flags<E>::Wrap rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying(lhs) + | o3tl::to_underlying<E>(rhs)); +} + +template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator |( + typename o3tl::typed_flags<E>::Wrap lhs, E rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + return static_cast<typename o3tl::typed_flags<E>::Wrap>( + o3tl::to_underlying<E>(lhs) + | o3tl::to_underlying(rhs)); +} + +template<typename W> constexpr +typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator |( + W lhs, W rhs) +{ + return static_cast<W>( + o3tl::to_underlying<typename W::Unwrapped::Self>(lhs) + | o3tl::to_underlying<typename W::Unwrapped::Self>(rhs)); +} + +template<typename E> +inline typename o3tl::typed_flags<E>::Self operator &=(E & lhs, E rhs) { + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + lhs = lhs & rhs; + return lhs; +} + +template<typename E> +inline typename o3tl::typed_flags<E>::Self operator &=( + E & lhs, typename o3tl::typed_flags<E>::Wrap rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + lhs = lhs & rhs; + return lhs; +} + +template<typename E> +inline typename o3tl::typed_flags<E>::Self operator |=(E & lhs, E rhs) { + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + lhs = lhs | rhs; + return lhs; +} + +template<typename E> +inline typename o3tl::typed_flags<E>::Self operator |=( + E & lhs, typename o3tl::typed_flags<E>::Wrap rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + lhs = lhs | rhs; + return lhs; +} + +template<typename E> +inline typename o3tl::typed_flags<E>::Self operator ^=(E & lhs, E rhs) { + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(rhs))); + lhs = lhs ^ rhs; + return lhs; +} + +template<typename E> +inline typename o3tl::typed_flags<E>::Self operator ^=( + E & lhs, typename o3tl::typed_flags<E>::Wrap rhs) +{ + assert( + o3tl::detail::isNonNegative( + o3tl::to_underlying(lhs))); + lhs = lhs ^ rhs; + return lhs; +} + +#endif /* INCLUDED_O3TL_TYPED_FLAGS_SET_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |