audacia/src/MemoryX.h

718 lines
19 KiB
C
Raw Normal View History

#ifndef __AUDACITY_MEMORY_X_H__
#define __AUDACITY_MEMORY_X_H__
// C++ standard header <memory> with a few extensions
#include <memory>
#include <cstdlib> // Needed for free.
2016-03-12 03:42:31 +00:00
#ifndef safenew
#define safenew new
#endif
#include <functional>
#if !(_MSC_VER >= 1800 || __cplusplus >= 201402L)
/* replicate the very useful C++14 make_unique for those build environments
that don't implement it yet.
2021-01-12 09:54:34 +00:00
typical usage:
auto p = std::make_unique<Myclass>(ctorArg1, ctorArg2, ... ctorArgN);
p->DoSomething();
auto q = std::make_unique<Myclass[]>(count);
q[0].DoSomethingElse();
The first hides naked NEW and DELETE from the source code.
The second hides NEW[] and DELETE[]. Both of course ensure destruction if
you don't use something like std::move(p) or q.release(). Both expressions require
that you identify the type only once, which is brief and less error prone.
(Whereas this omission of [] might invite a runtime error:
2016-08-16 17:00:07 +00:00
std::unique_ptr<Myclass> q { safenew Myclass[count] }; )
Some C++11 tricks needed here are (1) variadic argument lists and
(2) making the compile-time dispatch work correctly. You can't have
a partially specialized template function, but you get the effect of that
by other metaprogramming means.
*/
namespace std {
// For overloading resolution
template <typename X> struct __make_unique_result {
using scalar_case = unique_ptr<X>;
};
// Partial specialization of the struct for array case
template <typename X> struct __make_unique_result<X[]> {
using array_case = unique_ptr<X[]>;
using element = X;
};
// Now the scalar version of unique_ptr
template<typename X, typename... Args> inline
typename __make_unique_result<X>::scalar_case
make_unique(Args&&... args)
{
return typename __make_unique_result<X>::scalar_case
{ safenew X(forward<Args>(args)...) };
}
// Now the array version of unique_ptr
// The compile-time dispatch trick is that the non-existence
// of the scalar_case type makes the above overload
// unavailable when the template parameter is explicit
template<typename X> inline
typename __make_unique_result<X>::array_case
make_unique(size_t count)
{
return typename __make_unique_result<X>::array_case
{ safenew typename __make_unique_result<X>::element[count] };
}
}
#endif
/*
* ArrayOf<X>
* Not to be confused with std::array (which takes a fixed size) or std::vector
* This maintains a pointer allocated by NEW X[]. It's cheap: only one pointer,
* with no size and capacity information for resizing as for vector, and if X is
* a built-in numeric or pointer type, by default there is no zero filling at
* allocation time.
*/
template<typename X>
class ArrayOf : public std::unique_ptr<X[]>
{
public:
ArrayOf() {}
template<typename Integral>
explicit ArrayOf(Integral count, bool initialize = false)
{
static_assert(std::is_unsigned<Integral>::value, "Unsigned arguments only");
2016-04-02 17:02:33 +00:00
reinit(count, initialize);
}
Automation: AudacityCommand This is a squash of 50 commits. This merges the capabilities of BatchCommands and Effects using a new AudacityCommand class. AudacityCommand provides one function to specify the parameters, and then we leverage that one function in automation, whether by chains, mod-script-pipe or (future) Nyquist. - Now have AudacityCommand which is using the same mechanism as Effect - Has configurable parameters - Has data-entry GUI (built using shuttle GUI) - Registers with PluginManager. - Menu commands now provided in chains, and to python batch. - Tested with Zoom Toggle. - ShuttleParams now can set, get, set defaults, validate and specify the parameters. - Bugfix: Don't overwrite values with defaults first time out. - Add DefineParams function for all built-in effects. - Extend CommandContext to carry output channels for results. We abuse EffectsManager. It handles both Effects and AudacityCommands now. In time an Effect should become a special case of AudacityCommand and we'll split and rename the EffectManager class. - Don't use 'default' as a parameter name. - Massive renaming for CommandDefinitionInterface - EffectIdentInterface becomes EffectDefinitionInterface - EffectAutomationParameters becomes CommandAutomationParameters - PluginType is now a bit field. This way we can search for related types at the same time. - Most old batch commands made into AudacityCommands. The ones that weren't are for a reason. They are used by mod-script-pipe to carry commands and responses across from a non-GUI thread to the GUI thread. - Major tidy up of ScreenshotCommand - Reworking of SelectCommand - GetPreferenceCommand and SetPreferenceCommand - GetTrackInfo and SetTrackInfo - GetInfoCommand - Help, Open, Save, Import and Export commands. - Removed obsolete commands ExecMenu, GetProjectInfo and SetProjectInfo which are now better handled by other commands. - JSONify "GetInfo: Commands" output, i.e. commas in the right places. - General work on better Doxygen. - Lyrics -> LyricsPanel - Meter -> MeterPanel - Updated Linux makefile. - Scripting commands added into Extra menu. - Distinct names for previously duplicated find-clipping parameters. - Fixed longstanding error with erroneous status field number which previously caused an ASSERT in debug. - Sensible formatting of numbers in Chains, 0.1 not 0.1000000000137
2018-01-14 18:51:41 +00:00
//ArrayOf(const ArrayOf&) PROHIBITED;
ArrayOf(const ArrayOf&) = delete;
2016-04-02 18:17:20 +00:00
ArrayOf(ArrayOf&& that)
: std::unique_ptr < X[] >
(std::move((std::unique_ptr < X[] >&)(that)))
{
}
ArrayOf& operator= (ArrayOf &&that)
{
std::unique_ptr<X[]>::operator=(std::move(that));
return *this;
}
ArrayOf& operator= (std::unique_ptr<X[]> &&that)
{
std::unique_ptr<X[]>::operator=(std::move(that));
return *this;
}
2016-04-02 17:02:33 +00:00
template< typename Integral >
void reinit(Integral count,
bool initialize = false)
2016-04-02 17:02:33 +00:00
{
static_assert(std::is_unsigned<Integral>::value, "Unsigned arguments only");
2016-04-02 17:02:33 +00:00
if (initialize)
// Initialize elements (usually, to zero for a numerical type)
2016-04-02 17:02:33 +00:00
std::unique_ptr<X[]>::reset(safenew X[count]{});
else
// Avoid the slight initialization overhead
2016-04-02 17:02:33 +00:00
std::unique_ptr<X[]>::reset(safenew X[count]);
}
};
2018-11-04 14:19:05 +00:00
/**
\class ArrayOf
ArraysOf<X>
\brief This simplifies arrays of arrays, each array separately allocated with NEW[]
But it might be better to use std::Array<ArrayOf<X>, N> for some small constant N
Or use just one array when sub-arrays have a common size and are not large.
*/
template<typename X>
class ArraysOf : public ArrayOf<ArrayOf<X>>
{
public:
ArraysOf() {}
template<typename Integral>
explicit ArraysOf(Integral N)
: ArrayOf<ArrayOf<X>>( N )
{}
template<typename Integral1, typename Integral2 >
ArraysOf(Integral1 N, Integral2 M, bool initialize = false)
: ArrayOf<ArrayOf<X>>( N )
{
static_assert(std::is_unsigned<Integral1>::value, "Unsigned arguments only");
static_assert(std::is_unsigned<Integral2>::value, "Unsigned arguments only");
for (size_t ii = 0; ii < N; ++ii)
(*this)[ii] = ArrayOf<X>{ M, initialize };
}
Automation: AudacityCommand This is a squash of 50 commits. This merges the capabilities of BatchCommands and Effects using a new AudacityCommand class. AudacityCommand provides one function to specify the parameters, and then we leverage that one function in automation, whether by chains, mod-script-pipe or (future) Nyquist. - Now have AudacityCommand which is using the same mechanism as Effect - Has configurable parameters - Has data-entry GUI (built using shuttle GUI) - Registers with PluginManager. - Menu commands now provided in chains, and to python batch. - Tested with Zoom Toggle. - ShuttleParams now can set, get, set defaults, validate and specify the parameters. - Bugfix: Don't overwrite values with defaults first time out. - Add DefineParams function for all built-in effects. - Extend CommandContext to carry output channels for results. We abuse EffectsManager. It handles both Effects and AudacityCommands now. In time an Effect should become a special case of AudacityCommand and we'll split and rename the EffectManager class. - Don't use 'default' as a parameter name. - Massive renaming for CommandDefinitionInterface - EffectIdentInterface becomes EffectDefinitionInterface - EffectAutomationParameters becomes CommandAutomationParameters - PluginType is now a bit field. This way we can search for related types at the same time. - Most old batch commands made into AudacityCommands. The ones that weren't are for a reason. They are used by mod-script-pipe to carry commands and responses across from a non-GUI thread to the GUI thread. - Major tidy up of ScreenshotCommand - Reworking of SelectCommand - GetPreferenceCommand and SetPreferenceCommand - GetTrackInfo and SetTrackInfo - GetInfoCommand - Help, Open, Save, Import and Export commands. - Removed obsolete commands ExecMenu, GetProjectInfo and SetProjectInfo which are now better handled by other commands. - JSONify "GetInfo: Commands" output, i.e. commas in the right places. - General work on better Doxygen. - Lyrics -> LyricsPanel - Meter -> MeterPanel - Updated Linux makefile. - Scripting commands added into Extra menu. - Distinct names for previously duplicated find-clipping parameters. - Fixed longstanding error with erroneous status field number which previously caused an ASSERT in debug. - Sensible formatting of numbers in Chains, 0.1 not 0.1000000000137
2018-01-14 18:51:41 +00:00
//ArraysOf(const ArraysOf&) PROHIBITED;
ArraysOf(const ArraysOf&) =delete;
ArraysOf& operator= (ArraysOf&& that)
{
ArrayOf<ArrayOf<X>>::operator=(std::move(that));
return *this;
}
2016-03-31 18:39:01 +00:00
template< typename Integral >
void reinit(Integral count)
{
ArrayOf<ArrayOf<X>>::reinit( count );
}
template< typename Integral >
void reinit(Integral count, bool initialize)
{
ArrayOf<ArrayOf<X>>::reinit( count, initialize );
}
template<typename Integral1, typename Integral2 >
void reinit(Integral1 countN, Integral2 countM, bool initialize = false)
2016-03-31 18:39:01 +00:00
{
static_assert(std::is_unsigned<Integral1>::value, "Unsigned arguments only");
static_assert(std::is_unsigned<Integral2>::value, "Unsigned arguments only");
2016-03-31 18:39:01 +00:00
reinit(countN, false);
for (size_t ii = 0; ii < countN; ++ii)
(*this)[ii].reinit(countM, initialize);
}
};
2018-11-04 14:19:05 +00:00
/**
\class Optional
2018-11-04 14:19:05 +00:00
\brief Like a smart pointer, allows for object to not exist (nullptr)
\brief emulating some of std::optional of C++17
2018-11-04 14:19:05 +00:00
template class Optional<X>
2018-11-04 14:19:05 +00:00
Can be used for monomorphic objects that are stack-allocable, but only conditionally constructed.
You might also use it as a member.
Initialize with emplace(), then use like a smart pointer,
with *, ->, reset(), or in if()
*/
2016-08-16 17:00:07 +00:00
// Placement-NEW is used below, and that does not cooperate with the DEBUG_NEW for Visual Studio
#ifdef _DEBUG
#ifdef _MSC_VER
#undef new
// wx/any.h also uses Placement-NEW so include it before redefining "new" at comment:
// "Restore definition of debug new"
#include <wx/any.h>
#endif
#endif
template<typename X>
class Optional {
public:
using value_type = X;
// Construct as NULL
Optional() {}
// Supply the copy and move, so you might use this as a class member too
Optional(const Optional &that)
{
if (that)
emplace(*that);
}
Optional& operator= (const Optional &that)
{
if (this != &that) {
if (that)
emplace(*that);
else
reset();
}
return *this;
}
Optional(Optional &&that)
{
if (that)
emplace(::std::move(*that));
}
Optional& operator= (Optional &&that)
{
if (this != &that) {
if (that)
emplace(::std::move(*that));
else
reset();
}
return *this;
}
2018-11-04 14:19:05 +00:00
/// Make an object in the buffer, passing constructor arguments,
/// but destroying any previous object first
/// Note that if constructor throws, we remain in a consistent
/// NULL state -- giving exception safety but only weakly
/// (previous value was lost if present)
template<typename... Args>
X& emplace(Args&&... args)
{
// Lose any old value
reset();
// emplace NEW value
pp = safenew(address()) X(std::forward<Args>(args)...);
return **this;
}
// Destroy any object that was built in it
~Optional()
{
reset();
}
// Pointer-like operators
2018-11-04 14:19:05 +00:00
/// Dereference, with the usual bad consequences if NULL
X &operator* () const
{
return *pp;
}
X *operator-> () const
{
return pp;
}
void reset()
{
if (pp)
pp->~X(), pp = nullptr;
}
// So you can say if(ptr)
explicit operator bool() const
{
return pp != nullptr;
}
bool has_value() const
{
return pp != nullptr;
}
private:
X* address()
{
return reinterpret_cast<X*>(&storage);
}
// Data
#if 0
typename ::std::aligned_storage<
sizeof(X)
// , alignof(X) // Not here yet in all compilers
>::type storage{};
#else
union {
double d;
char storage[sizeof(X)];
};
#endif
X* pp{ nullptr };
};
// Restore definition of debug new
#ifdef _DEBUG
#ifdef _MSC_VER
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__;
#define new new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
#endif
#endif
2018-11-04 14:19:05 +00:00
/**
A deleter for pointers obtained with malloc
2016-08-13 15:22:03 +00:00
*/
struct freer { void operator() (void *p) const { free(p); } };
2018-11-04 14:19:05 +00:00
/**
A useful alias for holding the result of malloc
2016-08-13 15:22:03 +00:00
*/
template< typename T >
using MallocPtr = std::unique_ptr< T, freer >;
2018-11-04 14:19:05 +00:00
/**
A useful alias for holding the result of strup and similar
2016-08-13 15:22:03 +00:00
*/
template <typename Character = char>
using MallocString = std::unique_ptr< Character[], freer >;
2018-11-04 14:19:05 +00:00
/**
\brief A deleter class to supply the second template parameter of unique_ptr for
classes like wxWindow that should be sent a message called Destroy rather
than be deleted directly
2016-08-10 02:40:21 +00:00
*/
template <typename T>
struct Destroyer {
void operator () (T *p) const { if (p) p->Destroy(); }
};
2018-11-04 14:19:05 +00:00
/**
\brief a convenience for using Destroyer
2016-08-10 02:40:21 +00:00
*/
template <typename T>
using Destroy_ptr = std::unique_ptr<T, Destroyer<T>>;
2018-11-04 14:19:05 +00:00
/**
\brief "finally" as in The C++ Programming Language, 4th ed., p. 358
Useful for defining ad-hoc RAII actions.
typical usage:
auto cleanup = finally([&]{ ... code; ... });
2016-04-10 00:44:38 +00:00
*/
// Construct this from any copyable function object, such as a lambda
template <typename F>
struct Final_action {
Final_action(F f) : clean( f ) {}
2016-04-10 00:44:38 +00:00
~Final_action() { clean(); }
F clean;
};
2018-11-04 14:19:05 +00:00
/// \brief Function template with type deduction lets you construct Final_action
/// without typing any angle brackets
2016-04-10 00:44:38 +00:00
template <typename F>
Final_action<F> finally (F f)
{
return Final_action<F>(f);
}
#include <wx/utils.h> // for wxMin, wxMax
#include <algorithm>
2018-11-04 14:19:05 +00:00
/**
\brief Structure used by ValueRestorer
*/
template< typename T >
struct RestoreValue {
T oldValue;
void operator () ( T *p ) const { if (p) *p = oldValue; }
};
2018-11-04 14:19:05 +00:00
/**
\brief Set a variable temporarily in a scope
*/
template< typename T >
class ValueRestorer : public std::unique_ptr< T, RestoreValue<T> >
{
using std::unique_ptr< T, RestoreValue<T> >::reset; // make private
// But release() remains public and can be useful to commit a changed value
public:
explicit ValueRestorer( T &var )
: std::unique_ptr< T, RestoreValue<T> >( &var, { var } )
{}
explicit ValueRestorer( T &var, const T& newValue )
: std::unique_ptr< T, RestoreValue<T> >( &var, { var } )
{ var = newValue; }
ValueRestorer(ValueRestorer &&that)
: std::unique_ptr < T, RestoreValue<T> > ( std::move(that) ) {};
ValueRestorer & operator= (ValueRestorer &&that)
{
if (this != &that)
std::unique_ptr < T, RestoreValue<T> >::operator=(std::move(that));
return *this;
}
};
2018-11-04 14:19:05 +00:00
/// inline functions provide convenient parameter type deduction
template< typename T >
ValueRestorer< T > valueRestorer( T& var )
{ return ValueRestorer< T >{ var }; }
template< typename T >
ValueRestorer< T > valueRestorer( T& var, const T& newValue )
{ return ValueRestorer< T >{ var, newValue }; }
/**
\brief A convenience for defining iterators that return rvalue types, so that
they cooperate correctly with stl algorithms and std::reverse_iterator
*/
template< typename Value, typename Category = std::forward_iterator_tag >
using ValueIterator = std::iterator<
Category, const Value, ptrdiff_t,
// void pointer type so that operator -> is disabled
void,
// make "reference type" really the same as the value type
const Value
>;
2018-11-04 14:19:05 +00:00
/**
\brief A convenience for use with range-for
2016-08-11 17:06:39 +00:00
*/
template <typename Iterator>
struct IteratorRange : public std::pair<Iterator, Iterator> {
using iterator = Iterator;
using reverse_iterator = std::reverse_iterator<Iterator>;
IteratorRange (const Iterator &a, const Iterator &b)
: std::pair<Iterator, Iterator> ( a, b ) {}
2016-08-11 17:06:39 +00:00
IteratorRange (Iterator &&a, Iterator &&b)
: std::pair<Iterator, Iterator> ( std::move(a), std::move(b) ) {}
IteratorRange< reverse_iterator > reversal () const
{ return { this->rbegin(), this->rend() }; }
2016-08-11 17:06:39 +00:00
Iterator begin() const { return this->first; }
Iterator end() const { return this->second; }
reverse_iterator rbegin() const { return reverse_iterator{ this->second }; }
reverse_iterator rend() const { return reverse_iterator{ this->first }; }
bool empty() const { return this->begin() == this->end(); }
explicit operator bool () const { return !this->empty(); }
size_t size() const { return std::distance(this->begin(), this->end()); }
template <typename T> iterator find(const T &t) const
{ return std::find(this->begin(), this->end(), t); }
2017-10-04 03:55:06 +00:00
template <typename T> long index(const T &t) const
{
auto iter = this->find(t);
if (iter == this->end())
return -1;
return std::distance(this->begin(), iter);
}
template <typename T> bool contains(const T &t) const
{ return this->end() != this->find(t); }
template <typename F> iterator find_if(const F &f) const
{ return std::find_if(this->begin(), this->end(), f); }
2017-10-04 03:55:06 +00:00
template <typename F> long index_if(const F &f) const
{
auto iter = this->find_if(f);
if (iter == this->end())
return -1;
return std::distance(this->begin(), iter);
}
// to do: use std::all_of, any_of, none_of when available on all platforms
template <typename F> bool all_of(const F &f) const
{
auto notF =
[&](typename std::iterator_traits<Iterator>::reference v)
{ return !f(v); };
return !this->any_of( notF );
}
template <typename F> bool any_of(const F &f) const
{ return this->end() != this->find_if(f); }
template <typename F> bool none_of(const F &f) const
{ return !this->any_of(f); }
template<typename T> struct identity
{ const T&& operator () (T &&v) const { return std::forward(v); } };
// Like std::accumulate, but the iterators implied, and with another
// unary operation on the iterator value, pre-composed
template<
typename R,
typename Binary = std::plus< R >,
typename Unary = identity< decltype( *std::declval<Iterator>() ) >
>
R accumulate(
R init,
Binary binary_op = {},
Unary unary_op = {}
) const
{
R result = init;
for (auto&& v : *this)
result = binary_op(result, unary_op(v));
return result;
}
// An overload making it more convenient to use with pointers to member
// functions
template<
typename R,
typename Binary = std::plus< R >,
typename R2, typename C
>
R accumulate(
R init,
Binary binary_op,
R2 (C :: * pmf) () const
) const
{
return this->accumulate( init, binary_op, std::mem_fn( pmf ) );
}
// Some accumulations frequent enough to be worth abbreviation:
template<
typename Unary = identity< decltype( *std::declval<Iterator>() ) >,
typename R = decltype( std::declval<Unary>()( *std::declval<Iterator>() ) )
>
R min( Unary unary_op = {} ) const
{
return this->accumulate(
std::numeric_limits< R >::max(),
(const R&(*)(const R&, const R&)) std::min,
unary_op
);
}
template<
typename R2, typename C,
typename R = R2
>
R min( R2 (C :: * pmf) () const ) const
{
return this->min( std::mem_fn( pmf ) );
}
template<
typename Unary = identity< decltype( *std::declval<Iterator>() ) >,
typename R = decltype( std::declval<Unary>()( *std::declval<Iterator>() ) )
>
R max( Unary unary_op = {} ) const
{
return this->accumulate(
std::numeric_limits< R >::lowest(),
(const R&(*)(const R&, const R&)) std::max,
unary_op
);
}
template<
typename R2, typename C,
typename R = R2
>
R max( R2 (C :: * pmf) () const ) const
{
return this->max( std::mem_fn( pmf ) );
}
template<
typename Unary = identity< decltype( *std::declval<Iterator>() ) >,
typename R = decltype( std::declval<Unary>()( *std::declval<Iterator>() ) )
>
R sum( Unary unary_op = {} ) const
{
return this->accumulate(
R{ 0 },
std::plus< R >{},
unary_op
);
}
template<
typename R2, typename C,
typename R = R2
>
R sum( R2 (C :: * pmf) () const ) const
{
return this->sum( std::mem_fn( pmf ) );
}
2016-08-11 17:06:39 +00:00
};
template< typename Iterator>
IteratorRange< Iterator >
make_iterator_range( const Iterator &i1, const Iterator &i2 )
{
return { i1, i2 };
}
template< typename Container >
IteratorRange< typename Container::iterator >
make_iterator_range( Container &container )
{
return { container.begin(), container.end() };
}
template< typename Container >
IteratorRange< typename Container::const_iterator >
make_iterator_range( const Container &container )
{
return { container.begin(), container.end() };
}
// A utility function building a container of results
template< typename Container, typename Iterator, typename Function >
Container transform_range( Iterator first, Iterator last, Function &&fn )
{
Container result;
std::transform( first, last, std::back_inserter( result ), fn );
return result;
}
// A utility function, often constructing a vector from another vector
template< typename OutContainer, typename InContainer, typename Function >
OutContainer transform_container( InContainer &inContainer, Function &&fn )
{
return transform_range<OutContainer>(
inContainer.begin(), inContainer.end(), fn );
}
// Extend wxArrayString with move operations and construction and insertion from
// std::initializer_list
class wxArrayStringEx : public wxArrayString
{
public:
using wxArrayString::wxArrayString;
wxArrayStringEx() = default;
template< typename Iterator >
wxArrayStringEx( Iterator start, Iterator finish )
{
this->reserve( std::distance( start, finish ) );
while( start != finish )
this->push_back( *start++ );
}
template< typename T >
wxArrayStringEx( std::initializer_list< T > items )
{
this->reserve( this->size() + items.size() );
for ( const auto &item : items )
this->push_back( item );
}
// The move operations can take arguments of the base class wxArrayString
wxArrayStringEx( wxArrayString &&other )
{
swap( other );
}
wxArrayStringEx &operator= ( wxArrayString &&other )
{
if ( this != &other ) {
clear();
swap( other );
}
return *this;
}
using wxArrayString::insert;
template< typename T >
iterator insert( const_iterator pos, std::initializer_list< T > items )
{
const auto index = pos - ((const wxArrayString*)this)->begin();
this->wxArrayString::Insert( {}, index, items.size() );
auto result = this->begin() + index, iter = result;
for ( auto pItem = items.begin(), pEnd = items.end();
pItem != pEnd;
++pItem, ++iter
) {
*iter = *pItem;
}
return result;
}
};
#endif // __AUDACITY_MEMORY_X_H__