From: <man...@us...> - 2014-12-03 16:36:43
|
Revision: 4630 http://sourceforge.net/p/modplug/code/4630 Author: manxorist Date: 2014-12-03 16:36:24 +0000 (Wed, 03 Dec 2014) Log Message: ----------- [Fix] Fix undefined behaviour. Rewrite FlagSet to be standard-conforming and more type-safe. Storing bitwise compositions of enum values into a variable of enum type is undefined behaviour if the resulting value lies outside the enum value range. Clang ubsan complains loudly. Additionally, explicitely stating the FlagSet type makes the code intent more obvious. [Ref] Add Enum<enum_t>, a stricter version that allows only storing a single enum value and no compositions (without using casts anyway). [Ref] The type returned from FlagSet values bitwise combined with enum values is no longer comparable or convertible to an integer value. Specifically this means ((FlagSet<MODTYPE>(a) & MODTYPE_IT) != 0) no longer compiles. The bitwise combined expression, however, is convertible to bool, so this is a trivial replacement on all usage sites. [Ref] Convert FlagSet<MODTYPE> to Enum<MODTYPE>. [Ref] Avoid dynamic initialization of some static tables which had been caused by combining enum values using custom bitwise operators. Modified Paths: -------------- trunk/OpenMPT/common/FlagSet.h trunk/OpenMPT/common/typedefs.h trunk/OpenMPT/mptrack/Autotune.cpp trunk/OpenMPT/mptrack/CommandSet.cpp trunk/OpenMPT/mptrack/CommandSet.h trunk/OpenMPT/mptrack/Ctrl_gen.cpp trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Ctrl_ins.h trunk/OpenMPT/mptrack/Ctrl_pat.cpp trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/Ctrl_smp.h trunk/OpenMPT/mptrack/Draw_pat.cpp trunk/OpenMPT/mptrack/EffectInfo.cpp trunk/OpenMPT/mptrack/KeyConfigDlg.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Moddoc.h trunk/OpenMPT/mptrack/Notification.h trunk/OpenMPT/mptrack/PatternClipboard.cpp trunk/OpenMPT/mptrack/UpdateHints.h trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/mptrack/View_ins.cpp trunk/OpenMPT/mptrack/View_ins.h trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/mptrack/View_smp.h trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/mptrack/dlg_misc.cpp trunk/OpenMPT/mptrack/view_com.cpp trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/mod_specifications.cpp trunk/OpenMPT/soundlib/mod_specifications.h trunk/OpenMPT/soundlib/pattern.cpp trunk/OpenMPT/test/test.cpp Modified: trunk/OpenMPT/common/FlagSet.h =================================================================== --- trunk/OpenMPT/common/FlagSet.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/common/FlagSet.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -2,7 +2,8 @@ * FlagSet.h * --------- * Purpose: A flexible and typesafe flag set class. - * Notes : Mostly taken from http://stackoverflow.com/questions/4226960/type-safer-bitflags-in-c + * Notes : Originally based on http://stackoverflow.com/questions/4226960/type-safer-bitflags-in-c . + * Rewritten to be standard-conforming. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ @@ -14,165 +15,407 @@ OPENMPT_NAMESPACE_BEGIN -template <typename enum_t, typename store_t = enum_t> + +// Be aware of the required size when specializing this. +// We cannot assert the minimum size because some compilers always allocate an 'int', +// even for enums that would fit in smaller integral types. +template <typename Tenum> +struct enum_traits +{ + typedef typename mpt::make_unsigned<Tenum>::type store_type; +}; + + +// Type-safe wrapper around an enum, that can represent all enum values and bitwise compositions thereof. +// Conversions to and from plain integers as well as conversions to the base enum are always explicit. +template <typename enum_t> +class enum_value_type +{ +public: + typedef enum_t enum_type; + typedef enum_value_type value_type; + typedef typename enum_traits<enum_t>::store_type store_type; +private: + store_type bits; +public: + forceinline enum_value_type() : bits(0) { } + forceinline enum_value_type(const enum_value_type &x) : bits(x.bits) { } + forceinline enum_value_type(enum_type x) : bits(static_cast<store_type>(x)) { } +private: + explicit forceinline enum_value_type(store_type x) : bits(x) { } // private in order to prevent accidental conversions. use from_bits. + forceinline operator store_type () const { return bits; } // private in order to prevent accidental conversions. use as_bits. +public: + static forceinline enum_value_type from_bits(store_type bits) { return value_type(bits); } + forceinline enum_type as_enum() const { return static_cast<enum_t>(bits); } + forceinline store_type as_bits() const { return bits; } +public: + forceinline operator bool () const { return bits != store_type(); } + forceinline bool operator ! () const { return bits == store_type(); } + + forceinline const enum_value_type operator ~ () const { return enum_value_type(~bits); } + + friend forceinline bool operator == (enum_value_type a, enum_value_type b) { return a.bits == b.bits; } + friend forceinline bool operator != (enum_value_type a, enum_value_type b) { return a.bits != b.bits; } + + friend forceinline bool operator == (enum_value_type a, enum_t b) { return a == enum_value_type(b); } + friend forceinline bool operator != (enum_value_type a, enum_t b) { return a != enum_value_type(b); } + + friend forceinline bool operator == (enum_t a, enum_value_type b) { return enum_value_type(a) == b; } + friend forceinline bool operator != (enum_t a, enum_value_type b) { return enum_value_type(a) != b; } + + friend forceinline const enum_value_type operator | (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits | b.bits); } + friend forceinline const enum_value_type operator & (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits & b.bits); } + friend forceinline const enum_value_type operator ^ (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits ^ b.bits); } + + friend forceinline const enum_value_type operator | (enum_value_type a, enum_t b) { return a | enum_value_type(b); } + friend forceinline const enum_value_type operator & (enum_value_type a, enum_t b) { return a & enum_value_type(b); } + friend forceinline const enum_value_type operator ^ (enum_value_type a, enum_t b) { return a ^ enum_value_type(b); } + + friend forceinline const enum_value_type operator | (enum_t a, enum_value_type b) { return enum_value_type(a) | b; } + friend forceinline const enum_value_type operator & (enum_t a, enum_value_type b) { return enum_value_type(a) & b; } + friend forceinline const enum_value_type operator ^ (enum_t a, enum_value_type b) { return enum_value_type(a) ^ b; } + + forceinline enum_value_type &operator |= (enum_value_type b) { *this = *this | b; return *this; } + forceinline enum_value_type &operator &= (enum_value_type b) { *this = *this & b; return *this; } + forceinline enum_value_type &operator ^= (enum_value_type b) { *this = *this ^ b; return *this; } + + forceinline enum_value_type &operator |= (enum_t b) { *this = *this | b; return *this; } + forceinline enum_value_type &operator &= (enum_t b) { *this = *this & b; return *this; } + forceinline enum_value_type &operator ^= (enum_t b) { *this = *this ^ b; return *this; } + +}; + + +// Type-safe enum wrapper that allows type-safe bitwise testing. +template <typename enum_t> +class Enum +{ +public: + typedef Enum self_type; + typedef enum_t enum_type; + typedef enum_value_type<enum_t> value_type; + typedef typename value_type::store_type store_type; +private: + enum_type value; +public: + explicit forceinline Enum(enum_type val) : value(val) { } + forceinline operator enum_type () const { return value; } + forceinline Enum &operator = (enum_type val) { value = val; return *this; } +public: + forceinline const value_type operator ~ () const { return ~value_type(value); } + + friend forceinline bool operator == (self_type a, self_type b) { return value_type(a) == value_type(b); } + friend forceinline bool operator != (self_type a, self_type b) { return value_type(a) != value_type(b); } + + friend forceinline bool operator == (self_type a, value_type b) { return value_type(a) == value_type(b); } + friend forceinline bool operator != (self_type a, value_type b) { return value_type(a) != value_type(b); } + + friend forceinline bool operator == (value_type a, self_type b) { return value_type(a) == value_type(b); } + friend forceinline bool operator != (value_type a, self_type b) { return value_type(a) != value_type(b); } + + friend forceinline bool operator == (self_type a, enum_type b) { return value_type(a) == value_type(b); } + friend forceinline bool operator != (self_type a, enum_type b) { return value_type(a) != value_type(b); } + + friend forceinline bool operator == (enum_type a, self_type b) { return value_type(a) == value_type(b); } + friend forceinline bool operator != (enum_type a, self_type b) { return value_type(a) != value_type(b); } + + friend forceinline const value_type operator | (self_type a, self_type b) { return value_type(a) | value_type(b); } + friend forceinline const value_type operator & (self_type a, self_type b) { return value_type(a) & value_type(b); } + friend forceinline const value_type operator ^ (self_type a, self_type b) { return value_type(a) ^ value_type(b); } + + friend forceinline const value_type operator | (self_type a, value_type b) { return value_type(a) | value_type(b); } + friend forceinline const value_type operator & (self_type a, value_type b) { return value_type(a) & value_type(b); } + friend forceinline const value_type operator ^ (self_type a, value_type b) { return value_type(a) ^ value_type(b); } + + friend forceinline const value_type operator | (value_type a, self_type b) { return value_type(a) | value_type(b); } + friend forceinline const value_type operator & (value_type a, self_type b) { return value_type(a) & value_type(b); } + friend forceinline const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ value_type(b); } + + friend forceinline const value_type operator | (self_type a, enum_type b) { return value_type(a) | value_type(b); } + friend forceinline const value_type operator & (self_type a, enum_type b) { return value_type(a) & value_type(b); } + friend forceinline const value_type operator ^ (self_type a, enum_type b) { return value_type(a) ^ value_type(b); } + + friend forceinline const value_type operator | (enum_type a, self_type b) { return value_type(a) | value_type(b); } + friend forceinline const value_type operator & (enum_type a, self_type b) { return value_type(a) & value_type(b); } + friend forceinline const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ value_type(b); } + +}; + + +template <typename enum_t, typename store_t = typename enum_value_type<enum_t>::store_type > class FlagSet { public: + typedef FlagSet self_type; + typedef enum_t enum_type; + typedef enum_value_type<enum_t> value_type; + typedef store_t store_type; + +private: + + // support truncated store_type ... : + store_type bits_; + static forceinline store_type store_from_value(value_type bits) { return static_cast<store_type>(bits.as_bits()); } + static forceinline value_type value_from_store(store_type bits) { return value_type::from_bits(static_cast<typename value_type::store_type>(bits)); } + + forceinline void store(value_type bits) { bits_ = store_from_value(bits); } + forceinline value_type load() const { return value_from_store(bits_); } + +public: + // Default constructor (no flags set) - FlagSet() : flags(store_t(0)) + forceinline FlagSet() : bits_(store_from_value(value_type())) { - + return; } // Value constructor - explicit FlagSet(enum_t value) : flags(static_cast<store_t>(value)) + forceinline FlagSet(value_type flags) : bits_(store_from_value(value_type(flags))) { - + return; } - // Explicit conversion operator - operator enum_t() const + forceinline FlagSet(enum_type flag) : bits_(store_from_value(value_type(flag))) { - return static_cast<enum_t>(flags); + return; } - operator std::string() const + explicit forceinline FlagSet(store_type flags) : bits_(store_from_value(value_type::from_bits(flags))) { - return to_string(); + return; } + + forceinline operator bool () const + { + return load(); + } + // In order to catch undesired conversions to bool in integer contexts, + // add a deprecated conversion operator to store_type. + // C++11 explicit conversion cast operators ('explicit operator bool ();') + // would solve this in a better way and always fail at compile-time instead of this + // solution which just warns in some cases. + // The macro-based extended instrument fields writer in Sndfile.cpp currently needs this conversion, + // so it is not marked deprecated (for now). + /*MPT_DEPRECATED*/ forceinline operator store_type () const + { + return load().as_bits(); + } + + forceinline value_type value() const + { + return load(); + } + + forceinline operator value_type () const + { + return load(); + } // Test if one or more flags are set. Returns true if at least one of the given flags is set. - bool operator[] (enum_t flag) const + forceinline bool operator[] (value_type flags) const { - return test(flag); + return test(flags); } // String representation of flag set std::string to_string() const { - std::string str(size(), '0'); + std::string str(size_bits(), '0'); - for(size_t x = 0; x < size(); ++x) + for(size_t x = 0; x < size_bits(); ++x) { - str[size() - x - 1] = (flags & (1 << x) ? '1' : '0'); + str[size_bits() - x - 1] = (load() & (1 << x) ? '1' : '0'); } return str; } // Set one or more flags. - FlagSet &set(enum_t flag) + forceinline FlagSet &set(value_type flags) { - flags = static_cast<store_t>(flags | flag); + store(load() | flags); return *this; } // Set or clear one or more flags. - FlagSet &set(enum_t flag, bool val) + forceinline FlagSet &set(value_type flags, bool val) { - flags = static_cast<store_t>(val ? (flags | flag) : (flags & ~flag)); + store((val ? (load() | flags) : (load() & ~flags))); return *this; } // Clear or flags. - FlagSet &reset() + forceinline FlagSet &reset() { - flags = store_t(0); + store(value_type()); return *this; } // Clear one or more flags. - FlagSet &reset(enum_t flag) + forceinline FlagSet &reset(value_type flags) { - flags = static_cast<store_t>(flags & ~flag); + store(load() & ~flags); return *this; } // Toggle all flags. - FlagSet &flip() + forceinline FlagSet &flip() { - flags = ~flags; + store(~load()); return *this; } // Toggle one or more flags. - FlagSet &flip(enum_t flag) + forceinline FlagSet &flip(value_type flags) { - flags = static_cast<store_t>(flags ^ flag); + store(load() ^ flags); return *this; } + // Returns the size of the flag set in bytes + forceinline std::size_t size() const + { + return sizeof(store_type); + } + // Returns the size of the flag set in bits - size_t size() const + forceinline std::size_t size_bits() const { - return sizeof(enum_t) * 8; + return size() * 8; } - + // Test if one or more flags are set. Returns true if at least one of the given flags is set. - bool test(enum_t flag) const + forceinline bool test(value_type flags) const { - return (flags & static_cast<store_t>(flag)) > 0; + return (load() & flags); } // Test if all specified flags are set. - bool test_all(enum_t flag) const + forceinline bool test_all(value_type flags) const { - return (flags & static_cast<store_t>(flag)) == static_cast<store_t>(flag); + return (load() & flags) == flags; } // Test if any flag is set. - bool any() const + forceinline bool any() const { - return flags > 0; + return load(); } // Test if no flags are set. - bool none() const + forceinline bool none() const { - return flags == 0; + return !load(); } + + forceinline store_type GetRaw() const + { + return bits_; + } - FlagSet<enum_t, store_t> &operator = (const enum_t other) + forceinline void SetRaw(store_type flags) { - flags = static_cast<store_t>(other); + bits_ = flags; + } + + forceinline FlagSet &operator = (value_type flags) + { + store(flags); return *this; } + + forceinline FlagSet &operator = (enum_type flag) + { + store(flag); + return *this; + } - FlagSet<enum_t, store_t> &operator &= (const enum_t other) + forceinline FlagSet &operator = (FlagSet flags) { - flags &= static_cast<store_t>(other); + store(flags.load()); return *this; } - FlagSet<enum_t, store_t> &operator |= (const enum_t other) + forceinline FlagSet &operator &= (value_type flags) { - flags |= static_cast<store_t>(other); + store(load() & flags); return *this; } - store_t GetRaw() const + forceinline FlagSet &operator |= (value_type flags) { - return flags; + store(load() | flags); + return *this; } - void SetRaw(store_t flags_) + forceinline FlagSet &operator ^= (value_type flags) { - flags = flags_; + store(load() ^ flags); + return *this; } + + friend forceinline bool operator == (self_type a, self_type b) { return a.load() == b.load(); } + friend forceinline bool operator != (self_type a, self_type b) { return a.load() != b.load(); } -private: - store_t flags; + friend forceinline bool operator == (self_type a, value_type b) { return a.load() == value_type(b); } + friend forceinline bool operator != (self_type a, value_type b) { return a.load() != value_type(b); } + friend forceinline bool operator == (value_type a, self_type b) { return value_type(a) == b.load(); } + friend forceinline bool operator != (value_type a, self_type b) { return value_type(a) != b.load(); } + + friend forceinline bool operator == (self_type a, enum_type b) { return a.load() == value_type(b); } + friend forceinline bool operator != (self_type a, enum_type b) { return a.load() != value_type(b); } + + friend forceinline bool operator == (enum_type a, self_type b) { return value_type(a) == b.load(); } + friend forceinline bool operator != (enum_type a, self_type b) { return value_type(a) != b.load(); } + + friend forceinline bool operator == (self_type a, Enum<enum_type> b) { return a.load() == value_type(b); } + friend forceinline bool operator != (self_type a, Enum<enum_type> b) { return a.load() != value_type(b); } + + friend forceinline bool operator == (Enum<enum_type> a, self_type b) { return value_type(a) == b.load(); } + friend forceinline bool operator != (Enum<enum_type> a, self_type b) { return value_type(a) != b.load(); } + + friend forceinline const value_type operator | (self_type a, self_type b) { return a.load() | b.load(); } + friend forceinline const value_type operator & (self_type a, self_type b) { return a.load() & b.load(); } + friend forceinline const value_type operator ^ (self_type a, self_type b) { return a.load() ^ b.load(); } + + friend forceinline const value_type operator | (self_type a, value_type b) { return a.load() | value_type(b); } + friend forceinline const value_type operator & (self_type a, value_type b) { return a.load() & value_type(b); } + friend forceinline const value_type operator ^ (self_type a, value_type b) { return a.load() ^ value_type(b); } + + friend forceinline const value_type operator | (value_type a, self_type b) { return value_type(a) | b.load(); } + friend forceinline const value_type operator & (value_type a, self_type b) { return value_type(a) & b.load(); } + friend forceinline const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ b.load(); } + + friend forceinline const value_type operator | (self_type a, enum_type b) { return a.load() | value_type(b); } + friend forceinline const value_type operator & (self_type a, enum_type b) { return a.load() & value_type(b); } + friend forceinline const value_type operator ^ (self_type a, enum_type b) { return a.load() ^ value_type(b); } + + friend forceinline const value_type operator | (enum_type a, self_type b) { return value_type(a) | b.load(); } + friend forceinline const value_type operator & (enum_type a, self_type b) { return value_type(a) & b.load(); } + friend forceinline const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ b.load(); } + + friend forceinline const value_type operator | (self_type a, Enum<enum_type> b) { return a.load() | value_type(b); } + friend forceinline const value_type operator & (self_type a, Enum<enum_type> b) { return a.load() & value_type(b); } + friend forceinline const value_type operator ^ (self_type a, Enum<enum_type> b) { return a.load() ^ value_type(b); } + + friend forceinline const value_type operator | (Enum<enum_type> a, self_type b) { return value_type(a) | b.load(); } + friend forceinline const value_type operator & (Enum<enum_type> a, self_type b) { return value_type(a) & b.load(); } + friend forceinline const value_type operator ^ (Enum<enum_type> a, self_type b) { return value_type(a) ^ b.load(); } + }; -// Declare typesafe logical operators for flag set -#define DECLARE_FLAGSET(enum_t) \ - inline enum_t operator | (enum_t a, enum_t b) { return static_cast<enum_t>(+a | +b); } \ - inline enum_t operator & (enum_t a, enum_t b) { return static_cast<enum_t>(+a & +b); } \ - inline enum_t &operator &= (enum_t &a, enum_t b) { a = (a & b); return a; } \ - inline enum_t &operator |= (enum_t &a, enum_t b) { a = (a | b); return a; } \ - inline enum_t operator ~ (enum_t a) { return static_cast<enum_t>(~(+a)); } +// Declare typesafe logical operators for enum_t +#define MPT_DECLARE_ENUM(enum_t) \ + forceinline enum_value_type<enum_t> operator | (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) | enum_value_type<enum_t>(b); } \ + forceinline enum_value_type<enum_t> operator & (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) & enum_value_type<enum_t>(b); } \ + forceinline enum_value_type<enum_t> operator ^ (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) ^ enum_value_type<enum_t>(b); } \ + forceinline enum_value_type<enum_t> operator ~ (enum_t a) { return ~enum_value_type<enum_t>(a); } \ +/**/ +// backwards compatibility +#define DECLARE_FLAGSET MPT_DECLARE_ENUM + OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/common/typedefs.h =================================================================== --- trunk/OpenMPT/common/typedefs.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/common/typedefs.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -432,6 +432,37 @@ #endif // HAS_TYPE_TRAITS +namespace detail { + +template <std::size_t size> struct int_of_size { }; +template <> struct int_of_size<1> { typedef int8 type; }; +template <> struct int_of_size<2> { typedef int16 type; }; +template <> struct int_of_size<3> { typedef int32 type; }; +template <> struct int_of_size<4> { typedef int32 type; }; +template <> struct int_of_size<5> { typedef int64 type; }; +template <> struct int_of_size<6> { typedef int64 type; }; +template <> struct int_of_size<7> { typedef int64 type; }; +template <> struct int_of_size<8> { typedef int64 type; }; + +template <std::size_t size> struct uint_of_size { }; +template <> struct uint_of_size<1> { typedef uint8 type; }; +template <> struct uint_of_size<2> { typedef uint16 type; }; +template <> struct uint_of_size<3> { typedef uint32 type; }; +template <> struct uint_of_size<4> { typedef uint32 type; }; +template <> struct uint_of_size<5> { typedef uint64 type; }; +template <> struct uint_of_size<6> { typedef uint64 type; }; +template <> struct uint_of_size<7> { typedef uint64 type; }; +template <> struct uint_of_size<8> { typedef uint64 type; }; + +} // namespace detail + +// Simplified version of C++11 std::make_signed and std::make_unsigned: +// - we do not require a C++11 <type_traits> header +// - no support fr CV-qualifiers +// - does not error out on non-integral types +template <typename T> struct make_signed { typedef typename mpt::detail::int_of_size<sizeof(T)>::type type; }; +template <typename T> struct make_unsigned { typedef typename mpt::detail::uint_of_size<sizeof(T)>::type type; }; + } // namespace mpt Modified: trunk/OpenMPT/mptrack/Autotune.cpp =================================================================== --- trunk/OpenMPT/mptrack/Autotune.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Autotune.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -323,10 +323,10 @@ sample.nC5Speed = Util::Round<uint32>(sample.nC5Speed * pitchReference / newFundamentalFreq); - if((modType & (MOD_TYPE_XM | MOD_TYPE_MOD)) != 0) + if((modType & (MOD_TYPE_XM | MOD_TYPE_MOD))) { sample.FrequencyToTranspose(); - if((modType & MOD_TYPE_MOD) != 0) + if((modType & MOD_TYPE_MOD)) { sample.RelativeTone = 0; } Modified: trunk/OpenMPT/mptrack/CommandSet.cpp =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/CommandSet.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -1742,8 +1742,8 @@ }; -CString KeyCombination::GetKeyEventText(KeyEventType event) -//--------------------------------------------------------- +CString KeyCombination::GetKeyEventText(FlagSet<KeyEventType> event) +//------------------------------------------------------------------ { CString text=""; @@ -1989,7 +1989,7 @@ { bool modConflict = (kc1.Modifier()==kc2.Modifier()); bool codeConflict = (kc1.KeyCode()==kc2.KeyCode()); - bool eventConflict = ((kc1.EventType()&kc2.EventType())!=0); + bool eventConflict = ((kc1.EventType()&kc2.EventType())); bool ctxConflict = (kc1.Context() == kc2.Context()); bool crossCxtConflict = IsCrossContextConflict(kc1, kc2); Modified: trunk/OpenMPT/mptrack/CommandSet.h =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/CommandSet.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -60,6 +60,7 @@ kKeyEventRepeat = 1 << 2, kNumKeyEvents = 1 << 3 }; +template <> struct enum_traits<KeyEventType> { typedef uint8 store_type; }; DECLARE_FLAGSET(KeyEventType) @@ -1162,11 +1163,11 @@ STATIC_ASSERT(static_cast<uint8>(kNumKeyEvents - 1) == kNumKeyEvents - 1); public: - KeyCombination(InputTargetContext context = kCtxAllContexts, UINT modifier = 0, UINT key = 0, KeyEventType type = kKeyEventNone) + KeyCombination(InputTargetContext context = kCtxAllContexts, UINT modifier = 0, UINT key = 0, FlagSet<KeyEventType> type = kKeyEventNone) : ctx(static_cast<uint8>(context)) , mod(static_cast<uint8>(modifier)) , code(static_cast<uint8>(key)) - , event(static_cast<uint8>(type)) + , event(type.GetRaw()) { } bool operator== (const KeyCombination &other) const @@ -1197,8 +1198,8 @@ void KeyCode(UINT key) { code = static_cast<uint8>(key); } UINT KeyCode() const { return static_cast<UINT>(code); } - void EventType(KeyEventType type) { event = static_cast<uint8>(type); } - KeyEventType EventType() const { return static_cast<KeyEventType>(event); } + void EventType(FlagSet<KeyEventType> type) { event = type.GetRaw(); } + FlagSet<KeyEventType> EventType() const { FlagSet<KeyEventType> result; result.SetRaw(event); return result; } // Key combination to string static CString GetContextText(InputTargetContext ctx); @@ -1210,7 +1211,7 @@ static CString GetKeyText(UINT mod, UINT code); CString GetKeyText() const { return GetKeyText(Modifier(), KeyCode()); } - static CString GetKeyEventText(KeyEventType event); + static CString GetKeyEventText(FlagSet<KeyEventType> event); CString GetKeyEventText() const { return GetKeyEventText(EventType()); } static bool IsExtended(UINT code); Modified: trunk/OpenMPT/mptrack/Ctrl_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_gen.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_gen.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -206,7 +206,7 @@ //------------------------------------------------------------ { if (pHint == this) return; - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); if (hintType & HINT_MODSEQUENCE) { // Set max valid restart position Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -982,8 +982,8 @@ // Set instrument (and moddoc) as modified. // updateAll: Update all views including this one. Otherwise, only update update other views. -void CCtrlInstruments::SetModified(HintType mask, bool updateAll, bool modified) -//------------------------------------------------------------------------------ +void CCtrlInstruments::SetModified(FlagSet<HintType> mask, bool updateAll, bool modified) +//--------------------------------------------------------------------------------------- { m_modDoc.UpdateAllViews(NULL, InstrumentHint(mask, m_nInstrument), updateAll ? nullptr : this); if(modified) m_modDoc.SetModified(); @@ -1128,7 +1128,7 @@ //--------------------------------------------------------------- { if(pObj == this) return; - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); if (hintType & HINT_MPTOPTIONS) { m_ToolBar.UpdateStyle(); @@ -1169,7 +1169,7 @@ m_SpinMidiPR.EnableWindow(bITandXM); m_SpinMidiBK.EnableWindow(bITandXM); - const bool extendedFadeoutRange = (m_sndFile.GetType() & MOD_TYPE_XM) != 0; + const bool extendedFadeoutRange = (m_sndFile.GetType() & MOD_TYPE_XM); m_SpinFadeOut.EnableWindow(bITandXM); m_SpinFadeOut.SetRange(0, extendedFadeoutRange ? 32767 : 8192); m_EditFadeOut.SetLimitText(extendedFadeoutRange ? 5 : 4); Modified: trunk/OpenMPT/mptrack/Ctrl_ins.h =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_ins.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -122,7 +122,7 @@ virtual ~CCtrlInstruments(); public: - void SetModified(HintType mask, bool updateAll, bool modified = true); + void SetModified(FlagSet<HintType> mask, bool updateAll, bool modified = true); BOOL SetCurrentInstrument(UINT nIns, BOOL bUpdNum=TRUE); BOOL OpenInstrument(const mpt::PathString &fileName); BOOL OpenInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr); Modified: trunk/OpenMPT/mptrack/Ctrl_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -243,7 +243,7 @@ //------------------------------------------------------------ { m_OrderList.UpdateView(hint, pObj); - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); if(hintType & HINT_MODSEQUENCE) { @@ -431,7 +431,7 @@ case CTRLMSG_SETVIEWWND: { SendViewMessage(VIEWMSG_FOLLOWSONG, IsDlgButtonChecked(IDC_PATTERN_FOLLOWSONG)); - SendViewMessage(VIEWMSG_PATTERNLOOP, (SONG_PATTERNLOOP & m_sndFile.m_SongFlags)); + SendViewMessage(VIEWMSG_PATTERNLOOP, (m_sndFile.m_SongFlags & SONG_PATTERNLOOP) ? TRUE : FALSE); OnSpacingChanged(); SendViewMessage(VIEWMSG_SETDETAIL, m_nDetailLevel); SendViewMessage(VIEWMSG_SETRECORD, m_bRecord); Modified: trunk/OpenMPT/mptrack/Ctrl_seq.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -342,7 +342,7 @@ changedPos = true; } else if(m_pParent.GetFollowSong()) { - SongFlags pausedFlags = sndFile.m_SongFlags & (SONG_PAUSED | SONG_STEP | SONG_PATTERNLOOP); + FlagSet<SongFlags> pausedFlags = sndFile.m_SongFlags & (SONG_PAUSED | SONG_STEP | SONG_PATTERNLOOP); sndFile.m_PlayState.m_nCurrentOrder = m_nScrollPos; sndFile.SetCurrentOrder(m_nScrollPos); Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -551,7 +551,7 @@ //----------------------------------------------------------- { if(pObj == this) return; - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); if (hintType & HINT_MPTOPTIONS) { m_ToolBar1.UpdateStyle(); @@ -777,8 +777,8 @@ // updateAll: Update all views including this one. Otherwise, only update update other views. -void CCtrlSamples::SetModified(HintType mask, bool updateAll, bool waveformModified) -//---------------------------------------------------------------------------------- +void CCtrlSamples::SetModified(FlagSet<HintType> mask, bool updateAll, bool waveformModified) +//------------------------------------------------------------------------------------------- { m_modDoc.SetModified(); Modified: trunk/OpenMPT/mptrack/Ctrl_smp.h =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Ctrl_smp.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -128,7 +128,7 @@ afx_msg void OnEnableStretchToSize(); afx_msg void OnEstimateSampleSize(); - void SetModified(HintType mask, bool updateAll, bool waveformModified); + void SetModified(FlagSet<HintType> mask, bool updateAll, bool waveformModified); //}}AFX_MSG DECLARE_MESSAGE_MAP() Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Draw_pat.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Draw_pat.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -231,7 +231,7 @@ { return; } - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); if(hintType & HINT_MPTOPTIONS) { UpdateColors(); Modified: trunk/OpenMPT/mptrack/EffectInfo.cpp =================================================================== --- trunk/OpenMPT/mptrack/EffectInfo.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/EffectInfo.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -27,20 +27,25 @@ ModCommand::PARAM paramMask; // 0 = default ModCommand::PARAM paramValue; // 0 = default ModCommand::PARAM paramLimit; // Parameter Editor limit - MODTYPE supportedFormats; // MOD_TYPE_XXX combo + FlagSet<MODTYPE>::store_type supportedFormats; // MOD_TYPE_XXX combo const char *name; // e.g. "Tone Portamento" + FlagSet<MODTYPE> GetSupportedFormats() const { return FlagSet<MODTYPE>(supportedFormats); } }; -#define MOD_TYPE_MODXM (MOD_TYPE_MOD | MOD_TYPE_XM) -#define MOD_TYPE_S3MIT (MOD_TYPE_S3M | MOD_TYPE_IT) -#define MOD_TYPE_S3MITMPT (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT) -#define MOD_TYPE_NOMOD (MOD_TYPE_S3M | MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT) -#define MOD_TYPE_XMIT (MOD_TYPE_XM | MOD_TYPE_IT) -#define MOD_TYPE_XMITMPT (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT) -#define MOD_TYPE_ITMPT (MOD_TYPE_IT | MOD_TYPE_MPT) -#define MOD_TYPE_ALL ((MODTYPE)~0) +// Force built-in integer operations. +// C++11 constexpr operations on the enum value_type would also solve this. +#define ModType FlagSet<MODTYPE>::store_type +#define MOD_TYPE_MODXM (ModType(0) | MOD_TYPE_MOD | MOD_TYPE_XM) +#define MOD_TYPE_S3MIT (ModType(0) | MOD_TYPE_S3M | MOD_TYPE_IT) +#define MOD_TYPE_S3MITMPT (ModType(0) | MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT) +#define MOD_TYPE_NOMOD (ModType(0) | MOD_TYPE_S3M | MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT) +#define MOD_TYPE_XMIT (ModType(0) | MOD_TYPE_XM | MOD_TYPE_IT) +#define MOD_TYPE_XMITMPT (ModType(0) | MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT) +#define MOD_TYPE_ITMPT (ModType(0) | MOD_TYPE_IT | MOD_TYPE_MPT) +#define MOD_TYPE_ALL (~ModType(0)) + const MPTEFFECTINFO gFXInfo[] = { {CMD_ARPEGGIO, 0,0, 0, MOD_TYPE_ALL, "Arpeggio"}, @@ -118,8 +123,8 @@ // -> DESC="add extended parameter mechanism to pattern effects" {CMD_XPARAM, 0,0, 0, MOD_TYPE_XMITMPT, "Parameter Extension"}, // -! NEW_FEATURE#0010 - {CMD_NOTESLIDEUP, 0,0, 0, MOD_TYPE_IMF | MOD_TYPE_PTM, "Note Slide Up"}, // IMF / PTM effect - {CMD_NOTESLIDEDOWN, 0,0, 0, MOD_TYPE_IMF | MOD_TYPE_PTM, "Note Slide Down"}, // IMF / PTM effect + {CMD_NOTESLIDEUP, 0,0, 0, ModType(0) | MOD_TYPE_IMF | MOD_TYPE_PTM, "Note Slide Up"}, // IMF / PTM effect + {CMD_NOTESLIDEDOWN, 0,0, 0, ModType(0) | MOD_TYPE_IMF | MOD_TYPE_PTM, "Note Slide Down"}, // IMF / PTM effect {CMD_NOTESLIDEUPRETRIG, 0,0, 0, MOD_TYPE_PTM, "Note Slide Up + Retrigger Note"}, // PTM effect {CMD_NOTESLIDEDOWNRETRIG,0,0, 0, MOD_TYPE_PTM, "Note Slide Down + Retrigger Note"}, // PTM effect {CMD_REVERSEOFFSET, 0,0, 0, MOD_TYPE_PTM, "Revert Sample + Offset"}, // PTM effect @@ -155,12 +160,12 @@ // if format is compatible, everything is fine. if not, let's still search // for another command. this fixes searching for the EFx command, which // does different things in MOD format. - if((sndFile.GetType() & gFXInfo[i].supportedFormats) != 0) + if((sndFile.GetType() & gFXInfo[i].GetSupportedFormats())) break; } } if (fxndx == CountOf(gFXInfo)) return false; - bSupported = ((sndFile.GetType() & gFXInfo[fxndx].supportedFormats) != 0); + bSupported = ((sndFile.GetType() & gFXInfo[fxndx].GetSupportedFormats())); if (gFXInfo[fxndx].name) { if ((bXX) && (bSupported)) @@ -228,7 +233,7 @@ && ((param & gFXInfo[i].paramMask) == gFXInfo[i].paramValue)) // Value { ndx = i; - if((sndFile.GetType() & gFXInfo[i].supportedFormats) != 0) + if((sndFile.GetType() & gFXInfo[i].GetSupportedFormats())) break; // found fitting format; this is correct for sure } } @@ -296,7 +301,7 @@ if (s) s[0] = 0; if (prangeMin) *prangeMin = 0; if (prangeMax) *prangeMax = 0; - if ((ndx >= CountOf(gFXInfo)) || (!(sndFile.GetType() & gFXInfo[ndx].supportedFormats))) return FALSE; + if ((ndx >= CountOf(gFXInfo)) || (!(sndFile.GetType() & gFXInfo[ndx].GetSupportedFormats()))) return FALSE; if (s) GetEffectName(s, gFXInfo[ndx].effect, gFXInfo[ndx].paramValue, bXX); if ((prangeMin) && (prangeMax)) { @@ -885,8 +890,9 @@ struct MPTVOLCMDINFO { ModCommand::VOLCMD volCmd; // VOLCMD_XXXX - MODTYPE supportedFormats; // MOD_TYPE_XXX combo + FlagSet<MODTYPE>::store_type supportedFormats; // MOD_TYPE_XXX combo const char *name; // e.g. "Set Volume" + FlagSet<MODTYPE> GetSupportedFormats() const { return FlagSet<MODTYPE>(supportedFormats); } }; const MPTVOLCMDINFO gVolCmdInfo[] = @@ -960,7 +966,7 @@ *prangeMax = (sndFile.GetType() & MOD_TYPE_XM) ? 15 : 9; } } - return (gVolCmdInfo[ndx].supportedFormats & sndFile.GetType()) != 0; + return (sndFile.GetType() & gVolCmdInfo[ndx].GetSupportedFormats()); } Modified: trunk/OpenMPT/mptrack/KeyConfigDlg.cpp =================================================================== --- trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -745,12 +745,12 @@ return; } - KeyEventType event = kKeyEventNone; + FlagSet<KeyEventType> event = kKeyEventNone; if(m_bKeyDown.GetCheck()) event |= kKeyEventDown; if(m_bKeyHold.GetCheck()) event |= kKeyEventRepeat; if(m_bKeyUp.GetCheck()) event |= kKeyEventUp; - KeyCombination kc((commandCategories[m_nCurCategory]).id, m_eCustHotKey.mod, m_eCustHotKey.code, (KeyEventType)event); + KeyCombination kc((commandCategories[m_nCurCategory]).id, m_eCustHotKey.mod, m_eCustHotKey.code, event); //detect invalid input if (!kc.KeyCode()) { Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -530,7 +530,7 @@ CHANGEMODTYPE_WARNING(wLinearSlides); } if(oldTypeIsXM && newTypeIsIT_MPT) m_SndFile.m_SongFlags.set(SONG_ITCOMPATGXX); - m_SndFile.m_SongFlags &= (specs.songFlags | SONG_PLAY_FLAGS); + m_SndFile.m_SongFlags &= (specs.GetSongFlags() | SONG_PLAY_FLAGS); // Adjust mix levels if(newTypeIsMOD || newTypeIsS3M) Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -185,10 +185,10 @@ m_SndFile.ChangeModTypeTo(CTrackApp::GetDefaultDocType()); theApp.GetDefaultMidiMacro(m_SndFile.m_MidiCfg); - m_SndFile.m_SongFlags.set(SONG_LINEARSLIDES & m_SndFile.GetModSpecifications().songFlags); + m_SndFile.m_SongFlags.set(SONG_LINEARSLIDES & m_SndFile.GetModSpecifications().GetSongFlags()); if(!m_SndFile.m_MidiCfg.IsMacroDefaultSetupUsed()) { - m_SndFile.m_SongFlags.set(SONG_EMBEDMIDICFG & m_SndFile.GetModSpecifications().songFlags); + m_SndFile.m_SongFlags.set(SONG_EMBEDMIDICFG & m_SndFile.GetModSpecifications().GetSongFlags()); } @@ -1108,7 +1108,7 @@ chn.nC5Speed = sample.nC5Speed; chn.nLoopStart = sample.nLoopStart; chn.nLoopEnd = sample.nLoopEnd; - chn.dwFlags = static_cast<ChannelFlags>(sample.uFlags) & (CHN_SAMPLEFLAGS & ~CHN_MUTE); + chn.dwFlags = (sample.uFlags & (CHN_SAMPLEFLAGS & ~CHN_MUTE)); chn.nPan = 128; if (sample.uFlags[CHN_PANNING]) chn.nPan = sample.nPan; chn.nInsVol = sample.nGlobalVol; @@ -1212,7 +1212,7 @@ } //end rewbs.vstiLive - const ChannelFlags mask = (fade ? CHN_NOTEFADE : (CHN_NOTEFADE | CHN_KEYOFF)); + const FlagSet<ChannelFlags> mask = (fade ? CHN_NOTEFADE : (CHN_NOTEFADE | CHN_KEYOFF)); ModChannel *pChn = &m_SndFile.m_PlayState.Chn[stopChn != CHANNELINDEX_INVALID ? stopChn : m_SndFile.m_nChannels]; for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++, pChn++) { @@ -1709,7 +1709,7 @@ int nRenderPasses = 1; // Channel mode std::vector<bool> usedChannels; - std::vector<ChannelFlags> channelFlags; + std::vector<FlagSet<ChannelFlags> > channelFlags; // Instrument mode std::vector<bool> instrMuteState; Modified: trunk/OpenMPT/mptrack/Moddoc.h =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Moddoc.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -162,7 +162,7 @@ HWND GetFollowWnd() const { return m_hWndFollow; } void SetFollowWnd(HWND hwnd); - void SetNotifications(Notification::Type type, Notification::Item item = 0) { m_notifyType = type; m_notifyItem = item; } + void SetNotifications(FlagSet<Notification::Type> type, Notification::Item item = 0) { m_notifyType = type; m_notifyItem = item; } FlagSet<Notification::Type, uint16> GetNotificationType() const { return m_notifyType; } Notification::Item GetNotificationItem() const { return m_notifyItem; } Modified: trunk/OpenMPT/mptrack/Notification.h =================================================================== --- trunk/OpenMPT/mptrack/Notification.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/Notification.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -36,7 +36,7 @@ static const uint32 ClipVU = 0x80000000; // Master VU clip indicator bit (sound output has previously clipped) int64 timestampSamples; - FlagSet<Type, uint16> type; + FlagSet<Notification::Type> type; Item item; // Sample or instrument number, depending on type ROWINDEX row; // Always valid uint32 tick; // ditto @@ -47,7 +47,7 @@ uint8 masterVUchannels; // ditto SmpLength pos[MAX_CHANNELS]; // Sample / envelope pos for each channel if != PosInvalid, or pattern channel VUs - Notification(Type t = Default, Item i = 0, int64 s = 0, ROWINDEX r = 0, uint32 ti = 0, ORDERINDEX o = 0, PATTERNINDEX p = 0, uint32 x = 0, uint8 outChannels = 0) : timestampSamples(s), type(t), item(i), row(r), tick(ti), order(o), pattern(p), mixedChannels(x), masterVUchannels(outChannels) + Notification(FlagSet<Notification::Type> t = Default, Item i = 0, int64 s = 0, ROWINDEX r = 0, uint32 ti = 0, ORDERINDEX o = 0, PATTERNINDEX p = 0, uint32 x = 0, uint8 outChannels = 0) : timestampSamples(s), type(t), item(i), row(r), tick(ti), order(o), pattern(p), mixedChannels(x), masterVUchannels(outChannels) { MemsetZero(masterVU); } Modified: trunk/OpenMPT/mptrack/PatternClipboard.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternClipboard.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/PatternClipboard.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -444,7 +444,7 @@ const bool overflowPaste = ((TrackerSettings::Instance().m_dwPatternSetup & PATTERN_OVERFLOWPASTE) && mode != pmPasteFlood && mode != pmPushForward) && !multiPaste; const bool doITStyleMix = (mode == pmMixPasteIT); const bool doMixPaste = (mode == pmMixPaste) || doITStyleMix; - const bool clipboardHasS3MCommands = (pasteFormat & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M)) != 0; + const bool clipboardHasS3MCommands = (pasteFormat & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M)); PatternCursor startPoint(startRow, startChan, PatternCursor::lastColumn), endPoint(startRow, startChan, PatternCursor::firstColumn); ModCommand *patData = sndFile.Patterns[pattern].GetpModCommand(startRow, 0); Modified: trunk/OpenMPT/mptrack/UpdateHints.h =================================================================== --- trunk/OpenMPT/mptrack/UpdateHints.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/UpdateHints.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -62,12 +62,22 @@ else return 1 + PowerOf2Exponent<v / 2>(); } - void Set(HintType type, uint16_t item = 0) + void Set(FlagSet<HintType> type, uint16_t item = 0) { - data = type | item << PowerOf2Exponent<HINT_MAXHINTFLAG>(); + data = type.GetRaw() | item << PowerOf2Exponent<HINT_MAXHINTFLAG>(); } public: + UpdateHint(FlagSet<HintType>::value_type type, uint16_t item = 0) + { + Set(type, item); + } + + UpdateHint(FlagSet<HintType> type, uint16_t item = 0) + { + Set(type, item); + } + UpdateHint(HintType type, uint16_t item = 0) { Set(type, item); @@ -75,7 +85,7 @@ explicit UpdateHint(LPARAM data) : data(static_cast<uint32_t>(data)) { } - HintType GetType() const { return static_cast<HintType>(data & (HINT_MAXHINTFLAG | (HINT_MAXHINTFLAG - 1))); } + FlagSet<HintType> GetType() const { return FlagSet<HintType>(static_cast<FlagSet<HintType>::store_type>(data & (HINT_MAXHINTFLAG | (HINT_MAXHINTFLAG - 1)))); } uint16_t GetData() const { return static_cast<uint16_t>(data >> PowerOf2Exponent<HINT_MAXHINTFLAG>()); } LPARAM AsLPARAM() const { return data; } @@ -85,30 +95,30 @@ struct SampleHint : public UpdateHint { - SampleHint(HintType type, SAMPLEINDEX item) : UpdateHint(type, item) { } + SampleHint(FlagSet<HintType> type, SAMPLEINDEX item) : UpdateHint(type, item) { } }; struct InstrumentHint : public UpdateHint { - InstrumentHint(HintType type, INSTRUMENTINDEX item) : UpdateHint(type, item) { } + InstrumentHint(FlagSet<HintType> type, INSTRUMENTINDEX item) : UpdateHint(type, item) { } }; struct PatternHint : public UpdateHint { - PatternHint(HintType type, PATTERNINDEX item) : UpdateHint(type, item) { } + PatternHint(FlagSet<HintType> type, PATTERNINDEX item) : UpdateHint(type, item) { } }; struct RowHint : public UpdateHint { - RowHint(HintType type, ROWINDEX item) : UpdateHint(type, static_cast<uint16_t>(item)) { } + RowHint(FlagSet<HintType> type, ROWINDEX item) : UpdateHint(type, static_cast<uint16_t>(item)) { } }; struct SequenceHint : public UpdateHint { - SequenceHint(HintType type, SEQUENCEINDEX item) : UpdateHint(type, item) { } + SequenceHint(FlagSet<HintType> type, SEQUENCEINDEX item) : UpdateHint(type, item) { } }; struct ChannelTabHint : public UpdateHint { - ChannelTabHint(HintType type, int item) : UpdateHint(type, static_cast<uint16_t>(item)) { } + ChannelTabHint(FlagSet<HintType> type, int item) : UpdateHint(type, static_cast<uint16_t>(item)) { } }; Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -308,7 +308,7 @@ if (!pModDoc) return; CSoundFile &sndFile = pModDoc->GetrSoundFile(); - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); if (!(hintType & (HINT_MODTYPE|HINT_MODCHANNELS|HINT_MIXPLUGINS))) return; nTabCount = (sndFile.m_nChannels + 3) / 4; if (nTabCount != m_TabCtrl.GetItemCount()) Modified: trunk/OpenMPT/mptrack/View_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_ins.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/View_ins.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -183,8 +183,8 @@ // Set instrument (and moddoc) as modified. // updateAll: Update all views including this one. Otherwise, only update update other views. -void CViewInstrument::SetModified(HintType mask, bool updateAll) -//-------------------------------------------------------------- +void CViewInstrument::SetModified(FlagSet<HintType> mask, bool updateAll) +//----------------------------------------------------------------------- { CModDoc *pModDoc = GetDocument(); if(pModDoc == nullptr) return; @@ -570,7 +570,7 @@ { InstrumentEnvelope &env = ins.GetEnvelope(envelope); - const EnvelopeFlags flags = (ENV_ENABLED | extraFlags); + const FlagSet<EnvelopeFlags> flags = (ENV_ENABLED | extraFlags); env.dwFlags.set(flags, enable); if(enable && !env.nNodes) @@ -781,7 +781,7 @@ { return; } - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); const INSTRUMENTINDEX updateIns = hint.GetData(); if((hintType & (HINT_MPTOPTIONS | HINT_MODTYPE)) || ((hintType & HINT_ENVELOPE) && (m_nInstrument == updateIns || updateIns == 0))) Modified: trunk/OpenMPT/mptrack/View_ins.h =================================================================== --- trunk/OpenMPT/mptrack/View_ins.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/View_ins.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -133,7 +133,7 @@ //////////////////////// // Misc stuff void UpdateScrollSize(); - void SetModified(HintType mask, bool updateAll); + void SetModified(FlagSet<HintType> mask, bool updateAll); BOOL SetCurrentInstrument(INSTRUMENTINDEX nIns, enmEnvelopeTypes m_nEnv = ENV_VOLUME); ModInstrument *GetInstrumentPtr() const; InstrumentEnvelope *GetEnvelopePtr() const; Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -164,8 +164,8 @@ // updateAll: Update all views including this one. Otherwise, only update update other views. -void CViewSample::SetModified(HintType mask, bool updateAll, bool waveformModified) -//--------------------------------------------------------------------------------- +void CViewSample::SetModified(FlagSet<HintType> mask, bool updateAll, bool waveformModified) +//------------------------------------------------------------------------------------------ { CModDoc *pModDoc = GetDocument(); pModDoc->SetModified(); @@ -521,7 +521,7 @@ { return; } - HintType hintType = hint.GetType(); + FlagSet<HintType> hintType = hint.GetType(); const SAMPLEINDEX updateSmp = hint.GetData(); if((hintType & (HINT_MPTOPTIONS | HINT_MODTYPE)) || ((hintType & HINT_SAMPLEDATA) && (m_nSample == updateSmp || updateSmp == 0))) @@ -543,8 +543,8 @@ // Draw one channel of sample data, 1:1 ratio or higher (zoomed in) -void CViewSample::DrawSampleData1(HDC hdc, int ymed, int cx, int cy, SmpLength len, int uFlags, const void *pSampleData) -//---------------------------------------------------------------------------------------------------------------------- +void CViewSample::DrawSampleData1(HDC hdc, int ymed, int cx, int cy, SmpLength len, SampleFlags uFlags, const void *pSampleData) +//------------------------------------------------------------------------------------------------------------------------------ { int smplsize; int yrange = cy/2; @@ -901,8 +901,8 @@ // Draw one channel of zoomed-out sample data -void CViewSample::DrawSampleData2(HDC hdc, int ymed, int cx, int cy, SmpLength len, int uFlags, const void *pSampleData) -//---------------------------------------------------------------------------------------------------------------------- +void CViewSample::DrawSampleData2(HDC hdc, int ymed, int cx, int cy, SmpLength len, SampleFlags uFlags, const void *pSampleData) +//------------------------------------------------------------------------------------------------------------------------------ { int oldsmin, oldsmax; int yrange = cy/2; @@ -1993,7 +1993,7 @@ //------------------------------ { CModDoc *pModDoc = GetDocument(); - HintType updateFlags = HINT_SAMPLEINFO | HINT_SAMPLEDATA; + FlagSet<HintType> updateFlags = HINT_SAMPLEINFO | HINT_SAMPLEDATA; if (!pModDoc) return; CSoundFile &sndFile = pModDoc->GetrSoundFile(); Modified: trunk/OpenMPT/mptrack/View_smp.h =================================================================== --- trunk/OpenMPT/mptrack/View_smp.h 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/View_smp.h 2014-12-03 16:36:24 UTC (rev 4630) @@ -62,7 +62,7 @@ DECLARE_SERIAL(CViewSample) protected: - void SetModified(HintType mask, bool updateAll, bool waveformModified); + void SetModified(FlagSet<HintType> mask, bool updateAll, bool waveformModified); void UpdateScrollSize() { UpdateScrollSize(m_nZoom, true); } void UpdateScrollSize(int newZoom, bool forceRefresh, SmpLength centeredSample = SmpLength(-1)); BOOL SetCurrentSample(SAMPLEINDEX nSmp); @@ -75,8 +75,8 @@ void SetCurSel(SmpLength nBegin, SmpLength nEnd); void ScrollToPosition(int x); void DrawPositionMarks(); - void DrawSampleData1(HDC hdc, int ymed, int cx, int cy, SmpLength len, int uFlags, const void *pSampleData); - void DrawSampleData2(HDC hdc, int ymed, int cx, int cy, SmpLength len, int uFlags, const void *pSampleData); + void DrawSampleData1(HDC hdc, int ymed, int cx, int cy, SmpLength len, SampleFlags uFlags, const void *pSampleData); + void DrawSampleData2(HDC hdc, int ymed, int cx, int cy, SmpLength len, SampleFlags uFlags, const void *pSampleData); void DrawNcButton(CDC *pDC, UINT nBtn); BOOL GetNcButtonRect(UINT nBtn, LPRECT lpRect); void UpdateNcButtonState(); Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -744,7 +744,7 @@ TCHAR s[256], stmp[256]; TV_ITEM tvi; MemsetZero(tvi); - const HintType hintFlagPart = hint.GetType(); + const FlagSet<HintType> hintFlagPart = hint.GetType(); if (IsSampleBrowser() || !hintFlagPart) return; const CModDoc &modDoc = info.modDoc; @@ -2313,7 +2313,7 @@ } } // what should be updated? - HintType hintFlags = (updateSamples ? HINT_SAMPLEINFO : HINT_NONE) | (updateInstruments ? HINT_INSTRUMENT : HINT_NONE); + FlagSet<HintType> hintFlags = (updateSamples ? HINT_SAMPLEINFO : HINT_NONE) | (updateInstruments ? HINT_INSTRUMENT : HINT_NONE); if(hintFlags != HINT_NONE) UpdateView(*pInfo, hintFlags); } Modified: trunk/OpenMPT/mptrack/dlg_misc.cpp =================================================================== --- trunk/OpenMPT/mptrack/dlg_misc.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/dlg_misc.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -177,9 +177,9 @@ m_CheckBox5.ShowWindow(type != MOD_TYPE_MOD ? SW_SHOW : SW_HIDE); if(allowedFlags[SONG_PT1XMODE]) OnPTModeChanged(); - const bool XMorITorMPT = (type & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT)) != 0; - const bool ITorMPT = (type & (MOD_TYPE_IT | MOD_TYPE_MPT)) != 0; - const bool XM = (type & (MOD_TYPE_XM)) != 0; + const bool XMorITorMPT = (type & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT)); + const bool ITorMPT = (type & (MOD_TYPE_IT | MOD_TYPE_MPT)); + const bool XM = (type & (MOD_TYPE_XM)); // Misc Flags if(ITorMPT) @@ -344,7 +344,7 @@ sndFile.SetMixLevels(static_cast<mixLevels>(m_PlugMixBox.GetItemData(sel))); } - sndFile.SetModFlags(0); + sndFile.SetModFlags(FlagSet<ModSpecificFlag>()); if(IsDlgButtonChecked(IDC_CHK_COMPATPLAY)) sndFile.SetModFlag(MSF_COMPATIBLE_PLAY, true); if(m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)) { Modified: trunk/OpenMPT/mptrack/view_com.cpp =================================================================== --- trunk/OpenMPT/mptrack/view_com.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/mptrack/view_com.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -189,18 +189,19 @@ CModDoc *pModDoc = GetDocument(); LV_COLUMN lvc; LV_ITEM lvi, lvi2; + FlagSet<HintType> hintType = UpdateHint(lHint).GetType(); if ((!pModDoc) || (pSender == this) || (!(m_ItemList.m_hWnd))) return; - if (lHint & HINT_MPTOPTIONS) + if (hintType & HINT_MPTOPTIONS) { m_ToolBar.UpdateStyle(); - lHint &= ~HINT_MPTOPTIONS; + hintType &= ~HINT_MPTOPTIONS; } - lHint &= (HINT_MODTYPE + hintType &= (HINT_MODTYPE |HINT_SMPNAMES|HINT_SAMPLEINFO |HINT_INSNAMES|HINT_INSTRUMENT /*|HINT_PATNAMES|HINT_PATTERNROW*/); // pattern stuff currently unused - if (!lHint) return; + if (!hintType) return; const CSoundFile &sndFile = pModDoc->GetrSoundFile(); @@ -208,7 +209,7 @@ m_ItemList.SetRedraw(FALSE); // Add sample headers - if ((m_nListId != m_nCurrentListId) || (lHint & HINT_MODTYPE)) + if ((m_nListId != m_nCurrentListId) || (hintType & HINT_MODTYPE)) { UINT ichk = 0; m_ItemList.DeleteAllItems(); @@ -246,12 +247,12 @@ nCol++; } } else - lHint |= HINT_MODTYPE; + hintType |= HINT_MODTYPE; } // Add Items UINT nCount = m_ItemList.GetItemCount(); // Add Samples - if ((m_nCurrentListId == IDC_LIST_SAMPLES) && (lHint & (HINT_MODTYPE|HINT_SMPNAMES|HINT_SAMPLEINFO))) + if ((m_nCurrentListId == IDC_LIST_SAMPLES) && (hintType & (HINT_MODTYPE|HINT_SMPNAMES|HINT_SAMPLEINFO))) { SAMPLEINDEX nMax = static_cast<SAMPLEINDEX>(nCount); if (nMax < sndFile.GetNumSamples()) nMax = sndFile.GetNumSamples(); @@ -354,7 +355,7 @@ } } else // Add Instruments - if ((m_nCurrentListId == IDC_LIST_INSTRUMENTS) && (lHint & (HINT_MODTYPE|HINT_INSNAMES|HINT_INSTRUMENT))) + if ((m_nCurrentListId == IDC_LIST_INSTRUMENTS) && (hintType & (HINT_MODTYPE|HINT_INSNAMES|HINT_INSTRUMENT))) { INSTRUMENTINDEX nMax = static_cast<INSTRUMENTINDEX>(nCount); if (nMax < sndFile.GetNumInstruments()) nMax = sndFile.GetNumInstruments(); @@ -449,7 +450,7 @@ } } else // Add Patterns - if ((m_nCurrentListId == IDC_LIST_PATTERNS) && (lHint & (HINT_MODTYPE|HINT_PATNAMES|HINT_PATTERNROW))) + if ((m_nCurrentListId == IDC_LIST_PATTERNS) && (hintType & (HINT_MODTYPE|HINT_PATNAMES|HINT_PATTERNROW))) { } m_ItemList.SetRedraw(TRUE); Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2014-12-03 16:28:36 UTC (rev 4629) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2014-12-03 16:36:24 UTC (rev 4630) @@ -1194,7 +1194,7 @@ //-------------------------------------------- { MPT_TRACE(); - const FlagSet<AsioFeatures> unsupported((AsioFeatures)(AsioFeatureNoDirectProcess | AsioFeatureOverload | AsioFeatureBufferSizeChange | AsioFeatureSampleRateChange)); + const FlagSet<AsioF... [truncated message content] |