From 7cf153a34b86ddc9a418b4ac3421282f2b8228de Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 May 2021 12:54:03 -0400 Subject: [PATCH] Duplicate MemoryX.h into wxArrayStringEx.h, diff should be empty --- src/wxArrayStringEx.h | 725 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 725 insertions(+) create mode 100644 src/wxArrayStringEx.h diff --git a/src/wxArrayStringEx.h b/src/wxArrayStringEx.h new file mode 100644 index 000000000..c80b74a15 --- /dev/null +++ b/src/wxArrayStringEx.h @@ -0,0 +1,725 @@ +#ifndef __AUDACITY_MEMORY_X_H__ +#define __AUDACITY_MEMORY_X_H__ + +// C++ standard header with a few extensions +#include +#include // Needed for free. +#ifndef safenew +#define safenew new +#endif + +#include + +#if !(_MSC_VER >= 1800 || __cplusplus >= 201402L) +/* replicate the very useful C++14 make_unique for those build environments +that don't implement it yet. +typical usage: +auto p = std::make_unique(ctorArg1, ctorArg2, ... ctorArgN); +p->DoSomething(); +auto q = std::make_unique(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: +std::unique_ptr 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 struct __make_unique_result { + using scalar_case = unique_ptr; + }; + + // Partial specialization of the struct for array case + template struct __make_unique_result { + using array_case = unique_ptr; + using element = X; + }; + + // Now the scalar version of unique_ptr + template inline + typename __make_unique_result::scalar_case + make_unique(Args&&... args) + { + return typename __make_unique_result::scalar_case + { safenew X(forward(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 inline + typename __make_unique_result::array_case + make_unique(size_t count) + { + return typename __make_unique_result::array_case + { safenew typename __make_unique_result::element[count] }; + } +} +#endif + +/* + * ArrayOf + * 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 +class ArrayOf : public std::unique_ptr +{ +public: + ArrayOf() {} + + template + explicit ArrayOf(Integral count, bool initialize = false) + { + static_assert(std::is_unsigned::value, "Unsigned arguments only"); + reinit(count, initialize); + } + + //ArrayOf(const ArrayOf&) PROHIBITED; + ArrayOf(const ArrayOf&) = delete; + ArrayOf(ArrayOf&& that) + : std::unique_ptr < X[] > + (std::move((std::unique_ptr < X[] >&)(that))) + { + } + ArrayOf& operator= (ArrayOf &&that) + { + std::unique_ptr::operator=(std::move(that)); + return *this; + } + ArrayOf& operator= (std::unique_ptr &&that) + { + std::unique_ptr::operator=(std::move(that)); + return *this; + } + + template< typename Integral > + void reinit(Integral count, + bool initialize = false) + { + static_assert(std::is_unsigned::value, "Unsigned arguments only"); + if (initialize) + // Initialize elements (usually, to zero for a numerical type) + std::unique_ptr::reset(safenew X[count]{}); + else + // Avoid the slight initialization overhead + std::unique_ptr::reset(safenew X[count]); + } +}; + +/** + \class ArrayOf + + ArraysOf + + \brief This simplifies arrays of arrays, each array separately allocated with NEW[] + But it might be better to use std::Array, N> for some small constant N + Or use just one array when sub-arrays have a common size and are not large. + */ +template +class ArraysOf : public ArrayOf> +{ +public: + ArraysOf() {} + + template + explicit ArraysOf(Integral N) + : ArrayOf>( N ) + {} + + template + ArraysOf(Integral1 N, Integral2 M, bool initialize = false) + : ArrayOf>( N ) + { + static_assert(std::is_unsigned::value, "Unsigned arguments only"); + static_assert(std::is_unsigned::value, "Unsigned arguments only"); + for (size_t ii = 0; ii < N; ++ii) + (*this)[ii] = ArrayOf{ M, initialize }; + } + + //ArraysOf(const ArraysOf&) PROHIBITED; + ArraysOf(const ArraysOf&) =delete; + ArraysOf& operator= (ArraysOf&& that) + { + ArrayOf>::operator=(std::move(that)); + return *this; + } + + template< typename Integral > + void reinit(Integral count) + { + ArrayOf>::reinit( count ); + } + + template< typename Integral > + void reinit(Integral count, bool initialize) + { + ArrayOf>::reinit( count, initialize ); + } + + template + void reinit(Integral1 countN, Integral2 countM, bool initialize = false) + { + static_assert(std::is_unsigned::value, "Unsigned arguments only"); + static_assert(std::is_unsigned::value, "Unsigned arguments only"); + reinit(countN, false); + for (size_t ii = 0; ii < countN; ++ii) + (*this)[ii].reinit(countM, initialize); + } +}; + +/** + \class Optional + \brief Like a smart pointer, allows for object to not exist (nullptr) + \brief emulating some of std::optional of C++17 + + template class Optional + 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() + */ + +// 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 +#endif +#endif + +template +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; + } + + /// 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 + X& emplace(Args&&... args) + { + // Lose any old value + reset(); + // emplace NEW value + pp = safenew(address()) X(std::forward(args)...); + return **this; + } + + // Destroy any object that was built in it + ~Optional() + { + reset(); + } + + // Pointer-like operators + + /// 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(&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 + +/** + A deleter for pointers obtained with malloc + */ +struct freer { void operator() (void *p) const { free(p); } }; + +/** + A useful alias for holding the result of malloc + */ +template< typename T > +using MallocPtr = std::unique_ptr< T, freer >; + +/** + A useful alias for holding the result of strup and similar + */ +template +using MallocString = std::unique_ptr< Character[], freer >; + +/** + \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 + */ +template +struct Destroyer { + void operator () (T *p) const { if (p) p->Destroy(); } +}; + +/** + \brief a convenience for using Destroyer + */ +template +using Destroy_ptr = std::unique_ptr>; + +/** + \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; ... }); + */ + +// Construct this from any copyable function object, such as a lambda +template +struct Final_action { + Final_action(F f) : clean( f ) {} + ~Final_action() { clean(); } + F clean; +}; + +/// \brief Function template with type deduction lets you construct Final_action +/// without typing any angle brackets +template +Final_action finally (F f) +{ + return Final_action(f); +} + +#include // for wxMin, wxMax +#include + +/** + \brief Structure used by ValueRestorer + */ +template< typename T > +struct RestoreValue { + T oldValue; + void operator () ( T *p ) const { if (p) *p = oldValue; } +}; + + +/** + \brief Set a variable temporarily in a scope + */ +template< typename T > +class ValueRestorer : public std::unique_ptr< T, RestoreValue > +{ + using std::unique_ptr< T, RestoreValue >::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 >( &var, { var } ) + {} + explicit ValueRestorer( T &var, const T& newValue ) + : std::unique_ptr< T, RestoreValue >( &var, { var } ) + { var = newValue; } + ValueRestorer(ValueRestorer &&that) + : std::unique_ptr < T, RestoreValue > ( std::move(that) ) {}; + ValueRestorer & operator= (ValueRestorer &&that) + { + if (this != &that) + std::unique_ptr < T, RestoreValue >::operator=(std::move(that)); + return *this; + } +}; + +/// 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 +>; + +/** + \brief A convenience for use with range-for + */ +template +struct IteratorRange : public std::pair { + using iterator = Iterator; + using reverse_iterator = std::reverse_iterator; + + IteratorRange (const Iterator &a, const Iterator &b) + : std::pair ( a, b ) {} + + IteratorRange (Iterator &&a, Iterator &&b) + : std::pair ( std::move(a), std::move(b) ) {} + + IteratorRange< reverse_iterator > reversal () const + { return { this->rbegin(), this->rend() }; } + + 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 iterator find(const T &t) const + { return std::find(this->begin(), this->end(), t); } + + template long index(const T &t) const + { + auto iter = this->find(t); + if (iter == this->end()) + return -1; + return std::distance(this->begin(), iter); + } + + template bool contains(const T &t) const + { return this->end() != this->find(t); } + + template iterator find_if(const F &f) const + { return std::find_if(this->begin(), this->end(), f); } + + template 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 bool all_of(const F &f) const + { + auto notF = + [&](typename std::iterator_traits::reference v) + { return !f(v); }; + return !this->any_of( notF ); + } + + template bool any_of(const F &f) const + { return this->end() != this->find_if(f); } + + template bool none_of(const F &f) const + { return !this->any_of(f); } + + template 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() ) > + > + 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() ) >, + typename R = decltype( std::declval()( *std::declval() ) ) + > + 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() ) >, + typename R = decltype( std::declval()( *std::declval() ) ) + > + 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() ) >, + typename R = decltype( std::declval()( *std::declval() ) ) + > + 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 ) ); + } +}; + +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( + 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; + } +}; + +// These macros are used widely, so declared here. +#define QUANTIZED_TIME(time, rate) (floor(((double)(time) * (rate)) + 0.5) / (rate)) +// dB - linear amplitude conversions +#define DB_TO_LINEAR(x) (pow(10.0, (x) / 20.0)) +#define LINEAR_TO_DB(x) (20.0 * log10(x)) + +#define MAX_AUDIO (1. - 1./(1<<15)) + +#endif // __AUDACITY_MEMORY_X_H__