diff --git a/source/mijin/logging/logger.hpp b/source/mijin/logging/logger.hpp index 4904ae7..5aea0a8 100644 --- a/source/mijin/logging/logger.hpp +++ b/source/mijin/logging/logger.hpp @@ -12,6 +12,7 @@ #include #include "../internal/common.hpp" #include "../util/annot.hpp" +#include "../util/iterators.hpp" namespace mijin { @@ -148,11 +149,8 @@ public: {} BaseLogger(const BaseLogger&) = default; - BaseLogger(BaseLogger&&) = default; - BaseLogger& operator=(const BaseLogger&) = default; - BaseLogger& operator=(BaseLogger&&) = default; void addSink(sink_t& sink) @@ -191,12 +189,28 @@ public: template void log(const level_t& level, const channel_t& channel, std::source_location sourceLocation, - std::basic_format_string...> fmt, TArgs&& ... args) const - MIJIN_NOEXCEPT_IF(noexcept(std::declval().allocate(1))) + std::basic_format_string...> fmt, TArgs&& ... args) const MIJIN_NOEXCEPT { - string_t buffer(allocator_t(mSinks.get_allocator())); - std::format_to(std::back_inserter(buffer), fmt, std::forward(args)...); - log(level, channel, std::move(sourceLocation), buffer.c_str()); + // TODO: make the logger use a traits struct to make this adjustable + static constexpr std::size_t BUFFER_SIZE = 256; + std::array buffer; + + // first try to write into a buffer on the stack + FixedArrayOutputIterator itAfter = std::format_to(FixedArrayOutputIterator(buffer), fmt, std::forward(args)...); + *itAfter = '\0'; + ++itAfter; + if (!itAfter.didOverflow()) + { + log(level, channel, std::move(sourceLocation), buffer.data()); + return; + } + + // if that didn't work, allocate more space + const std::size_t newBufferSize = itAfter.getCounter(); + char_t* newBuffer = static_cast(alloca(newBufferSize * sizeof(char_t))); + const std::format_to_n_result result = std::format_to_n(newBuffer, newBufferSize - 1, fmt, std::forward(args)...); + *result.out = '\0'; + log(level, channel, std::move(sourceLocation), newBuffer); } }; diff --git a/source/mijin/util/iterators.hpp b/source/mijin/util/iterators.hpp index 36023de..b49c99a 100644 --- a/source/mijin/util/iterators.hpp +++ b/source/mijin/util/iterators.hpp @@ -13,6 +13,7 @@ #include #include "../container/optional.hpp" #include "../internal/common.hpp" +#include "../util/annot.hpp" namespace mijin { @@ -855,6 +856,64 @@ TAs collect(TIterable&& iterable) return TAs(iterable.begin(), iterable.end()); } +template +class FixedArrayOutputIterator +{ +public: + using array_t = std::array; + using difference_type = std::ptrdiff_t; + using value_type = TEle; + using pointer = value_type*; + using reference = value_type&; + + static constexpr std::size_t NUM_ELES = numEles; +private: + not_null_t array_; + std::size_t counter_ = 0; +public: + constexpr explicit FixedArrayOutputIterator(array_t& array) MIJIN_NOEXCEPT : array_(&array) {} + constexpr explicit FixedArrayOutputIterator(array_t& array, array_t::iterator pos) MIJIN_NOEXCEPT + : array_(&array), counter_(static_cast(pos - array.begin())) {} + constexpr FixedArrayOutputIterator(const FixedArrayOutputIterator&) noexcept = default; + + constexpr FixedArrayOutputIterator& operator=(const FixedArrayOutputIterator&) noexcept = default; + + [[nodiscard]] + constexpr std::size_t getCounter() const MIJIN_NOEXCEPT + { + return counter_; + } + + [[nodiscard]] + constexpr bool didOverflow() const MIJIN_NOEXCEPT + { + return counter_ >= NUM_ELES; + } + + constexpr reference operator*() const MIJIN_NOEXCEPT + { + static TEle dummy_; // returned when we're at the end of the array + if (counter_ < NUM_ELES) { + return array_->at(counter_); + } + return dummy_; + } + + constexpr FixedArrayOutputIterator& operator++() MIJIN_NOEXCEPT + { + ++counter_; + return *this; + } + + constexpr FixedArrayOutputIterator operator++(int) const MIJIN_NOEXCEPT + { + FixedArrayOutputIterator copy(*this); + ++copy; + return copy; + } +}; +static_assert(std::output_iterator, int>); + namespace pipe { template @@ -973,7 +1032,7 @@ auto operator|(TIterable&& iterable, Xth) { return map(std::forward(iterable), [](auto&& element) { return std::get(element); } ); } -} +} // namespace pipe } // namespace mijin #endif // MIJIN_UTIL_ITERATORS_HPP_INCLUDED \ No newline at end of file