Make Audacity build in C++17 ...
... Fixing many conditional operators with explicit construction of wxString instead of simple string literals; And fixing allocation of more strictly aligned structures on Mac, without need for 10.14 as the minimum SDK, by means of some class-specific operators new and delete.
This commit is contained in:
parent
e6e81399f7
commit
77dab158c3
|
@ -116,7 +116,7 @@ set( CMAKE_PREFIX_PATH
|
|||
#set( CMAKE_INTERPROCEDURAL_OPTIMIZATION_DEBUG OFF )
|
||||
|
||||
# Set the required C++ standard
|
||||
set( CMAKE_CXX_STANDARD 14 )
|
||||
set( CMAKE_CXX_STANDARD 17 )
|
||||
set( CMAKE_CXX_STANDARD_REQUIRED ON )
|
||||
|
||||
# Use ccache if available
|
||||
|
|
|
@ -107,7 +107,8 @@ public:
|
|||
if (Read(key, &str))
|
||||
{
|
||||
struct lconv *info = localeconv();
|
||||
wxString dec = info ? wxString::FromUTF8(info->decimal_point) : wxT(".");
|
||||
wxString dec =
|
||||
info ? wxString::FromUTF8(info->decimal_point) : wxString(".");
|
||||
|
||||
str.Replace(wxT(","), dec);
|
||||
str.Replace(wxT("."), dec);
|
||||
|
|
|
@ -1,5 +1,58 @@
|
|||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
MemoryX.cpp
|
||||
|
||||
Paul Licameli
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "MemoryX.h"
|
||||
|
||||
// Make the symbol table non-empty
|
||||
UTILITY_API void lib_utility_dummy_symbol()
|
||||
{}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
constexpr auto sizeof_align_val = sizeof(std::align_val_t);
|
||||
|
||||
void *NonInterferingBase::operator new(std::size_t count, std::align_val_t al)
|
||||
{
|
||||
using namespace std;
|
||||
// Get an allocation with sufficient extra space to remember the alignment
|
||||
// (And to do that, adjust the alignment to be not less than the alignment of
|
||||
// an alignment value!).
|
||||
// Also increase the allocation by one entire alignment.
|
||||
al = max( al, static_cast<align_val_t>( alignof(align_val_t) ) );
|
||||
const auto al_as_size = static_cast<size_t>(al);
|
||||
auto ptr = static_cast<char*>(
|
||||
::operator new( count + sizeof_align_val + al_as_size ) );
|
||||
|
||||
// Adjust the pointer to a properly aligned one, with a space just before it
|
||||
// to remember the adjustment
|
||||
ptr += sizeof_align_val;
|
||||
auto integer = reinterpret_cast<uintptr_t>(ptr);
|
||||
const auto partial = integer % al_as_size;
|
||||
auto adjustment = partial ? al_as_size - partial : 0;
|
||||
integer += adjustment;
|
||||
ptr = reinterpret_cast<char*>(integer);
|
||||
|
||||
// Remember the adjustment
|
||||
*(reinterpret_cast<size_t*>(ptr) - 1) = adjustment;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void NonInterferingBase::operator delete(void *ptr, std::align_val_t al)
|
||||
{
|
||||
// Find the adjustment
|
||||
auto adjustment = *(reinterpret_cast<size_t*>(ptr) - 1);
|
||||
// Apply the adjustment
|
||||
auto p = reinterpret_cast<char*>(ptr) - adjustment - sizeof_align_val;
|
||||
// Call through to default operator
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// C++ standard header <memory> with a few extensions
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <new> // align_val_t and hardware_destructive_interference_size
|
||||
#include <cstdlib> // Needed for free.
|
||||
#ifndef safenew
|
||||
#define safenew new
|
||||
|
@ -579,6 +580,36 @@ OutContainer transform_container( InContainer &inContainer, Function &&fn )
|
|||
inContainer.begin(), inContainer.end(), fn );
|
||||
}
|
||||
|
||||
//! Non-template helper for class template NonInterfering
|
||||
/*!
|
||||
If a structure contains any members with large alignment, this base class may also allow it to work in
|
||||
macOS builds under current limitations of the C++17 standard implementation.
|
||||
*/
|
||||
struct UTILITY_API alignas(
|
||||
#ifdef __WIN32__
|
||||
std::hardware_destructive_interference_size
|
||||
#else
|
||||
// That constant isn't defined for the other builds yet
|
||||
64 /* ? */
|
||||
#endif
|
||||
)
|
||||
NonInterferingBase {
|
||||
#ifdef __APPLE__
|
||||
static void *operator new(std::size_t count, std::align_val_t al);
|
||||
static void operator delete(void *ptr, std::align_val_t al);
|
||||
#endif
|
||||
};
|
||||
|
||||
/*! Given a structure type T, derive a structure with sufficient padding so that there is not false sharing of
|
||||
cache lines between successive elements of an array of those structures.
|
||||
*/
|
||||
template< typename T > struct NonInterfering
|
||||
: NonInterferingBase // Inherit operators; use empty base class optimization
|
||||
, T
|
||||
{
|
||||
using T::T;
|
||||
};
|
||||
|
||||
// These macros are used widely, so declared here.
|
||||
#define QUANTIZED_TIME(time, rate) (floor(((double)(time) * (rate)) + 0.5) / (rate))
|
||||
// dB - linear amplitude conversions
|
||||
|
|
|
@ -93,6 +93,6 @@ wxString ActiveProjects::Find(const FilePath &path)
|
|||
|
||||
gPrefs->SetPath(configPath);
|
||||
|
||||
return found ? key : wxT("");
|
||||
return found ? key : wxString{};
|
||||
}
|
||||
|
||||
|
|
|
@ -541,7 +541,7 @@ constexpr size_t TimeQueueGrainSize = 2000;
|
|||
#endif
|
||||
|
||||
|
||||
struct AudioIoCallback::ScrubState
|
||||
struct AudioIoCallback::ScrubState : NonInterferingBase
|
||||
{
|
||||
ScrubState(double t0,
|
||||
double rate,
|
||||
|
|
|
@ -132,12 +132,11 @@ int audacityAudioCallback(
|
|||
// Data must be default-constructible and either copyable or movable.
|
||||
template<typename Data>
|
||||
class MessageBuffer {
|
||||
struct alignas( 64
|
||||
//std::hardware_destructive_interference_size // C++17
|
||||
) UpdateSlot {
|
||||
struct UpdateSlot {
|
||||
std::atomic<bool> mBusy{ false };
|
||||
Data mData;
|
||||
} mSlots[2];
|
||||
};
|
||||
NonInterfering<UpdateSlot> mSlots[2];
|
||||
|
||||
std::atomic<unsigned char> mLastWrittenSlot{ 0 };
|
||||
|
||||
|
@ -566,10 +565,11 @@ protected:
|
|||
// These need not be updated atomically, because we rely on the atomics
|
||||
// in the playback ring buffers to supply the synchronization. Still,
|
||||
// align them to avoid false sharing.
|
||||
alignas(64) struct Cursor {
|
||||
struct Cursor {
|
||||
size_t mIndex {};
|
||||
size_t mRemainder {};
|
||||
} mHead, mTail;
|
||||
};
|
||||
NonInterfering<Cursor> mHead, mTail;
|
||||
|
||||
void Producer(
|
||||
const PlaybackSchedule &schedule, double rate, double scrubSpeed,
|
||||
|
|
|
@ -16,10 +16,10 @@ Paul Licameli split from AudioIO.h
|
|||
|
||||
#include <cfloat>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
#include <wx/weakref.h> // member variable
|
||||
#include "MemoryX.h"
|
||||
|
||||
struct PaDeviceInfo;
|
||||
typedef void PaStream;
|
||||
|
@ -117,6 +117,7 @@ struct AudioIOStartStreamOptions
|
|||
///\brief A singleton object supporting queries of the state of any active
|
||||
/// audio streams, and audio device capabilities
|
||||
class AUDACITY_DLL_API AudioIOBase /* not final */
|
||||
: public NonInterferingBase
|
||||
{
|
||||
public:
|
||||
static AudioIOBase *Get();
|
||||
|
|
|
@ -49,7 +49,7 @@ END_EVENT_TABLE()
|
|||
const wxSize gSize = wxSize(LYRICS_DEFAULT_WIDTH, LYRICS_DEFAULT_HEIGHT);
|
||||
|
||||
LyricsWindow::LyricsWindow(AudacityProject *parent)
|
||||
: wxFrame( &GetProjectFrame( *parent ), -1, {},
|
||||
: wxFrame( &GetProjectFrame( *parent ), -1, wxString{},
|
||||
wxPoint(100, 300), gSize,
|
||||
//v Bug in wxFRAME_FLOAT_ON_PARENT:
|
||||
// If both the project frame and LyricsWindow are minimized and you restore LyricsWindow,
|
||||
|
|
|
@ -1408,7 +1408,7 @@ const wxSize kDefaultSize =
|
|||
wxSize(MIXER_BOARD_MIN_WIDTH, MIXER_BOARD_MIN_HEIGHT);
|
||||
|
||||
MixerBoardFrame::MixerBoardFrame(AudacityProject* parent)
|
||||
: wxFrame( &GetProjectFrame( *parent ), -1, {},
|
||||
: wxFrame( &GetProjectFrame( *parent ), -1, wxString{},
|
||||
wxDefaultPosition, kDefaultSize,
|
||||
wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT)
|
||||
, mProject(parent)
|
||||
|
|
|
@ -3032,7 +3032,7 @@ RegistryPath PluginManager::SettingsPath(const PluginID & ID, bool shared)
|
|||
wxT("_") +
|
||||
plug.GetVendor() +
|
||||
wxT("_") +
|
||||
(shared ? wxT("") : plug.GetSymbol().Internal());
|
||||
(shared ? wxString{} : plug.GetSymbol().Internal());
|
||||
|
||||
return SETROOT +
|
||||
ConvertID(id) +
|
||||
|
|
|
@ -1140,7 +1140,7 @@ FilePath ProjectFileIO::SafetyFileName(const FilePath &src)
|
|||
|
||||
int nn = 1;
|
||||
auto numberString = [](int num) -> wxString {
|
||||
return num == 1 ? "" : wxString::Format(".%d", num);
|
||||
return num == 1 ? wxString{} : wxString::Format(".%d", num);
|
||||
};
|
||||
|
||||
auto suffixes = AuxiliaryFileSuffixes();
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "SampleFormat.h"
|
||||
#include <atomic>
|
||||
|
||||
class RingBuffer {
|
||||
class RingBuffer final : public NonInterferingBase {
|
||||
public:
|
||||
RingBuffer(sampleFormat format, size_t size);
|
||||
~RingBuffer();
|
||||
|
@ -43,16 +43,8 @@ class RingBuffer {
|
|||
size_t Filled( size_t start, size_t end );
|
||||
size_t Free( size_t start, size_t end );
|
||||
|
||||
enum : size_t { CacheLine = 64 };
|
||||
/*
|
||||
// We will do this in C++17 instead:
|
||||
static constexpr size_t CacheLine =
|
||||
std::hardware_destructive_interference_size;
|
||||
*/
|
||||
|
||||
// Align the two atomics to avoid false sharing
|
||||
alignas(CacheLine) std::atomic<size_t> mStart { 0 };
|
||||
alignas(CacheLine) std::atomic<size_t> mEnd{ 0 };
|
||||
NonInterfering< std::atomic<size_t> > mStart { 0 }, mEnd{ 0 };
|
||||
|
||||
const size_t mBufferSize;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ void CommandMessageTarget::EndStruct(){
|
|||
void CommandMessageTarget::AddItem(const wxString &value, const wxString &name){
|
||||
wxString Padding;
|
||||
Padding.Pad( mCounts.size() *2 -2);
|
||||
Padding = (( value.length() < 15 ) || (mCounts.back()<=0)) ? "" : wxString("\n") + Padding;
|
||||
Padding = (( value.length() < 15 ) || (mCounts.back()<=0)) ? wxString{} : wxString("\n") + Padding;
|
||||
if( name.empty() )
|
||||
Update( wxString::Format( "%s%s\"%s\"", (mCounts.back()>0)?", ":"", Padding, Escaped(value)));
|
||||
else
|
||||
|
|
|
@ -242,7 +242,7 @@ TranslatableString NyquistEffect::GetDescription()
|
|||
wxString NyquistEffect::ManualPage()
|
||||
{
|
||||
return mIsPrompt
|
||||
? wxT("Nyquist_Prompt")
|
||||
? wxString("Nyquist_Prompt")
|
||||
: mManPage;
|
||||
}
|
||||
|
||||
|
@ -2183,7 +2183,7 @@ bool NyquistEffect::Parse(
|
|||
ctrl.label = tokens[4];
|
||||
|
||||
// valStr may or may not be a quoted string
|
||||
ctrl.valStr = len > 5 ? tokens[5] : wxT("");
|
||||
ctrl.valStr = len > 5 ? tokens[5] : wxString{};
|
||||
ctrl.val = GetCtrlValue(ctrl.valStr);
|
||||
if (ctrl.valStr.length() > 0 &&
|
||||
(ctrl.valStr[0] == wxT('(') ||
|
||||
|
|
|
@ -244,7 +244,7 @@ void DeviceToolBar::UpdatePrefs()
|
|||
|
||||
int hostSelectionIndex = mHost->GetSelection();
|
||||
wxString oldHost = hostSelectionIndex >= 0 ? mHost->GetString(hostSelectionIndex) :
|
||||
wxT("");
|
||||
wxString{};
|
||||
auto hostName = AudioIOHost.Read();
|
||||
|
||||
// if the prefs host name doesn't match the one displayed, it changed
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include "FileConfig.h"
|
||||
|
||||
#include <cerrno> // for ENOENT
|
||||
|
||||
#if !defined(F_OK)
|
||||
#define F_OK 0x00
|
||||
#endif
|
||||
|
|
|
@ -115,7 +115,7 @@ void FileHistory::Load(wxConfigBase & config, const wxString & group)
|
|||
{
|
||||
mHistory.clear();
|
||||
mGroup = group.empty()
|
||||
? wxT("RecentFiles")
|
||||
? wxString{ "RecentFiles" }
|
||||
: group;
|
||||
|
||||
config.SetPath(mGroup);
|
||||
|
|
|
@ -57,7 +57,7 @@ wxChar NumberFormatter::GetDecimalSeparator()
|
|||
{
|
||||
#if wxUSE_INTL
|
||||
struct lconv *info = localeconv();
|
||||
wxString s = info ? wxString::FromUTF8(info->decimal_point) : wxT(".");
|
||||
wxString s = info ? wxString::FromUTF8(info->decimal_point) : wxString(".");
|
||||
if (s.empty())
|
||||
{
|
||||
// We really must have something for decimal separator, so fall
|
||||
|
@ -75,7 +75,7 @@ bool NumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep)
|
|||
{
|
||||
#if wxUSE_INTL
|
||||
struct lconv *info = localeconv();
|
||||
wxString s = info ? wxString::FromUTF8(info->thousands_sep) : wxT("");
|
||||
wxString s = info ? wxString::FromUTF8(info->thousands_sep) : wxString{};
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue