bsnes-libretro/nall/variant.hpp
Tim Allen 4d7bb510f2 Update to bsnes v107.1 release.
byuu says:

Don't let the point release fool you, there are many significant changes in this
release. I will be keeping bsnes releases using a point system until the new
higan release is ready.

Changelog:

  - GUI: added high DPI support
  - GUI: fixed the state manager image preview
  - Windows: added a new waveOut driver with support for dynamic rate control
  - Windows: corrected the XAudio 2.1 dynamic rate control support [BearOso]
  - Windows: corrected the Direct3D 9.0 fullscreen exclusive window centering
  - Windows: fixed XInput controller support on Windows 10
  - SFC: added high-level emulation for the DSP1, DSP2, DSP4, ST010, and Cx4
    coprocessors
  - SFC: fixed a slight rendering glitch in the intro to Megalomania

If the coprocessor firmware is missing, bsnes will fallback on HLE where it is
supported, which is everything other than SD Gundam GX and the two Hayazashi
Nidan Morita Shougi games.

The Windows dynamic rate control works best with Direct3D in fullscreen
exclusive mode. I recommend the waveOut driver over the XAudio 2.1 driver, as it
is not possible to target a single XAudio2 version on all Windows OS releases.
The waveOut driver should work everywhere out of the box.

Note that with DRC, the synchronization source is your monitor, so you will
want to be running at 60hz (NTSC) or 50hz (PAL). If you have an adaptive sync
monitor, you should instead use the WASAPI (exclusive) or ASIO audio driver.
2019-04-09 11:16:30 +10:00

149 lines
4.8 KiB
C++

#pragma once
namespace nall {
template<typename T, typename... P> struct variant_size {
static constexpr uint size = max(sizeof(T), variant_size<P...>::size);
};
template<typename T> struct variant_size<T> {
static constexpr uint size = sizeof(T);
};
template<uint Index, typename F, typename T, typename... P> struct variant_index {
static constexpr uint index = is_same_v<F, T> ? Index : variant_index<Index + 1, F, P...>::index;
};
template<uint Index, typename F, typename T> struct variant_index<Index, F, T> {
static constexpr uint index = is_same_v<F, T> ? Index : 0;
};
template<typename T, typename... P> struct variant_copy {
constexpr variant_copy(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(*((T*)source));
else variant_copy<P...>(index + 1, assigned, target, source);
}
};
template<typename T> struct variant_copy<T> {
constexpr variant_copy(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(*((T*)source));
}
};
template<typename T, typename... P> struct variant_move {
constexpr variant_move(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(move(*((T*)source)));
else variant_move<P...>(index + 1, assigned, target, source);
}
};
template<typename T> struct variant_move<T> {
constexpr variant_move(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(move(*((T*)source)));
}
};
template<typename T, typename... P> struct variant_destruct {
constexpr variant_destruct(uint index, uint assigned, void* data) {
if(index == assigned) ((T*)data)->~T();
else variant_destruct<P...>(index + 1, assigned, data);
}
};
template<typename T> struct variant_destruct<T> {
constexpr variant_destruct(uint index, uint assigned, void* data) {
if(index == assigned) ((T*)data)->~T();
}
};
template<typename F, typename T, typename... P> struct variant_equals {
constexpr auto operator()(uint index, uint assigned) const -> bool {
if(index == assigned) return is_same_v<F, T>;
return variant_equals<F, P...>()(index + 1, assigned);
}
};
template<typename F, typename T> struct variant_equals<F, T> {
constexpr auto operator()(uint index, uint assigned) const -> bool {
if(index == assigned) return is_same_v<F, T>;
return false;
}
};
template<typename... P> struct variant final { //final as destructor is not virtual
variant() : assigned(0) {}
variant(const variant& source) { operator=(source); }
variant(variant&& source) { operator=(move(source)); }
template<typename T> variant(const T& value) { operator=(value); }
template<typename T> variant(T&& value) { operator=(move(value)); }
~variant() { reset(); }
explicit operator bool() const { return assigned; }
template<typename T> explicit constexpr operator T&() { return get<T>(); }
template<typename T> explicit constexpr operator const T&() const { return get<T>(); }
template<typename T> constexpr auto is() const -> bool {
return variant_equals<T, P...>()(1, assigned);
}
template<typename T> constexpr auto get() -> T& {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
struct variant_bad_cast{};
if(!is<T>()) throw variant_bad_cast{};
return *((T*)data);
}
template<typename T> constexpr auto get() const -> const T& {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
struct variant_bad_cast{};
if(!is<T>()) throw variant_bad_cast{};
return *((const T*)data);
}
template<typename T> constexpr auto get(const T& fallback) const -> const T& {
if(!is<T>()) return fallback;
return *((const T*)data);
}
auto reset() -> void {
if(assigned) variant_destruct<P...>(1, assigned, (void*)data);
assigned = 0;
}
auto& operator=(const variant& source) {
reset();
if(assigned = source.assigned) variant_copy<P...>(1, source.assigned, (void*)data, (void*)source.data);
return *this;
}
auto& operator=(variant&& source) {
reset();
if(assigned = source.assigned) variant_move<P...>(1, source.assigned, (void*)data, (void*)source.data);
source.assigned = 0;
return *this;
}
template<typename T> auto& operator=(const T& value) {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
reset();
new((void*)&data) T(value);
assigned = variant_index<1, T, P...>::index;
return *this;
}
template<typename T> auto& operator=(T&& value) {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
reset();
new((void*)&data) T(move(value));
assigned = variant_index<1, T, P...>::index;
return *this;
}
private:
alignas(P...) char data[variant_size<P...>::size];
uint assigned;
};
}