Add FormatToSpan
This commit is contained in:
committed by
Space
parent
2c068b8c5a
commit
4c3fb8697b
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
#include "Porting.h"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
std_support::span<char> kotlin::FormatToSpan(std_support::span<char> buffer, const char* format, ...) noexcept {
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
auto result = VFormatToSpan(buffer, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
std_support::span<char> kotlin::VFormatToSpan(std_support::span<char> buffer, const char* format, std::va_list args) noexcept {
|
||||
if (buffer.empty()) return buffer;
|
||||
if (buffer.size() == 1) {
|
||||
buffer.front() = '\0';
|
||||
return buffer;
|
||||
}
|
||||
int written = konan::vsnprintf(buffer.data(), buffer.size(), format, args);
|
||||
// Consider this a failure, nothing has been written. TODO: Should this be an exception/RuntimeAssert?
|
||||
if (written < 0) return buffer;
|
||||
// If `written` is larger than the buffer size, just pretend we filled the entire buffer (ignoring the trailing \0).
|
||||
size_t writtenSize = std::min(static_cast<size_t>(written), buffer.size() - 1);
|
||||
return buffer.subspan(writtenSize);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef RUNTIME_FORMAT_H
|
||||
#define RUNTIME_FORMAT_H
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
#include "cpp_support/Span.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
|
||||
/*
|
||||
* `FormatToSpan` is a `snprintf`-like API for formatting text.
|
||||
*
|
||||
* It formats text into a `span` buffer (it uses `snprintf` under the hood and so needs a contiguous memory buffer to write into)
|
||||
* and returns the unused portion of `span`.
|
||||
* When input `span` is empty it does nothing.
|
||||
* If `snprintf` fails it returns the buffer unmodified.
|
||||
* If the formatted text cannot fit into the buffer, it'll be truncated enough to fit.
|
||||
* If any character was written into the buffer, there will always be a null character appended, and the returned span will point to it.
|
||||
*
|
||||
* ```
|
||||
* auto output = FormatToSpan(input, "string");
|
||||
* ```
|
||||
* If `input` was a buffer filled with `'\1'` of size 10, by the end the memory would look something like:
|
||||
* ```
|
||||
* s t r i n g \0 \1 \1 \1
|
||||
* ^ ^
|
||||
* | |
|
||||
* input output
|
||||
* ```
|
||||
* and the output will be of size 4.
|
||||
* If `input` was of size 5 instead:
|
||||
* ```
|
||||
* s t r i \0
|
||||
* ^ ^
|
||||
* | |
|
||||
* | output
|
||||
* input
|
||||
* ```
|
||||
* and the output will be of size 1.
|
||||
*
|
||||
* This allows for a composable behaviour:
|
||||
* ```
|
||||
* auto buffer = ...;
|
||||
* buffer = FormatToSpan(buffer, "str");
|
||||
* buffer = FormatToSpan(buffer, "%d", 42);
|
||||
* buffer = FormatToSpan(buffer, "%s", "again");
|
||||
* ```
|
||||
* If `buffer` was of sufficient size, the result will be `str42again\0`.
|
||||
*/
|
||||
|
||||
// Format snprintf-style message into a `buffer` and return the unused portion of a buffer.
|
||||
std_support::span<char> FormatToSpan(std_support::span<char> buffer, const char* format, ...) noexcept
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
// Format vsnprintf-style message into a `buffer` and return the unused portion of a buffer.
|
||||
std_support::span<char> VFormatToSpan(std_support::span<char> buffer, const char* format, std::va_list args) noexcept;
|
||||
|
||||
} // namespace kotlin
|
||||
|
||||
#endif // RUNTIME_FORMAT_H
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "cpp_support/Span.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
TEST(FormatTest, FormatToSpan_String) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(buffer, "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), buffer.size() - 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_StringFormat) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(buffer, "%s", "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), buffer.size() - 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_IntFormat) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(buffer, "%d", 42);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('4', '2', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), buffer.size() - 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_String_Size0) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(0), "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\1', '\1', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 0);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_StringFormat_Size0) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(0), "%s", "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\1', '\1', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 0);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_IntFormat_Size0) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(0), "%d", 42);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\1', '\1', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 0);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_String_Size1) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(1), "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\0', '\1', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_StringFormat_Size1) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(1), "%s", "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\0', '\1', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_IntFormat_Size1) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(1), "%d", 42);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\0', '\1', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_String_Size2) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(2), "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', '\0', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 1);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_StringFormat_Size2) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(2), "%s", "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', '\0', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 1);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_IntFormat_Size2) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(2), "%d", 42);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('4', '\0', '\1', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 1);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_String_Size3) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(3), "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_StringFormat_Size3) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(3), "%s", "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_IntFormat_Size3) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(3), "%d", 42);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('4', '2', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_String_Size4) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(4), "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_StringFormat_Size4) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(4), "%s", "ab");
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_IntFormat_Size4) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatToSpan(std_support::span(buffer).first(4), "%d", 42);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('4', '2', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Sequence) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
std_support::span<char> result(buffer);
|
||||
result = FormatToSpan(result, "a");
|
||||
result = FormatToSpan(result, "%s", "b");
|
||||
result = FormatToSpan(result, "%d", 4);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('a', 'b', '4', '\0', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 3);
|
||||
EXPECT_THAT(result.size(), 2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std_support::span<char> FormatNesting(std_support::span<char> buffer) {
|
||||
buffer = FormatToSpan(buffer, "(");
|
||||
auto nested = buffer.first(buffer.size() - 1); // Leave a space for `)`
|
||||
nested = FormatToSpan(nested, "a ");
|
||||
nested = FormatToSpan(nested, "b ");
|
||||
buffer = buffer.subspan(nested.data() - buffer.data());
|
||||
return FormatToSpan(buffer, ")");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size1) {
|
||||
std::array buffer{'\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size2) {
|
||||
std::array buffer{'\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 1);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size3) {
|
||||
std::array buffer{'\1', '\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size4) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 3);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size5) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 4);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size6) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', 'b', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 5);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size7) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', 'b', ' ', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 6);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_Nesting_Size8) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNesting(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', 'b', ' ', ')', '\0', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 6);
|
||||
EXPECT_THAT(result.size(), 2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std_support::span<char> FormatNestingWithBacktrack(std_support::span<char> buffer) {
|
||||
buffer = FormatToSpan(buffer, "(");
|
||||
auto nested = buffer;
|
||||
nested = FormatToSpan(nested, "a ");
|
||||
nested = FormatToSpan(nested, "b ");
|
||||
if (nested.data() != buffer.data()) {
|
||||
// If we managed to format something in nested, replace the last formatted character with ')'
|
||||
buffer = buffer.subspan(nested.data() - buffer.data() - 1);
|
||||
}
|
||||
return FormatToSpan(buffer, ")");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size1) {
|
||||
std::array buffer{'\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data());
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size2) {
|
||||
std::array buffer{'\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 1);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size3) {
|
||||
std::array buffer{'\1', '\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 2);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size4) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 3);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size5) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 4);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size6) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', 'b', ')', '\0'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 5);
|
||||
EXPECT_THAT(result.size(), 1);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size7) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', 'b', ')', '\0', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 5);
|
||||
EXPECT_THAT(result.size(), 2);
|
||||
}
|
||||
|
||||
TEST(FormatTest, FormatToSpan_NestingWithBacktrack_Size8) {
|
||||
std::array buffer{'\1', '\1', '\1', '\1', '\1', '\1', '\1', '\1'};
|
||||
auto result = FormatNestingWithBacktrack(buffer);
|
||||
EXPECT_THAT(buffer, testing::ElementsAre('(', 'a', ' ', 'b', ')', '\0', '\1', '\1'));
|
||||
EXPECT_THAT(result.data(), buffer.data() + 5);
|
||||
EXPECT_THAT(result.size(), 3);
|
||||
}
|
||||
@@ -3,9 +3,13 @@
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "KAssert.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdarg>
|
||||
|
||||
#include "Porting.h"
|
||||
#include "cpp_support/Span.hpp"
|
||||
#include "Format.h"
|
||||
#include "StackTrace.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
@@ -13,22 +17,20 @@ using namespace kotlin;
|
||||
namespace {
|
||||
|
||||
void PrintAssert(bool allowStacktrace, const char* location, const char* format, std::va_list args) noexcept {
|
||||
char buf[1024];
|
||||
int written = -1;
|
||||
std::array<char, 1024> bufferStorage;
|
||||
std_support::span<char> buffer(bufferStorage);
|
||||
|
||||
// Write the title with a source location.
|
||||
if (location != nullptr) {
|
||||
written = konan::snprintf(buf, sizeof(buf), "%s: runtime assert: ", location);
|
||||
buffer = FormatToSpan(buffer, "%s: runtime assert: ", location);
|
||||
} else {
|
||||
written = konan::snprintf(buf, sizeof(buf), "runtime assert: ");
|
||||
buffer = FormatToSpan(buffer, "runtime assert: ");
|
||||
}
|
||||
|
||||
// Write the message.
|
||||
if (written >= 0 && static_cast<size_t>(written) < sizeof(buf)) {
|
||||
konan::vsnprintf(buf + written, sizeof(buf) - written, format, args);
|
||||
}
|
||||
buffer = VFormatToSpan(buffer, format, args);
|
||||
|
||||
konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf)));
|
||||
konan::consoleErrorUtf8(bufferStorage.data(), bufferStorage.size() - buffer.size());
|
||||
konan::consoleErrorf("\n");
|
||||
if (allowStacktrace) {
|
||||
kotlin::PrintStackTraceStderr();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
extern "C" OBJ_GETTER(Kotlin_Throwable_getStackTrace, KRef throwable);
|
||||
|
||||
// TODO: Consider refactoring to `FormatToSpan`.
|
||||
static void writeStackTraceToBuffer(KRef throwable, char* buffer, unsigned long bufferSize) {
|
||||
if (bufferSize < 2) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user