/* -*- 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 #include #include #include namespace o3tl { namespace detail { template constexpr typename std::enable_if::value, bool>::type isNonNegative( T value) { return value >= 0; } template constexpr typename std::enable_if::value, bool>::type isNonNegative(T) { return true; } } template struct typed_flags {}; /// Mark a (scoped) enumeration as a set of bit flags, with accompanying /// operations. /// /// template<> /// struct o3tl::typed_flags: o3tl::is_typed_flags {}; /// /// 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::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::type value): value_(value) { assert(detail::isNonNegative(value)); assert( static_cast::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(value_); } explicit constexpr operator typename std::underlying_type::type() const { return value_; } explicit constexpr operator bool() const { return value_ != 0; } private: typename std::underlying_type::type value_; }; static typename std::underlying_type::type const mask = M; }; } template constexpr typename o3tl::typed_flags::Wrap operator ~(E rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(rhs))); return static_cast::Wrap>( o3tl::typed_flags::mask & ~o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator ~( typename o3tl::typed_flags::Wrap rhs) { return static_cast::Wrap>( o3tl::typed_flags::mask & ~o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::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::Wrap>( o3tl::to_underlying(lhs) ^ o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator ^( E lhs, typename o3tl::typed_flags::Wrap rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(lhs))); return static_cast::Wrap>( o3tl::to_underlying(lhs) ^ o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator ^( typename o3tl::typed_flags::Wrap lhs, E rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(rhs))); return static_cast::Wrap>( o3tl::to_underlying(lhs) ^ o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator ^( W lhs, W rhs) { return static_cast( o3tl::to_underlying(lhs) ^ o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::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::Wrap>( o3tl::to_underlying(lhs) & o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator &( E lhs, typename o3tl::typed_flags::Wrap rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(lhs))); return static_cast::Wrap>( o3tl::to_underlying(lhs) & o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator &( typename o3tl::typed_flags::Wrap lhs, E rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(rhs))); return static_cast::Wrap>( o3tl::to_underlying(lhs) & o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator &( W lhs, W rhs) { return static_cast( o3tl::to_underlying(lhs) & o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::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::Wrap>( o3tl::to_underlying(lhs) | o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator |( E lhs, typename o3tl::typed_flags::Wrap rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(lhs))); return static_cast::Wrap>( o3tl::to_underlying(lhs) | o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator |( typename o3tl::typed_flags::Wrap lhs, E rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(rhs))); return static_cast::Wrap>( o3tl::to_underlying(lhs) | o3tl::to_underlying(rhs)); } template constexpr typename o3tl::typed_flags::Wrap operator |( W lhs, W rhs) { return static_cast( o3tl::to_underlying(lhs) | o3tl::to_underlying(rhs)); } template inline typename o3tl::typed_flags::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 inline typename o3tl::typed_flags::Self operator &=( E & lhs, typename o3tl::typed_flags::Wrap rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(lhs))); lhs = lhs & rhs; return lhs; } template inline typename o3tl::typed_flags::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 inline typename o3tl::typed_flags::Self operator |=( E & lhs, typename o3tl::typed_flags::Wrap rhs) { assert( o3tl::detail::isNonNegative( o3tl::to_underlying(lhs))); lhs = lhs | rhs; return lhs; } template inline typename o3tl::typed_flags::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 inline typename o3tl::typed_flags::Self operator ^=( E & lhs, typename o3tl::typed_flags::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: */