From cf37d92442ccf3c7f4b979bd97282dcbe28ca64a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 10 Dec 2023 12:58:18 -0800 Subject: Refactor FlexArray This avoids using an array of 1 as a flexible array member, and instead uses a span to reference the memory after itself. --- common/flexarray.h | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 common/flexarray.h (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h new file mode 100644 index 00000000..d02a7342 --- /dev/null +++ b/common/flexarray.h @@ -0,0 +1,113 @@ +#ifndef AL_FLEXARRAY_H +#define AL_FLEXARRAY_H + +#include +#include + +#include "almalloc.h" +#include "alspan.h" + +namespace al { + +/* Storage for flexible array data. This is trivially destructible if type T is + * trivially destructible. + */ +template::value> +struct FlexArrayStorage { + alignas(alignment) const ::al::span mData; + + static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept + { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } + + FlexArrayStorage(size_t size) : mData{::new(static_cast(this+1)) T[size], size} { } + ~FlexArrayStorage() = default; + + FlexArrayStorage(const FlexArrayStorage&) = delete; + FlexArrayStorage& operator=(const FlexArrayStorage&) = delete; +}; + +template +struct FlexArrayStorage { + alignas(alignment) const ::al::span mData; + + static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept + { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } + + FlexArrayStorage(size_t size) : mData{::new(static_cast(this+1)) T[size], size} { } + ~FlexArrayStorage() { std::destroy(mData.begin(), mData.end()); } + + FlexArrayStorage(const FlexArrayStorage&) = delete; + FlexArrayStorage& operator=(const FlexArrayStorage&) = delete; +}; + +/* A flexible array type. Used either standalone or at the end of a parent + * struct, with placement new, to have a run-time-sized array that's embedded + * with its size. + */ +template +struct FlexArray { + using element_type = T; + using value_type = std::remove_cv_t; + using index_type = size_t; + using difference_type = ptrdiff_t; + + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + using Storage_t_ = FlexArrayStorage; + + Storage_t_ mStore; + + static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept + { return Storage_t_::Sizeof(count, base); } + static std::unique_ptr Create(index_type count) + { + void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))}; + return std::unique_ptr{al::construct_at(static_cast(ptr), count)}; + } + + FlexArray(index_type size) : mStore{size} { } + ~FlexArray() = default; + + [[nodiscard]] auto size() const noexcept -> index_type { return mStore.mData.size(); } + [[nodiscard]] auto empty() const noexcept -> bool { return mStore.mData.empty(); } + + [[nodiscard]] auto data() noexcept -> pointer { return mStore.mData.data(); } + [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.mData.data(); } + + [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore.mData[i]; } + [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore.mData[i]; } + + [[nodiscard]] auto front() noexcept -> reference { return mStore.mData.front(); } + [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.mData.front(); } + + [[nodiscard]] auto back() noexcept -> reference { return mStore.mData.back(); } + [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.mData.back(); } + + [[nodiscard]] auto begin() noexcept -> iterator { return mStore.mData.begin(); } + [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.mData.begin(); } + [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.mData.cbegin(); } + [[nodiscard]] auto end() noexcept -> iterator { return mStore.mData.end(); } + [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.mData.end(); } + [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.mData.cend(); } + + [[nodiscard]] auto rbegin() noexcept -> reverse_iterator { return end(); } + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return end(); } + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return cend(); } + [[nodiscard]] auto rend() noexcept -> reverse_iterator { return begin(); } + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return begin(); } + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); } + + DEF_PLACE_NEWDEL() +}; + +} // namespace al + +#endif /* AL_FLEXARRAY_H */ -- cgit v1.2.3 From 41266e96aeb0cac54d05a9e57dcea0990933dd33 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Dec 2023 18:54:53 -0800 Subject: Remove unnecessary macro parameter lists --- al/buffer.h | 2 +- al/effect.h | 2 +- al/filter.h | 2 +- al/listener.h | 2 +- al/source.h | 4 ++-- common/almalloc.h | 10 +++++----- common/flexarray.h | 2 +- core/device.h | 2 +- core/hrtf.h | 2 +- core/mastering.h | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) (limited to 'common/flexarray.h') diff --git a/al/buffer.h b/al/buffer.h index cb864aff..2bcab6cf 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -50,7 +50,7 @@ struct ALbuffer : public BufferStorage { static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC #ifdef ALSOFT_EAX EaxStorage eax_x_ram_mode{EaxStorage::Automatic}; diff --git a/al/effect.h b/al/effect.h index fef03475..71fe9c87 100644 --- a/al/effect.h +++ b/al/effect.h @@ -54,7 +54,7 @@ struct ALeffect { static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC }; void InitEffect(ALeffect *effect); diff --git a/al/filter.h b/al/filter.h index 505900d4..b87e7f03 100644 --- a/al/filter.h +++ b/al/filter.h @@ -51,7 +51,7 @@ struct ALfilter { static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC }; #endif diff --git a/al/listener.h b/al/listener.h index 81532877..a50f118a 100644 --- a/al/listener.h +++ b/al/listener.h @@ -18,7 +18,7 @@ struct ALlistener { float Gain{1.0f}; float mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT}; - DISABLE_ALLOC() + DISABLE_ALLOC }; #endif diff --git a/al/source.h b/al/source.h index 3fd43a5c..69bedda3 100644 --- a/al/source.h +++ b/al/source.h @@ -46,7 +46,7 @@ inline bool sBufferSubDataCompat{false}; struct ALbufferQueueItem : public VoiceBufferItem { ALbuffer *mBuffer{nullptr}; - DISABLE_ALLOC() + DISABLE_ALLOC }; @@ -159,7 +159,7 @@ struct ALsource { static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC #ifdef ALSOFT_EAX public: diff --git a/common/almalloc.h b/common/almalloc.h index 8a976aae..b3d8dd58 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -20,7 +20,7 @@ void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); -#define DISABLE_ALLOC() \ +#define DISABLE_ALLOC \ void *operator new(size_t) = delete; \ void *operator new[](size_t) = delete; \ void operator delete(void*) noexcept = delete; \ @@ -39,9 +39,9 @@ void *al_calloc(size_t alignment, size_t size); void operator delete(void *block) noexcept { al_free(block); } \ void operator delete[](void *block) noexcept { operator delete(block); } -#define DEF_PLACE_NEWDEL() \ - void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \ - void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \ +#define DEF_PLACE_NEWDEL \ + void *operator new(size_t) = delete; \ + void *operator new[](size_t) = delete; \ void operator delete(void *block, void*) noexcept { al_free(block); } \ void operator delete(void *block) noexcept { al_free(block); } \ void operator delete[](void *block, void*) noexcept { al_free(block); } \ @@ -65,7 +65,7 @@ enum FamCount : size_t { }; throw std::bad_alloc(); \ } \ void *operator new[](size_t /*size*/) = delete; \ - void operator delete(void *block, FamCount) { al_free(block); } \ + void operator delete(void *block, FamCount) noexcept { al_free(block); } \ void operator delete(void *block) noexcept { al_free(block); } \ void operator delete[](void* /*block*/) = delete; diff --git a/common/flexarray.h b/common/flexarray.h index d02a7342..c317bfbe 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -105,7 +105,7 @@ struct FlexArray { [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return begin(); } [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); } - DEF_PLACE_NEWDEL() + DEF_PLACE_NEWDEL }; } // namespace al diff --git a/core/device.h b/core/device.h index 668779fa..93d64aef 100644 --- a/core/device.h +++ b/core/device.h @@ -380,7 +380,7 @@ struct DeviceBase { [[nodiscard]] auto channelIdxByName(Channel chan) const noexcept -> uint8_t { return RealOut.ChannelIndex[chan]; } - DISABLE_ALLOC() + DISABLE_ALLOC private: uint renderSamples(const uint numSamples); diff --git a/core/hrtf.h b/core/hrtf.h index c5dc6475..e0263493 100644 --- a/core/hrtf.h +++ b/core/hrtf.h @@ -47,7 +47,7 @@ struct HrtfStore { void add_ref(); void dec_ref(); - DEF_PLACE_NEWDEL() + DEF_PLACE_NEWDEL }; using HrtfStorePtr = al::intrusive_ptr; diff --git a/core/mastering.h b/core/mastering.h index 0d4f5fa1..35480176 100644 --- a/core/mastering.h +++ b/core/mastering.h @@ -66,7 +66,7 @@ struct Compressor { void process(const uint SamplesToDo, FloatBufferLine *OutBuffer); [[nodiscard]] auto getLookAhead() const noexcept -> int { return static_cast(mLookAhead); } - DEF_PLACE_NEWDEL() + DEF_PLACE_NEWDEL /** * The compressor is initialized with the following settings: -- cgit v1.2.3 From f1c5b1a4345c48cb498570dca6a11c4947aa88bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Dec 2023 21:38:20 -0800 Subject: Catch a potential exception to free memory --- common/flexarray.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h index c317bfbe..ad15d554 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -2,6 +2,7 @@ #define AL_FLEXARRAY_H #include +#include #include #include "almalloc.h" @@ -69,11 +70,20 @@ struct FlexArray { { return Storage_t_::Sizeof(count, base); } static std::unique_ptr Create(index_type count) { - void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))}; - return std::unique_ptr{al::construct_at(static_cast(ptr), count)}; + if(void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))}) + { + try { + return std::unique_ptr{::new(ptr) FlexArray{count}}; + } + catch(...) { + al_free(ptr); + throw; + } + } + throw std::bad_alloc(); } - FlexArray(index_type size) : mStore{size} { } + FlexArray(index_type size) noexcept(noexcept(Storage_t_{size})) : mStore{size} { } ~FlexArray() = default; [[nodiscard]] auto size() const noexcept -> index_type { return mStore.mData.size(); } -- cgit v1.2.3 From bfd9323d4a1253dc32be5720e769d22b40712135 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Dec 2023 22:13:36 -0800 Subject: Mark constructors noexcept as needed --- common/flexarray.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h index ad15d554..9b6fcc63 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -20,7 +20,9 @@ struct FlexArrayStorage { static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } - FlexArrayStorage(size_t size) : mData{::new(static_cast(this+1)) T[size], size} { } + FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v) + : mData{::new(static_cast(this+1)) T[size], size} + { } ~FlexArrayStorage() = default; FlexArrayStorage(const FlexArrayStorage&) = delete; @@ -34,7 +36,9 @@ struct FlexArrayStorage { static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } - FlexArrayStorage(size_t size) : mData{::new(static_cast(this+1)) T[size], size} { } + FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v) + : mData{::new(static_cast(this+1)) T[size], size} + { } ~FlexArrayStorage() { std::destroy(mData.begin(), mData.end()); } FlexArrayStorage(const FlexArrayStorage&) = delete; @@ -83,7 +87,9 @@ struct FlexArray { throw std::bad_alloc(); } - FlexArray(index_type size) noexcept(noexcept(Storage_t_{size})) : mStore{size} { } + FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v) + : mStore{size} + { } ~FlexArray() = default; [[nodiscard]] auto size() const noexcept -> index_type { return mStore.mData.size(); } -- cgit v1.2.3 From 205a73876234c0b1363189306530ada73ece56f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Dec 2023 22:37:12 -0800 Subject: Try to start being a bit more pointer-owner conscious --- al/auxeffectslot.cpp | 25 +++++++---------- al/buffer.cpp | 3 +- al/effect.cpp | 3 +- al/filter.cpp | 3 +- alc/alc.cpp | 2 +- alc/backends/wave.cpp | 78 +++++++++++++++++++++++++-------------------------- alc/context.h | 4 +-- alc/device.h | 6 ++-- common/almalloc.cpp | 12 ++++---- common/almalloc.h | 59 +++++++++++++++++++++++++------------- common/flexarray.h | 4 +-- core/context.cpp | 24 +++++----------- 12 files changed, 115 insertions(+), 108 deletions(-) (limited to 'common/flexarray.h') diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 408b742b..ea41a842 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -155,19 +155,17 @@ void AddActiveEffectSlots(const al::span auxslots, ALCcontext *co */ if(newcount < newarray->size()) UNLIKELY { - curarray = newarray; + std::unique_ptr oldarray{newarray}; newarray = EffectSlot::CreatePtrArray(newcount); - std::copy_n(curarray->begin(), newcount, newarray->begin()); - delete curarray; - curarray = nullptr; + std::copy_n(oldarray->begin(), newcount, newarray->begin()); } std::uninitialized_fill_n(newarray->end(), newcount, nullptr); - curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + std::unique_ptr oldarray{context->mActiveAuxSlots.exchange(newarray, + std::memory_order_acq_rel)}; std::ignore = context->mDevice->waitForMix(); - std::destroy_n(curarray->end(), curarray->size()); - delete curarray; + std::destroy_n(oldarray->end(), oldarray->size()); } void RemoveActiveEffectSlots(const al::span auxslots, ALCcontext *context) @@ -193,20 +191,17 @@ void RemoveActiveEffectSlots(const al::span auxslots, ALCcontext auto newsize = static_cast(std::distance(newarray->begin(), new_end)); if(newsize != newarray->size()) LIKELY { - curarray = newarray; + std::unique_ptr oldarray{newarray}; newarray = EffectSlot::CreatePtrArray(newsize); - std::copy_n(curarray->begin(), newsize, newarray->begin()); - - delete curarray; - curarray = nullptr; + std::copy_n(oldarray->begin(), newsize, newarray->begin()); } std::uninitialized_fill_n(newarray->end(), newsize, nullptr); - curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + std::unique_ptr oldarray{context->mActiveAuxSlots.exchange(newarray, + std::memory_order_acq_rel)}; std::ignore = context->mDevice->waitForMix(); std::destroy_n(curarray->end(), curarray->size()); - delete curarray; } @@ -251,7 +246,7 @@ bool EnsureEffectSlots(ALCcontext *context, size_t needed) context->mEffectSlotList.emplace_back(); auto sublist = context->mEffectSlotList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->EffectSlots = static_cast( + sublist->EffectSlots = static_cast>( al_calloc(alignof(ALeffectslot), sizeof(ALeffectslot)*64)); if(!sublist->EffectSlots) UNLIKELY { diff --git a/al/buffer.cpp b/al/buffer.cpp index e577e17a..c0f3f348 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -186,7 +186,8 @@ bool EnsureBuffers(ALCdevice *device, size_t needed) device->BufferList.emplace_back(); auto sublist = device->BufferList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Buffers = static_cast(al_calloc(alignof(ALbuffer), sizeof(ALbuffer)*64)); + sublist->Buffers = static_cast>(al_calloc(alignof(ALbuffer), + sizeof(ALbuffer)*64)); if(!sublist->Buffers) UNLIKELY { device->BufferList.pop_back(); diff --git a/al/effect.cpp b/al/effect.cpp index c33faa2c..c2a2d1b1 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -134,7 +134,8 @@ bool EnsureEffects(ALCdevice *device, size_t needed) device->EffectList.emplace_back(); auto sublist = device->EffectList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Effects = static_cast(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64)); + sublist->Effects = static_cast>(al_calloc(alignof(ALeffect), + sizeof(ALeffect)*64)); if(!sublist->Effects) UNLIKELY { device->EffectList.pop_back(); diff --git a/al/filter.cpp b/al/filter.cpp index 9c8e4c62..ce37b0aa 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -129,7 +129,8 @@ bool EnsureFilters(ALCdevice *device, size_t needed) device->FilterList.emplace_back(); auto sublist = device->FilterList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Filters = static_cast(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64)); + sublist->Filters = static_cast>(al_calloc(alignof(ALfilter), + sizeof(ALfilter)*64)); if(!sublist->Filters) UNLIKELY { device->FilterList.pop_back(); diff --git a/alc/alc.cpp b/alc/alc.cpp index e9d3aed7..64b77080 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2735,7 +2735,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(oldarray != &DeviceBase::sEmptyContextArray) { std::ignore = dev->waitForMix(); - delete oldarray; + newarray.reset(oldarray); } } statelock.unlock(); diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 95064906..60cebd7f 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -55,6 +55,11 @@ using std::chrono::nanoseconds; using ubyte = unsigned char; using ushort = unsigned short; +struct FileDeleter { + void operator()(FILE *f) { fclose(f); } +}; +using FilePtr = std::unique_ptr; + /* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char waveDevice[] = "Wave File Writer"; @@ -102,7 +107,7 @@ struct WaveBackend final : public BackendBase { void start() override; void stop() override; - FILE *mFile{nullptr}; + FilePtr mFile{nullptr}; long mDataStart{-1}; std::vector mBuffer; @@ -111,12 +116,7 @@ struct WaveBackend final : public BackendBase { std::thread mThread; }; -WaveBackend::~WaveBackend() -{ - if(mFile) - fclose(mFile); - mFile = nullptr; -} +WaveBackend::~WaveBackend() = default; int WaveBackend::mixerProc() { @@ -168,8 +168,8 @@ int WaveBackend::mixerProc() } } - const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)}; - if(fs < mDevice->UpdateSize || ferror(mFile)) + const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile.get())}; + if(fs < mDevice->UpdateSize || ferror(mFile.get())) { ERR("Error writing to file\n"); mDevice->handleDisconnect("Failed to write playback samples"); @@ -211,10 +211,10 @@ void WaveBackend::open(std::string_view name) #ifdef _WIN32 { std::wstring wname{utf8_to_wstr(fname.value())}; - mFile = _wfopen(wname.c_str(), L"wb"); + mFile.reset(_wfopen(wname.c_str(), L"wb")); } #else - mFile = fopen(fname->c_str(), "wb"); + mFile.reset(fopen(fname->c_str(), "wb")); #endif if(!mFile) throw al::backend_exception{al::backend_error::DeviceError, "Could not open file '%s': %s", @@ -228,8 +228,8 @@ bool WaveBackend::reset() uint channels{0}, bytes{0}, chanmask{0}; bool isbformat{false}; - fseek(mFile, 0, SEEK_SET); - clearerr(mFile); + fseek(mFile.get(), 0, SEEK_SET); + clearerr(mFile.get()); if(GetConfigValueBool({}, "wave", "bformat", false)) { @@ -280,48 +280,48 @@ bool WaveBackend::reset() bytes = mDevice->bytesFromFmt(); channels = mDevice->channelsFromFmt(); - rewind(mFile); + rewind(mFile.get()); - fputs("RIFF", mFile); - fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close + fputs("RIFF", mFile.get()); + fwrite32le(0xFFFFFFFF, mFile.get()); // 'RIFF' header len; filled in at close - fputs("WAVE", mFile); + fputs("WAVE", mFile.get()); - fputs("fmt ", mFile); - fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE + fputs("fmt ", mFile.get()); + fwrite32le(40, mFile.get()); // 'fmt ' header len; 40 bytes for EXTENSIBLE // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, mFile); + fwrite16le(0xFFFE, mFile.get()); // 16-bit val, channel count - fwrite16le(static_cast(channels), mFile); + fwrite16le(static_cast(channels), mFile.get()); // 32-bit val, frequency - fwrite32le(mDevice->Frequency, mFile); + fwrite32le(mDevice->Frequency, mFile.get()); // 32-bit val, bytes per second - fwrite32le(mDevice->Frequency * channels * bytes, mFile); + fwrite32le(mDevice->Frequency * channels * bytes, mFile.get()); // 16-bit val, frame size - fwrite16le(static_cast(channels * bytes), mFile); + fwrite16le(static_cast(channels * bytes), mFile.get()); // 16-bit val, bits per sample - fwrite16le(static_cast(bytes * 8), mFile); + fwrite16le(static_cast(bytes * 8), mFile.get()); // 16-bit val, extra byte count - fwrite16le(22, mFile); + fwrite16le(22, mFile.get()); // 16-bit val, valid bits per sample - fwrite16le(static_cast(bytes * 8), mFile); + fwrite16le(static_cast(bytes * 8), mFile.get()); // 32-bit val, channel mask - fwrite32le(chanmask, mFile); + fwrite32le(chanmask, mFile.get()); // 16 byte GUID, sub-type format std::ignore = fwrite((mDevice->FmtType == DevFmtFloat) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT.data() : SUBTYPE_FLOAT.data()) : - (isbformat ? SUBTYPE_BFORMAT_PCM.data() : SUBTYPE_PCM.data()), 1, 16, mFile); + (isbformat ? SUBTYPE_BFORMAT_PCM.data() : SUBTYPE_PCM.data()), 1, 16, mFile.get()); - fputs("data", mFile); - fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close + fputs("data", mFile.get()); + fwrite32le(0xFFFFFFFF, mFile.get()); // 'data' header len; filled in at close - if(ferror(mFile)) + if(ferror(mFile.get())) { ERR("Error writing header: %s\n", strerror(errno)); return false; } - mDataStart = ftell(mFile); + mDataStart = ftell(mFile.get()); setDefaultWFXChannelOrder(); @@ -333,7 +333,7 @@ bool WaveBackend::reset() void WaveBackend::start() { - if(mDataStart > 0 && fseek(mFile, 0, SEEK_END) != 0) + if(mDataStart > 0 && fseek(mFile.get(), 0, SEEK_END) != 0) WARN("Failed to seek on output file\n"); try { mKillNow.store(false, std::memory_order_release); @@ -353,14 +353,14 @@ void WaveBackend::stop() if(mDataStart > 0) { - long size{ftell(mFile)}; + long size{ftell(mFile.get())}; if(size > 0) { long dataLen{size - mDataStart}; - if(fseek(mFile, 4, SEEK_SET) == 0) - fwrite32le(static_cast(size-8), mFile); // 'WAVE' header len - if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) - fwrite32le(static_cast(dataLen), mFile); // 'data' header len + if(fseek(mFile.get(), 4, SEEK_SET) == 0) + fwrite32le(static_cast(size-8), mFile.get()); // 'WAVE' header len + if(fseek(mFile.get(), mDataStart-4, SEEK_SET) == 0) + fwrite32le(static_cast(dataLen), mFile.get()); // 'data' header len } } } diff --git a/alc/context.h b/alc/context.h index 9f49ceac..d5e5e78b 100644 --- a/alc/context.h +++ b/alc/context.h @@ -70,7 +70,7 @@ struct DebugLogEntry { struct SourceSubList { uint64_t FreeMask{~0_u64}; - ALsource *Sources{nullptr}; /* 64 */ + gsl::owner Sources{nullptr}; /* 64 */ SourceSubList() noexcept = default; SourceSubList(const SourceSubList&) = delete; @@ -85,7 +85,7 @@ struct SourceSubList { struct EffectSlotSubList { uint64_t FreeMask{~0_u64}; - ALeffectslot *EffectSlots{nullptr}; /* 64 */ + gsl::owner EffectSlots{nullptr}; /* 64 */ EffectSlotSubList() noexcept = default; EffectSlotSubList(const EffectSlotSubList&) = delete; diff --git a/alc/device.h b/alc/device.h index 4eb693ff..e5e9b3d2 100644 --- a/alc/device.h +++ b/alc/device.h @@ -35,7 +35,7 @@ using uint = unsigned int; struct BufferSubList { uint64_t FreeMask{~0_u64}; - ALbuffer *Buffers{nullptr}; /* 64 */ + gsl::owner Buffers{nullptr}; /* 64 */ BufferSubList() noexcept = default; BufferSubList(const BufferSubList&) = delete; @@ -50,7 +50,7 @@ struct BufferSubList { struct EffectSubList { uint64_t FreeMask{~0_u64}; - ALeffect *Effects{nullptr}; /* 64 */ + gsl::owner Effects{nullptr}; /* 64 */ EffectSubList() noexcept = default; EffectSubList(const EffectSubList&) = delete; @@ -65,7 +65,7 @@ struct EffectSubList { struct FilterSubList { uint64_t FreeMask{~0_u64}; - ALfilter *Filters{nullptr}; /* 64 */ + gsl::owner Filters{nullptr}; /* 64 */ FilterSubList() noexcept = default; FilterSubList(const FilterSubList&) = delete; diff --git a/common/almalloc.cpp b/common/almalloc.cpp index ad1dc6be..71953d8b 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -13,13 +13,13 @@ #endif -void *al_malloc(size_t alignment, size_t size) +gsl::owner al_malloc(size_t alignment, size_t size) { assert((alignment & (alignment-1)) == 0); alignment = std::max(alignment, alignof(std::max_align_t)); #if defined(HAVE_POSIX_MEMALIGN) - void *ret{}; + gsl::owner ret{}; if(posix_memalign(&ret, alignment, size) == 0) return ret; return nullptr; @@ -41,14 +41,14 @@ void *al_malloc(size_t alignment, size_t size) #endif } -void *al_calloc(size_t alignment, size_t size) +gsl::owner al_calloc(size_t alignment, size_t size) { - void *ret{al_malloc(alignment, size)}; + gsl::owner ret{al_malloc(alignment, size)}; if(ret) std::memset(ret, 0, size); return ret; } -void al_free(void *ptr) noexcept +void al_free(gsl::owner ptr) noexcept { #if defined(HAVE_POSIX_MEMALIGN) std::free(ptr); @@ -56,6 +56,6 @@ void al_free(void *ptr) noexcept _aligned_free(ptr); #else if(ptr != nullptr) - std::free(*(static_cast(ptr) - 1)); + std::free(*(static_cast*>(ptr) - 1)); #endif } diff --git a/common/almalloc.h b/common/almalloc.h index 7ac02bf1..ac4ddfc2 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -13,11 +13,15 @@ #include "pragmadefs.h" -void al_free(void *ptr) noexcept; +namespace gsl { +template using owner = T; +}; + +void al_free(gsl::owner ptr) noexcept; [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]] -void *al_malloc(size_t alignment, size_t size); +gsl::owner al_malloc(size_t alignment, size_t size); [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]] -void *al_calloc(size_t alignment, size_t size); +gsl::owner al_calloc(size_t alignment, size_t size); #define DISABLE_ALLOC \ @@ -29,10 +33,10 @@ void *al_calloc(size_t alignment, size_t size); #define DEF_PLACE_NEWDEL \ void *operator new(size_t) = delete; \ void *operator new[](size_t) = delete; \ - void operator delete(void *block, void*) noexcept { al_free(block); } \ - void operator delete(void *block) noexcept { al_free(block); } \ - void operator delete[](void *block, void*) noexcept { al_free(block); } \ - void operator delete[](void *block) noexcept { al_free(block); } + void operator delete(gsl::owner block, void*) noexcept { al_free(block); } \ + void operator delete(gsl::owner block) noexcept { al_free(block); } \ + void operator delete[](gsl::owner block, void*) noexcept { al_free(block); } \ + void operator delete[](gsl::owner block) noexcept { al_free(block); } enum FamCount : size_t { }; @@ -45,15 +49,22 @@ enum FamCount : size_t { }; sizeof(T)); \ } \ \ - void *operator new(size_t /*size*/, FamCount count) \ + gsl::owner operator new(size_t /*size*/, FamCount count) \ { \ - if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \ - return ret; \ - throw std::bad_alloc(); \ + const auto align = std::align_val_t(alignof(T)); \ + return ::new(align) std::byte[T::Sizeof(count)]; \ } \ void *operator new[](size_t /*size*/) = delete; \ - void operator delete(void *block, FamCount) noexcept { al_free(block); } \ - void operator delete(void *block) noexcept { al_free(block); } \ + void operator delete(gsl::owner block, FamCount) noexcept \ + { \ + const auto align = std::align_val_t(alignof(T)); \ + ::operator delete[](static_cast>(block), align); \ + } \ + void operator delete(gsl::owner block) noexcept \ + { \ + const auto align = std::align_val_t(alignof(T)); \ + ::operator delete[](static_cast>(block), align); \ + } \ void operator delete[](void* /*block*/) = delete; @@ -61,7 +72,8 @@ namespace al { template struct allocator { - static constexpr std::size_t alignment{std::max(Align, alignof(T))}; + static constexpr auto alignment = std::max(Align, alignof(T)); + static constexpr auto AlignVal = std::align_val_t(alignment); using value_type = T; using reference = T&; @@ -81,13 +93,13 @@ struct allocator { template constexpr explicit allocator(const allocator&) noexcept { } - T *allocate(std::size_t n) + gsl::owner allocate(std::size_t n) { if(n > std::numeric_limits::max()/sizeof(T)) throw std::bad_alloc(); - if(auto p = al_malloc(alignment, n*sizeof(T))) return static_cast(p); - throw std::bad_alloc(); + return reinterpret_cast>(::new(AlignVal) std::byte[n*sizeof(T)]); } - void deallocate(T *p, std::size_t) noexcept { al_free(p); } + void deallocate(gsl::owner p, std::size_t) noexcept + { ::operator delete[](reinterpret_cast>(p), AlignVal); } }; template constexpr bool operator==(const allocator&, const allocator&) noexcept { return true; } @@ -111,8 +123,15 @@ constexpr auto to_address(const T &p) noexcept template constexpr T* construct_at(T *ptr, Args&& ...args) - noexcept(std::is_nothrow_constructible::value) -{ return ::new(static_cast(ptr)) T{std::forward(args)...}; } + noexcept(std::is_nothrow_constructible_v) +{ + /* NOLINTBEGIN(cppcoreguidelines-owning-memory) construct_at doesn't + * necessarily handle the address from an owner, while placement new + * expects to. + */ + return ::new(static_cast(ptr)) T{std::forward(args)...}; + /* NOLINTEND(cppcoreguidelines-owning-memory) */ +} } // namespace al diff --git a/common/flexarray.h b/common/flexarray.h index 9b6fcc63..7975a52a 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -74,7 +74,7 @@ struct FlexArray { { return Storage_t_::Sizeof(count, base); } static std::unique_ptr Create(index_type count) { - if(void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))}) + if(gsl::owner ptr{al_calloc(alignof(FlexArray), Sizeof(count))}) { try { return std::unique_ptr{::new(ptr) FlexArray{count}}; @@ -87,7 +87,7 @@ struct FlexArray { throw std::bad_alloc(); } - FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v) + FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v) : mStore{size} { } ~FlexArray() = default; diff --git a/core/context.cpp b/core/context.cpp index 1415857c..b969583b 100644 --- a/core/context.cpp +++ b/core/context.cpp @@ -29,15 +29,12 @@ ContextBase::~ContextBase() { size_t count{0}; ContextProps *cprops{mParams.ContextUpdate.exchange(nullptr, std::memory_order_relaxed)}; - if(cprops) - { + if(std::unique_ptr old{cprops}) ++count; - delete cprops; - } + cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire); - while(cprops) + while(std::unique_ptr old{cprops}) { - std::unique_ptr old{cprops}; cprops = old->next.load(std::memory_order_relaxed); ++count; } @@ -45,21 +42,17 @@ ContextBase::~ContextBase() count = 0; EffectSlotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; - while(eprops) + while(std::unique_ptr old{eprops}) { - std::unique_ptr old{eprops}; eprops = old->next.load(std::memory_order_relaxed); ++count; } TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)}) - { + if(std::unique_ptr curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)}) std::destroy_n(curarray->end(), curarray->size()); - delete curarray; - } - delete mVoices.exchange(nullptr, std::memory_order_relaxed); + std::unique_ptr{mVoices.exchange(nullptr, std::memory_order_relaxed)}; if(mAsyncEvents) { @@ -149,11 +142,8 @@ void ContextBase::allocVoices(size_t addcount) voice_iter = std::transform(cluster->begin(), cluster->end(), voice_iter, [](Voice &voice) noexcept -> Voice* { return &voice; }); - if(auto *oldvoices = mVoices.exchange(newarray.release(), std::memory_order_acq_rel)) - { + if(std::unique_ptr oldvoices{mVoices.exchange(newarray.release(), std::memory_order_acq_rel)}) std::ignore = mDevice->waitForMix(); - delete oldvoices; - } } -- cgit v1.2.3 From cc8dd1c8ce560ef2f7d163f0c98fd95cb352be69 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Dec 2023 08:00:02 -0800 Subject: Avoid placement new for FlexArray --- common/flexarray.h | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h index 7975a52a..b2884639 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -1,6 +1,7 @@ #ifndef AL_FLEXARRAY_H #define AL_FLEXARRAY_H +#include #include #include #include @@ -15,7 +16,7 @@ namespace al { */ template::value> struct FlexArrayStorage { - alignas(alignment) const ::al::span mData; + alignas(std::max(alignment, alignof(::al::span))) const ::al::span mData; static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } @@ -31,7 +32,7 @@ struct FlexArrayStorage { template struct FlexArrayStorage { - alignas(alignment) const ::al::span mData; + alignas(std::max(alignment, alignof(::al::span))) const ::al::span mData; static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } @@ -49,7 +50,7 @@ struct FlexArrayStorage { * struct, with placement new, to have a run-time-sized array that's embedded * with its size. */ -template +template struct FlexArray { using element_type = T; using value_type = std::remove_cv_t; @@ -66,6 +67,7 @@ struct FlexArray { using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + static constexpr size_t alignment{std::max(alignof(T), Align)}; using Storage_t_ = FlexArrayStorage; Storage_t_ mStore; @@ -73,19 +75,7 @@ struct FlexArray { static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { return Storage_t_::Sizeof(count, base); } static std::unique_ptr Create(index_type count) - { - if(gsl::owner ptr{al_calloc(alignof(FlexArray), Sizeof(count))}) - { - try { - return std::unique_ptr{::new(ptr) FlexArray{count}}; - } - catch(...) { - al_free(ptr); - throw; - } - } - throw std::bad_alloc(); - } + { return std::unique_ptr{new(FamCount{count}) FlexArray{count}}; } FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v) : mStore{size} @@ -121,7 +111,16 @@ struct FlexArray { [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return begin(); } [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); } - DEF_PLACE_NEWDEL + gsl::owner operator new(size_t, FamCount count) + { return ::operator new[](Sizeof(count), std::align_val_t{alignof(FlexArray)}); } + void operator delete(gsl::owner block, FamCount) noexcept + { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); } + void operator delete(gsl::owner block) noexcept + { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); } + + void *operator new(size_t size) = delete; + void *operator new[](size_t size) = delete; + void operator delete[](void *block) = delete; }; } // namespace al -- cgit v1.2.3 From a03bfe04c16fa2df0ac86cde53154ca99c18ad53 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jan 2024 08:22:42 -0800 Subject: Remove an unnecessary member variable --- common/flexarray.h | 50 +++++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h index b2884639..09aeef4e 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -15,14 +15,12 @@ namespace al { * trivially destructible. */ template::value> -struct FlexArrayStorage { - alignas(std::max(alignment, alignof(::al::span))) const ::al::span mData; - +struct alignas(std::max(alignment, alignof(al::span))) FlexArrayStorage : al::span { static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v) - : mData{::new(static_cast(this+1)) T[size], size} + : al::span{::new(static_cast(this+1)) T[size], size} { } ~FlexArrayStorage() = default; @@ -31,16 +29,14 @@ struct FlexArrayStorage { }; template -struct FlexArrayStorage { - alignas(std::max(alignment, alignof(::al::span))) const ::al::span mData; - +struct alignas(std::max(alignment, alignof(al::span))) FlexArrayStorage : al::span { static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v) - : mData{::new(static_cast(this+1)) T[size], size} + : al::span{::new(static_cast(this+1)) T[size], size} { } - ~FlexArrayStorage() { std::destroy(mData.begin(), mData.end()); } + ~FlexArrayStorage() { std::destroy(this->begin(), this->end()); } FlexArrayStorage(const FlexArrayStorage&) = delete; FlexArrayStorage& operator=(const FlexArrayStorage&) = delete; @@ -82,33 +78,33 @@ struct FlexArray { { } ~FlexArray() = default; - [[nodiscard]] auto size() const noexcept -> index_type { return mStore.mData.size(); } - [[nodiscard]] auto empty() const noexcept -> bool { return mStore.mData.empty(); } + [[nodiscard]] auto size() const noexcept -> index_type { return mStore.size(); } + [[nodiscard]] auto empty() const noexcept -> bool { return mStore.empty(); } - [[nodiscard]] auto data() noexcept -> pointer { return mStore.mData.data(); } - [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.mData.data(); } + [[nodiscard]] auto data() noexcept -> pointer { return mStore.data(); } + [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.data(); } - [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore.mData[i]; } - [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore.mData[i]; } + [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore[i]; } + [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore[i]; } - [[nodiscard]] auto front() noexcept -> reference { return mStore.mData.front(); } - [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.mData.front(); } + [[nodiscard]] auto front() noexcept -> reference { return mStore.front(); } + [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.front(); } - [[nodiscard]] auto back() noexcept -> reference { return mStore.mData.back(); } - [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.mData.back(); } + [[nodiscard]] auto back() noexcept -> reference { return mStore.back(); } + [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.back(); } - [[nodiscard]] auto begin() noexcept -> iterator { return mStore.mData.begin(); } - [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.mData.begin(); } - [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.mData.cbegin(); } - [[nodiscard]] auto end() noexcept -> iterator { return mStore.mData.end(); } - [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.mData.end(); } - [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.mData.cend(); } + [[nodiscard]] auto begin() noexcept -> iterator { return mStore.begin(); } + [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.cbegin(); } + [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.cbegin(); } + [[nodiscard]] auto end() noexcept -> iterator { return mStore.end(); } + [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.cend(); } + [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.cend(); } [[nodiscard]] auto rbegin() noexcept -> reverse_iterator { return end(); } - [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return end(); } + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return cend(); } [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return cend(); } [[nodiscard]] auto rend() noexcept -> reverse_iterator { return begin(); } - [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return begin(); } + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return cbegin(); } [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); } gsl::owner operator new(size_t, FamCount count) -- cgit v1.2.3 From 936e654b261b4d1cb604a44da534ba385aa10099 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jan 2024 12:56:05 -0800 Subject: Make the flexarray storage span const --- common/flexarray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h index 09aeef4e..3e211f75 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -66,7 +66,7 @@ struct FlexArray { static constexpr size_t alignment{std::max(alignof(T), Align)}; using Storage_t_ = FlexArrayStorage; - Storage_t_ mStore; + const Storage_t_ mStore; static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { return Storage_t_::Sizeof(count, base); } -- cgit v1.2.3 From 2dacf2ddcc60b21a7ac67d8a020082d8f36d39dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Jan 2024 20:17:48 -0800 Subject: Update a comment about FlexArray --- common/flexarray.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'common/flexarray.h') diff --git a/common/flexarray.h b/common/flexarray.h index 3e211f75..b8077988 100644 --- a/common/flexarray.h +++ b/common/flexarray.h @@ -43,8 +43,9 @@ struct alignas(std::max(alignment, alignof(al::span))) FlexArrayStorage struct FlexArray { -- cgit v1.2.3