Commit ad611c13 authored by Kenton Varda's avatar Kenton Varda

Improve String.

parent 4958d3a4
...@@ -176,7 +176,7 @@ kj::String stringify(DynamicValue::Reader value) { ...@@ -176,7 +176,7 @@ kj::String stringify(DynamicValue::Reader value) {
std::stringstream out; std::stringstream out;
print(out, value, schema::Type::Body::STRUCT_TYPE); print(out, value, schema::Type::Body::STRUCT_TYPE);
auto content = out.str(); auto content = out.str();
return kj::String(content.data(), content.size()); return kj::heapString(content.data(), content.size());
} }
namespace internal { namespace internal {
......
...@@ -283,5 +283,24 @@ TEST(Array, AraryBuilderAddAll) { ...@@ -283,5 +283,24 @@ TEST(Array, AraryBuilderAddAll) {
EXPECT_EQ(0, TestObject::copiedCount); EXPECT_EQ(0, TestObject::copiedCount);
} }
TEST(Array, HeapCopy) {
{
Array<char> copy = heapArray("foo", 3);
EXPECT_EQ(3u, copy.size());
EXPECT_EQ("foo", std::string(copy.begin(), 3));
}
{
Array<char> copy = heapArray(ArrayPtr<const char>("bar", 3));
EXPECT_EQ(3u, copy.size());
EXPECT_EQ("bar", std::string(copy.begin(), 3));
}
{
const char* ptr = "baz";
Array<char> copy = heapArray<char>(ptr, ptr + 3);
EXPECT_EQ(3u, copy.size());
EXPECT_EQ("baz", std::string(copy.begin(), 3));
}
}
} // namespace } // namespace
} // namespace kj } // namespace kj
...@@ -156,14 +156,6 @@ namespace internal { ...@@ -156,14 +156,6 @@ namespace internal {
class HeapArrayDisposer final: public ArrayDisposer { class HeapArrayDisposer final: public ArrayDisposer {
public: public:
static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
void (*constructElement)(void*), void (*destroyElement)(void*));
// Allocates and constructs the array. Both function pointers are null if the constructor is
// trivial, otherwise destroyElement is null if the constructor doesn't throw.
virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
size_t capacity, void (*destroyElement)(void*)) const override;
template <typename T> template <typename T>
static T* allocate(size_t count); static T* allocate(size_t count);
template <typename T> template <typename T>
...@@ -172,6 +164,14 @@ public: ...@@ -172,6 +164,14 @@ public:
static const HeapArrayDisposer instance; static const HeapArrayDisposer instance;
private: private:
static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
void (*constructElement)(void*), void (*destroyElement)(void*));
// Allocates and constructs the array. Both function pointers are null if the constructor is
// trivial, otherwise destroyElement is null if the constructor doesn't throw.
virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
size_t capacity, void (*destroyElement)(void*)) const override;
template <typename T, bool hasTrivialConstructor = __has_trivial_constructor(T), template <typename T, bool hasTrivialConstructor = __has_trivial_constructor(T),
bool hasNothrowConstructor = __has_nothrow_constructor(T)> bool hasNothrowConstructor = __has_nothrow_constructor(T)>
struct Allocate_; struct Allocate_;
...@@ -189,6 +189,11 @@ inline Array<T> heapArray(size_t size) { ...@@ -189,6 +189,11 @@ inline Array<T> heapArray(size_t size) {
internal::HeapArrayDisposer::instance); internal::HeapArrayDisposer::instance);
} }
template <typename T> Array<T> heapArray(const T* content, size_t size);
template <typename T> Array<T> heapArray(ArrayPtr<const T> content);
template <typename T, typename Iterator> Array<T> heapArray(Iterator begin, Iterator end);
// Allocate a heap arary containing a copy of the given content.
// ======================================================================================= // =======================================================================================
// ArrayBuilder // ArrayBuilder
...@@ -462,6 +467,27 @@ void ArrayBuilder<T>::addAll(Iterator start, Iterator end) { ...@@ -462,6 +467,27 @@ void ArrayBuilder<T>::addAll(Iterator start, Iterator end) {
pos = internal::copyConstructArray(pos, start, end); pos = internal::copyConstructArray(pos, start, end);
} }
template <typename T>
Array<T> heapArray(const T* content, size_t size) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
builder.addAll(content, content + size);
return builder.finish();
}
template <typename T>
Array<T> heapArray(ArrayPtr<const T> content) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
builder.addAll(content);
return builder.finish();
}
template <typename T, typename Iterator> Array<T>
heapArray(Iterator begin, Iterator end) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(end - begin);
builder.addAll(begin, end);
return builder.finish();
}
} // namespace kj } // namespace kj
#endif // KJ_ARRAY_H_ #endif // KJ_ARRAY_H_
...@@ -181,6 +181,14 @@ template <typename T> struct IsLvalueReference_<T&> { static constexpr bool valu ...@@ -181,6 +181,14 @@ template <typename T> struct IsLvalueReference_<T&> { static constexpr bool valu
template <typename T> template <typename T>
inline constexpr bool isLvalueReference() { return IsLvalueReference_<T>::value; } inline constexpr bool isLvalueReference() { return IsLvalueReference_<T>::value; }
template <typename T> struct Decay_ { typedef T Type; };
template <typename T> struct Decay_<T&> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<T&&> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<T[]> { typedef typename Decay_<T*>::Type Type; };
template <typename T> struct Decay_<const T> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<volatile T> { typedef typename Decay_<T>::Type Type; };
template <typename T> using Decay = typename Decay_<T>::Type;
template <typename T> template <typename T>
T instance() noexcept; T instance() noexcept;
// Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify // Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify
...@@ -494,7 +502,7 @@ public: ...@@ -494,7 +502,7 @@ public:
inline T& front() const { return *ptr; } inline T& front() const { return *ptr; }
inline T& back() const { return *(ptr + size_ - 1); } inline T& back() const { return *(ptr + size_ - 1); }
inline ArrayPtr slice(size_t start, size_t end) { inline ArrayPtr slice(size_t start, size_t end) const {
KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice().");
return ArrayPtr(ptr + start, end - start); return ArrayPtr(ptr + start, end - start);
} }
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define KJ_PRIVATE
#include "exception.h" #include "exception.h"
#include "util.h" #include "util.h"
#include "logging.h" #include "logging.h"
...@@ -56,7 +55,7 @@ ArrayPtr<const char> operator*(const Stringifier&, Exception::Durability durabil ...@@ -56,7 +55,7 @@ ArrayPtr<const char> operator*(const Stringifier&, Exception::Durability durabil
} }
Exception::Exception(Nature nature, Durability durability, const char* file, int line, Exception::Exception(Nature nature, Durability durability, const char* file, int line,
Array<char> description) noexcept String description) noexcept
: file(file), line(line), nature(nature), durability(durability), : file(file), line(line), nature(nature), durability(durability),
description(mv(description)) { description(mv(description)) {
traceCount = backtrace(trace, 16); traceCount = backtrace(trace, 16);
...@@ -68,7 +67,7 @@ Exception::Exception(const Exception& other) noexcept ...@@ -68,7 +67,7 @@ Exception::Exception(const Exception& other) noexcept
memcpy(trace, other.trace, sizeof(trace[0]) * traceCount); memcpy(trace, other.trace, sizeof(trace[0]) * traceCount);
KJ_IF_MAYBE(c, other.context) { KJ_IF_MAYBE(c, other.context) {
context = heap<Context>(**c); context = heap(**c);
} }
} }
...@@ -77,11 +76,11 @@ Exception::~Exception() noexcept {} ...@@ -77,11 +76,11 @@ Exception::~Exception() noexcept {}
Exception::Context::Context(const Context& other) noexcept Exception::Context::Context(const Context& other) noexcept
: file(other.file), line(other.line), description(str(other.description)) { : file(other.file), line(other.line), description(str(other.description)) {
KJ_IF_MAYBE(n, other.next) { KJ_IF_MAYBE(n, other.next) {
next = heap<Context>(**n); next = heap(**n);
} }
} }
void Exception::wrapContext(const char* file, int line, Array<char>&& description) { void Exception::wrapContext(const char* file, int line, String&& description) {
context = heap<Context>(file, line, mv(description), mv(context)); context = heap<Context>(file, line, mv(description), mv(context));
} }
...@@ -98,7 +97,7 @@ const char* Exception::what() const noexcept { ...@@ -98,7 +97,7 @@ const char* Exception::what() const noexcept {
} }
} }
Array<Array<char>> contextText = heapArray<Array<char>>(contextDepth); Array<String> contextText = heapArray<String>(contextDepth);
contextDepth = 0; contextDepth = 0;
contextPtr = &context; contextPtr = &context;
...@@ -118,7 +117,7 @@ const char* Exception::what() const noexcept { ...@@ -118,7 +117,7 @@ const char* Exception::what() const noexcept {
file, ":", line, ": ", nature, file, ":", line, ": ", nature,
durability == Durability::TEMPORARY ? " (temporary)" : "", durability == Durability::TEMPORARY ? " (temporary)" : "",
this->description == nullptr ? "" : ": ", this->description, this->description == nullptr ? "" : ": ", this->description,
"\nstack: ", strArray(arrayPtr(trace, traceCount), " "), '\0'); "\nstack: ", strArray(arrayPtr(trace, traceCount), " "));
return whatBuffer.begin(); return whatBuffer.begin();
} }
...@@ -163,14 +162,14 @@ void ExceptionCallback::onFatalException(Exception&& exception) { ...@@ -163,14 +162,14 @@ void ExceptionCallback::onFatalException(Exception&& exception) {
#endif #endif
} }
void ExceptionCallback::logMessage(ArrayPtr<const char> text) { void ExceptionCallback::logMessage(StringPtr text) {
while (text != nullptr) { while (text != nullptr) {
ssize_t n = write(STDERR_FILENO, text.begin(), text.size()); ssize_t n = write(STDERR_FILENO, text.begin(), text.size());
if (n <= 0) { if (n <= 0) {
// stderr is broken. Give up. // stderr is broken. Give up.
return; return;
} }
text = text.slice(n, text.size()); text = text.slice(n);
} }
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <exception> #include <exception>
#include "memory.h" #include "memory.h"
#include "array.h" #include "array.h"
#include "string.h"
namespace kj { namespace kj {
...@@ -64,7 +65,7 @@ public: ...@@ -64,7 +65,7 @@ public:
}; };
Exception(Nature nature, Durability durability, const char* file, int line, Exception(Nature nature, Durability durability, const char* file, int line,
Array<char> description = nullptr) noexcept; String description = nullptr) noexcept;
Exception(const Exception& other) noexcept; Exception(const Exception& other) noexcept;
Exception(Exception&& other) = default; Exception(Exception&& other) = default;
~Exception() noexcept; ~Exception() noexcept;
...@@ -80,10 +81,10 @@ public: ...@@ -80,10 +81,10 @@ public:
const char* file; const char* file;
int line; int line;
Array<char> description; String description;
Maybe<Own<Context>> next; Maybe<Own<Context>> next;
Context(const char* file, int line, Array<char>&& description, Maybe<Own<Context>>&& next) Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
: file(file), line(line), description(mv(description)), next(mv(next)) {} : file(file), line(line), description(mv(description)), next(mv(next)) {}
Context(const Context& other) noexcept; Context(const Context& other) noexcept;
}; };
...@@ -96,7 +97,7 @@ public: ...@@ -96,7 +97,7 @@ public:
} }
} }
void wrapContext(const char* file, int line, Array<char>&& description); void wrapContext(const char* file, int line, String&& description);
// Wraps the context in a new node. This becomes the head node returned by getContext() -- it // Wraps the context in a new node. This becomes the head node returned by getContext() -- it
// is expected that contexts will be added in reverse order as the exception passes up the // is expected that contexts will be added in reverse order as the exception passes up the
// callback stack. // callback stack.
...@@ -108,11 +109,11 @@ private: ...@@ -108,11 +109,11 @@ private:
int line; int line;
Nature nature; Nature nature;
Durability durability; Durability durability;
Array<char> description; String description;
Maybe<Own<Context>> context; Maybe<Own<Context>> context;
void* trace[16]; void* trace[16];
uint traceCount; uint traceCount;
mutable Array<char> whatBuffer; mutable String whatBuffer;
}; };
struct Stringifier; struct Stringifier;
...@@ -143,7 +144,7 @@ public: ...@@ -143,7 +144,7 @@ public:
// aborting. The default implementation throws an exception unless the library was compiled with // aborting. The default implementation throws an exception unless the library was compiled with
// -fno-exceptions, in which case it logs an error and returns. // -fno-exceptions, in which case it logs an error and returns.
virtual void logMessage(ArrayPtr<const char> text); virtual void logMessage(StringPtr text);
// Called when something wants to log some debug text. The text always ends in a newline if // Called when something wants to log some debug text. The text always ends in a newline if
// it is non-empty. The default implementation writes the text to stderr. // it is non-empty. The default implementation writes the text to stderr.
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define KJ_PRIVATE
#include "logging.h" #include "logging.h"
#include "exception.h" #include "exception.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
...@@ -70,7 +69,7 @@ public: ...@@ -70,7 +69,7 @@ public:
throw MockException(); throw MockException();
} }
void logMessage(ArrayPtr<const char> text) override { void logMessage(StringPtr text) override {
this->text += "log message: "; this->text += "log message: ";
this->text.append(text.begin(), text.end()); this->text.append(text.begin(), text.end());
} }
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define KJ_PRIVATE
#include "logging.h" #include "logging.h"
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
...@@ -52,8 +51,8 @@ enum DescriptionStyle { ...@@ -52,8 +51,8 @@ enum DescriptionStyle {
SYSCALL SYSCALL
}; };
static Array<char> makeDescription(DescriptionStyle style, const char* code, int errorNumber, static String makeDescription(DescriptionStyle style, const char* code, int errorNumber,
const char* macroArgs, ArrayPtr<Array<char>> argValues) { const char* macroArgs, ArrayPtr<String> argValues) {
KJ_STACK_ARRAY(ArrayPtr<const char>, argNames, argValues.size(), 8, 64); KJ_STACK_ARRAY(ArrayPtr<const char>, argNames, argValues.size(), 8, 64);
if (argValues.size() > 0) { if (argValues.size() > 0) {
...@@ -112,22 +111,22 @@ static Array<char> makeDescription(DescriptionStyle style, const char* code, int ...@@ -112,22 +111,22 @@ static Array<char> makeDescription(DescriptionStyle style, const char* code, int
} }
{ {
ArrayPtr<const char> expected = stringPtr("expected "); StringPtr expected = "expected ";
ArrayPtr<const char> codeArray = style == LOG ? nullptr : stringPtr(code); StringPtr codeArray = style == LOG ? nullptr : StringPtr(code);
ArrayPtr<const char> sep = stringPtr(" = "); StringPtr sep = " = ";
ArrayPtr<const char> delim = stringPtr("; "); StringPtr delim = "; ";
ArrayPtr<const char> colon = stringPtr(": "); StringPtr colon = ": ";
if (style == ASSERTION && strcmp(code, "false") == 0) { if (style == ASSERTION && strcmp(code, "false") == 0) {
// Don't print "expected false", that's silly. // Don't print "expected false", that's silly.
style = LOG; style = LOG;
} }
ArrayPtr<const char> sysErrorArray; StringPtr sysErrorArray;
#if __USE_GNU #if __USE_GNU
char buffer[256]; char buffer[256];
if (style == SYSCALL) { if (style == SYSCALL) {
sysErrorArray = stringPtr(strerror_r(errorNumber, buffer, sizeof(buffer))); sysErrorArray = strerror_r(errorNumber, buffer, sizeof(buffer));
} }
#else #else
// TODO(port): Other unixes should have strerror_r but it may have a different signature. // TODO(port): Other unixes should have strerror_r but it may have a different signature.
...@@ -157,40 +156,37 @@ static Array<char> makeDescription(DescriptionStyle style, const char* code, int ...@@ -157,40 +156,37 @@ static Array<char> makeDescription(DescriptionStyle style, const char* code, int
totalSize += argValues[i].size(); totalSize += argValues[i].size();
} }
ArrayBuilder<char> result = heapArrayBuilder<char>(totalSize); String result = heapString(totalSize);
char* pos = result.begin();
switch (style) { switch (style) {
case LOG: case LOG:
break; break;
case ASSERTION: case ASSERTION:
result.addAll(expected); pos = fill(pos, expected, codeArray);
result.addAll(codeArray);
break; break;
case SYSCALL: case SYSCALL:
result.addAll(codeArray); pos = fill(pos, codeArray, colon, sysErrorArray);
result.addAll(colon);
result.addAll(sysErrorArray);
break; break;
} }
for (size_t i = 0; i < argValues.size(); i++) { for (size_t i = 0; i < argValues.size(); i++) {
if (i > 0 || style != LOG) { if (i > 0 || style != LOG) {
result.addAll(delim); pos = fill(pos, delim);
} }
if (argNames[i].size() > 0 && argNames[i][0] != '\"') { if (argNames[i].size() > 0 && argNames[i][0] != '\"') {
result.addAll(argNames[i]); pos = fill(pos, argNames[i], sep);
result.addAll(sep);
} }
result.addAll(argValues[i]); pos = fill(pos, argValues[i]);
} }
return result.finish(); return result;
} }
} }
} // namespace } // namespace
void Log::logInternal(const char* file, int line, Severity severity, const char* macroArgs, void Log::logInternal(const char* file, int line, Severity severity, const char* macroArgs,
ArrayPtr<Array<char>> argValues) { ArrayPtr<String> argValues) {
getExceptionCallback().logMessage( getExceptionCallback().logMessage(
str(severity, ": ", file, ":", line, ": ", str(severity, ": ", file, ":", line, ": ",
makeDescription(LOG, nullptr, 0, macroArgs, argValues), '\n')); makeDescription(LOG, nullptr, 0, macroArgs, argValues), '\n'));
...@@ -198,7 +194,7 @@ void Log::logInternal(const char* file, int line, Severity severity, const char* ...@@ -198,7 +194,7 @@ void Log::logInternal(const char* file, int line, Severity severity, const char*
void Log::recoverableFaultInternal( void Log::recoverableFaultInternal(
const char* file, int line, Exception::Nature nature, const char* file, int line, Exception::Nature nature,
const char* condition, const char* macroArgs, ArrayPtr<Array<char>> argValues) { const char* condition, const char* macroArgs, ArrayPtr<String> argValues) {
getExceptionCallback().onRecoverableException( getExceptionCallback().onRecoverableException(
Exception(nature, Exception::Durability::PERMANENT, file, line, Exception(nature, Exception::Durability::PERMANENT, file, line,
makeDescription(ASSERTION, condition, 0, macroArgs, argValues))); makeDescription(ASSERTION, condition, 0, macroArgs, argValues)));
...@@ -206,7 +202,7 @@ void Log::recoverableFaultInternal( ...@@ -206,7 +202,7 @@ void Log::recoverableFaultInternal(
void Log::fatalFaultInternal( void Log::fatalFaultInternal(
const char* file, int line, Exception::Nature nature, const char* file, int line, Exception::Nature nature,
const char* condition, const char* macroArgs, ArrayPtr<Array<char>> argValues) { const char* condition, const char* macroArgs, ArrayPtr<String> argValues) {
getExceptionCallback().onFatalException( getExceptionCallback().onFatalException(
Exception(nature, Exception::Durability::PERMANENT, file, line, Exception(nature, Exception::Durability::PERMANENT, file, line,
makeDescription(ASSERTION, condition, 0, macroArgs, argValues))); makeDescription(ASSERTION, condition, 0, macroArgs, argValues)));
...@@ -215,7 +211,7 @@ void Log::fatalFaultInternal( ...@@ -215,7 +211,7 @@ void Log::fatalFaultInternal(
void Log::recoverableFailedSyscallInternal( void Log::recoverableFailedSyscallInternal(
const char* file, int line, const char* call, const char* file, int line, const char* call,
int errorNumber, const char* macroArgs, ArrayPtr<Array<char>> argValues) { int errorNumber, const char* macroArgs, ArrayPtr<String> argValues) {
getExceptionCallback().onRecoverableException( getExceptionCallback().onRecoverableException(
Exception(Exception::Nature::OS_ERROR, Exception::Durability::PERMANENT, file, line, Exception(Exception::Nature::OS_ERROR, Exception::Durability::PERMANENT, file, line,
makeDescription(SYSCALL, call, errorNumber, macroArgs, argValues))); makeDescription(SYSCALL, call, errorNumber, macroArgs, argValues)));
...@@ -223,7 +219,7 @@ void Log::recoverableFailedSyscallInternal( ...@@ -223,7 +219,7 @@ void Log::recoverableFailedSyscallInternal(
void Log::fatalFailedSyscallInternal( void Log::fatalFailedSyscallInternal(
const char* file, int line, const char* call, const char* file, int line, const char* call,
int errorNumber, const char* macroArgs, ArrayPtr<Array<char>> argValues) { int errorNumber, const char* macroArgs, ArrayPtr<String> argValues) {
getExceptionCallback().onFatalException( getExceptionCallback().onFatalException(
Exception(Exception::Nature::OS_ERROR, Exception::Durability::PERMANENT, file, line, Exception(Exception::Nature::OS_ERROR, Exception::Durability::PERMANENT, file, line,
makeDescription(SYSCALL, call, errorNumber, macroArgs, argValues))); makeDescription(SYSCALL, call, errorNumber, macroArgs, argValues)));
...@@ -231,7 +227,7 @@ void Log::fatalFailedSyscallInternal( ...@@ -231,7 +227,7 @@ void Log::fatalFailedSyscallInternal(
} }
void Log::addContextToInternal(Exception& exception, const char* file, int line, void Log::addContextToInternal(Exception& exception, const char* file, int line,
const char* macroArgs, ArrayPtr<Array<char>> argValues) { const char* macroArgs, ArrayPtr<String> argValues) {
exception.wrapContext(file, line, makeDescription(LOG, nullptr, 0, macroArgs, argValues)); exception.wrapContext(file, line, makeDescription(LOG, nullptr, 0, macroArgs, argValues));
} }
...@@ -251,7 +247,7 @@ void Log::Context::onFatalException(Exception&& exception) { ...@@ -251,7 +247,7 @@ void Log::Context::onFatalException(Exception&& exception) {
addTo(exception); addTo(exception);
next.onFatalException(kj::mv(exception)); next.onFatalException(kj::mv(exception));
} }
void Log::Context::logMessage(ArrayPtr<const char> text) { void Log::Context::logMessage(StringPtr text) {
// TODO(someday): We could do something like log the context and then indent all log messages // TODO(someday): We could do something like log the context and then indent all log messages
// written until the end of the context. // written until the end of the context.
next.logMessage(text); next.logMessage(text);
......
...@@ -158,7 +158,7 @@ public: ...@@ -158,7 +158,7 @@ public:
virtual void onRecoverableException(Exception&& exception) override; virtual void onRecoverableException(Exception&& exception) override;
virtual void onFatalException(Exception&& exception) override; virtual void onFatalException(Exception&& exception) override;
virtual void logMessage(ArrayPtr<const char> text) override; virtual void logMessage(StringPtr text) override;
private: private:
ExceptionCallback& next; ExceptionCallback& next;
...@@ -186,23 +186,23 @@ private: ...@@ -186,23 +186,23 @@ private:
static Severity minSeverity; static Severity minSeverity;
static void logInternal(const char* file, int line, Severity severity, const char* macroArgs, static void logInternal(const char* file, int line, Severity severity, const char* macroArgs,
ArrayPtr<Array<char>> argValues); ArrayPtr<String> argValues);
static void recoverableFaultInternal( static void recoverableFaultInternal(
const char* file, int line, Exception::Nature nature, const char* file, int line, Exception::Nature nature,
const char* condition, const char* macroArgs, ArrayPtr<Array<char>> argValues); const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
static void fatalFaultInternal( static void fatalFaultInternal(
const char* file, int line, Exception::Nature nature, const char* file, int line, Exception::Nature nature,
const char* condition, const char* macroArgs, ArrayPtr<Array<char>> argValues) const char* condition, const char* macroArgs, ArrayPtr<String> argValues)
KJ_NORETURN; KJ_NORETURN;
static void recoverableFailedSyscallInternal( static void recoverableFailedSyscallInternal(
const char* file, int line, const char* call, const char* file, int line, const char* call,
int errorNumber, const char* macroArgs, ArrayPtr<Array<char>> argValues); int errorNumber, const char* macroArgs, ArrayPtr<String> argValues);
static void fatalFailedSyscallInternal( static void fatalFailedSyscallInternal(
const char* file, int line, const char* call, const char* file, int line, const char* call,
int errorNumber, const char* macroArgs, ArrayPtr<Array<char>> argValues) int errorNumber, const char* macroArgs, ArrayPtr<String> argValues)
KJ_NORETURN; KJ_NORETURN;
static void addContextToInternal(Exception& exception, const char* file, int line, static void addContextToInternal(Exception& exception, const char* file, int line,
const char* macroArgs, ArrayPtr<Array<char>> argValues); const char* macroArgs, ArrayPtr<String> argValues);
static int getOsErrorNumber(); static int getOsErrorNumber();
// Get the error code of the last error (e.g. from errno). Returns -1 on EINTR. // Get the error code of the last error (e.g. from errno). Returns -1 on EINTR.
...@@ -287,14 +287,14 @@ ArrayPtr<const char> operator*(const Stringifier&, Log::Severity severity); ...@@ -287,14 +287,14 @@ ArrayPtr<const char> operator*(const Stringifier&, Log::Severity severity);
template <typename... Params> template <typename... Params>
void Log::log(const char* file, int line, Severity severity, const char* macroArgs, void Log::log(const char* file, int line, Severity severity, const char* macroArgs,
Params&&... params) { Params&&... params) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params))); logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
} }
template <typename... Params> template <typename... Params>
void Log::recoverableFault(const char* file, int line, Exception::Nature nature, void Log::recoverableFault(const char* file, int line, Exception::Nature nature,
const char* condition, const char* macroArgs, Params&&... params) { const char* condition, const char* macroArgs, Params&&... params) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
recoverableFaultInternal(file, line, nature, condition, macroArgs, recoverableFaultInternal(file, line, nature, condition, macroArgs,
arrayPtr(argValues, sizeof...(Params))); arrayPtr(argValues, sizeof...(Params)));
} }
...@@ -302,7 +302,7 @@ void Log::recoverableFault(const char* file, int line, Exception::Nature nature, ...@@ -302,7 +302,7 @@ void Log::recoverableFault(const char* file, int line, Exception::Nature nature,
template <typename... Params> template <typename... Params>
void Log::fatalFault(const char* file, int line, Exception::Nature nature, void Log::fatalFault(const char* file, int line, Exception::Nature nature,
const char* condition, const char* macroArgs, Params&&... params) { const char* condition, const char* macroArgs, Params&&... params) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
fatalFaultInternal(file, line, nature, condition, macroArgs, fatalFaultInternal(file, line, nature, condition, macroArgs,
arrayPtr(argValues, sizeof...(Params))); arrayPtr(argValues, sizeof...(Params)));
} }
...@@ -315,7 +315,7 @@ bool Log::recoverableSyscall(Call&& call, const char* file, int line, const char ...@@ -315,7 +315,7 @@ bool Log::recoverableSyscall(Call&& call, const char* file, int line, const char
int errorNum = getOsErrorNumber(); int errorNum = getOsErrorNumber();
// getOsErrorNumber() returns -1 to indicate EINTR // getOsErrorNumber() returns -1 to indicate EINTR
if (errorNum != -1) { if (errorNum != -1) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
recoverableFailedSyscallInternal(file, line, callText, errorNum, recoverableFailedSyscallInternal(file, line, callText, errorNum,
macroArgs, arrayPtr(argValues, sizeof...(Params))); macroArgs, arrayPtr(argValues, sizeof...(Params)));
return false; return false;
...@@ -333,7 +333,7 @@ auto Log::syscall(Call&& call, const char* file, int line, const char* callText, ...@@ -333,7 +333,7 @@ auto Log::syscall(Call&& call, const char* file, int line, const char* callText,
int errorNum = getOsErrorNumber(); int errorNum = getOsErrorNumber();
// getOsErrorNumber() returns -1 to indicate EINTR // getOsErrorNumber() returns -1 to indicate EINTR
if (errorNum != -1) { if (errorNum != -1) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
fatalFailedSyscallInternal(file, line, callText, errorNum, fatalFailedSyscallInternal(file, line, callText, errorNum,
macroArgs, arrayPtr(argValues, sizeof...(Params))); macroArgs, arrayPtr(argValues, sizeof...(Params)));
} }
...@@ -346,7 +346,7 @@ template <typename... Params> ...@@ -346,7 +346,7 @@ template <typename... Params>
void Log::reportFailedRecoverableSyscall( void Log::reportFailedRecoverableSyscall(
int errorNumber, const char* file, int line, const char* callText, int errorNumber, const char* file, int line, const char* callText,
const char* macroArgs, Params&&... params) { const char* macroArgs, Params&&... params) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
recoverableFailedSyscallInternal(file, line, callText, errorNumber, macroArgs, recoverableFailedSyscallInternal(file, line, callText, errorNumber, macroArgs,
arrayPtr(argValues, sizeof...(Params))); arrayPtr(argValues, sizeof...(Params)));
} }
...@@ -355,7 +355,7 @@ template <typename... Params> ...@@ -355,7 +355,7 @@ template <typename... Params>
void Log::reportFailedSyscall( void Log::reportFailedSyscall(
int errorNumber, const char* file, int line, const char* callText, int errorNumber, const char* file, int line, const char* callText,
const char* macroArgs, Params&&... params) { const char* macroArgs, Params&&... params) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
fatalFailedSyscallInternal(file, line, callText, errorNumber, macroArgs, fatalFailedSyscallInternal(file, line, callText, errorNumber, macroArgs,
arrayPtr(argValues, sizeof...(Params))); arrayPtr(argValues, sizeof...(Params)));
} }
...@@ -363,7 +363,7 @@ void Log::reportFailedSyscall( ...@@ -363,7 +363,7 @@ void Log::reportFailedSyscall(
template <typename... Params> template <typename... Params>
void Log::addContextTo(Exception& exception, const char* file, int line, void Log::addContextTo(Exception& exception, const char* file, int line,
const char* macroArgs, Params&&... params) { const char* macroArgs, Params&&... params) {
Array<char> argValues[sizeof...(Params)] = {str(params)...}; String argValues[sizeof...(Params)] = {str(params)...};
addContextToInternal(exception, file, line, macroArgs, arrayPtr(argValues, sizeof...(Params))); addContextToInternal(exception, file, line, macroArgs, arrayPtr(argValues, sizeof...(Params)));
} }
......
...@@ -156,6 +156,17 @@ Own<T> heap(Params&&... params) { ...@@ -156,6 +156,17 @@ Own<T> heap(Params&&... params) {
return Own<T>(new T(kj::fwd<Params>(params)...), internal::HeapDisposer<T>::instance); return Own<T>(new T(kj::fwd<Params>(params)...), internal::HeapDisposer<T>::instance);
} }
template <typename T>
Own<Decay<T>> heap(T&& orig) {
// Allocate a copy (or move) of the argument on the heap.
//
// The purpose of this overload is to allow you to omit the template parameter as there is only
// one argument and the purpose is to copy it.
typedef Decay<T> T2;
return Own<T2>(new T2(kj::fwd<T>(orig)), internal::HeapDisposer<T2>::instance);
}
// ======================================================================================= // =======================================================================================
// Inline implementation details // Inline implementation details
......
...@@ -22,16 +22,20 @@ ...@@ -22,16 +22,20 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "string.h" #include "string.h"
#include "logging.h"
namespace kj { namespace kj {
String::String(const char* value): content(heapArray<char>(strlen(value) + 1)) { String heapString(size_t size) {
strcpy(content.begin(), value); char* buffer = internal::HeapArrayDisposer::allocate<char>(size + 1);
buffer[size] = '\0';
return String(buffer, size, internal::HeapArrayDisposer::instance);
} }
String::String(const char* value, size_t length): content(heapArray<char>(length + 1)) { String heapString(const char* value, size_t size) {
memcpy(content.begin(), value, length); char* buffer = internal::HeapArrayDisposer::allocate<char>(size + 1);
content[length] = '\0'; memcpy(buffer, value, size + 1);
return String(buffer, size, internal::HeapArrayDisposer::instance);
} }
} // namespace kj } // namespace kj
...@@ -29,39 +29,181 @@ ...@@ -29,39 +29,181 @@
namespace kj { namespace kj {
inline ArrayPtr<const char> stringPtr(const char* text) { class StringPtr;
return arrayPtr(text, strlen(text)); class String;
}
// =======================================================================================
// StringPtr -- A NUL-terminated ArrayPtr<const char> containing UTF-8 text.
//
// NUL bytes are allowed to appear before the end of the string. The only requirement is that
// a NUL byte appear immediately after the last byte of the content. This terminator byte is not
// counted in the string's size.
class StringPtr {
public:
inline StringPtr(): content("", 1) {}
inline StringPtr(decltype(nullptr)): content("", 1) {}
inline StringPtr(const char* value): content(value, strlen(value) + 1) {}
inline StringPtr(const String& value);
inline operator ArrayPtr<const char>() const;
inline ArrayPtr<const char> asArray() const;
// Result does not include NUL terminator.
inline const char* cStr() const { return content.begin(); }
// Returns NUL-terminated string.
inline size_t size() const { return content.size() - 1; }
// Result does not include NUL terminator.
inline char operator[](size_t index) const { return content[index]; }
inline const char* begin() const { return content.begin(); }
inline const char* end() const { return content.end() - 1; }
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
inline bool operator==(StringPtr other) const;
inline bool operator!=(StringPtr other) const { return !(*this == other); }
inline StringPtr slice(size_t start) const;
inline ArrayPtr<const char> slice(size_t start, size_t end) const;
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
// version that assumes end = size().
private:
inline StringPtr(ArrayPtr<const char> content): content(content) {}
ArrayPtr<const char> content;
};
inline bool operator==(const char* a, const StringPtr& b) { return b == a; }
inline bool operator!=(const char* a, const StringPtr& b) { return b != a; }
// ======================================================================================= // =======================================================================================
// String -- Just a NUL-terminated Array<char>. // String -- A NUL-terminated Array<char> containing UTF-8 text.
//
// NUL bytes are allowed to appear before the end of the string. The only requirement is that
// a NUL byte appear immediately after the last byte of the content. This terminator byte is not
// counted in the string's size.
//
// To allocate a String, you must call kj::heapString(). We do not implement implicit copying to
// the heap because this hides potential inefficiency from the developer.
class String { class String {
public: public:
String() = default; String() = default;
String(const char* value); inline String(decltype(nullptr)): content(nullptr) {}
String(const char* value, size_t length); inline String(char* value, size_t size, const ArrayDisposer& disposer);
// Does not copy. `size` does not include NUL terminator, but `value` must be NUL-terminated.
inline operator ArrayPtr<char>();
inline operator ArrayPtr<const char>() const;
inline ArrayPtr<char> asArray(); inline ArrayPtr<char> asArray();
inline ArrayPtr<const char> asArray() const; inline ArrayPtr<const char> asArray() const;
inline const char* cStr() const { return content == nullptr ? "" : content.begin(); } // Result does not include NUL terminator.
inline const char* cStr() const;
inline size_t size() const;
// Result does not include NUL terminator.
inline char operator[](size_t index) const;
inline char& operator[](size_t index);
inline size_t size() const { return content == nullptr ? 0 : content.size() - 1; } inline char* begin();
inline char* end();
inline const char* begin() const;
inline const char* end() const;
inline char* begin() { return content == nullptr ? nullptr : content.begin(); } inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
inline char* end() { return content == nullptr ? nullptr : content.end() - 1; } inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
inline const char* begin() const { return content == nullptr ? nullptr : content.begin(); }
inline const char* end() const { return content == nullptr ? nullptr : content.end() - 1; } inline bool operator==(StringPtr other) const { return StringPtr(*this) == other; }
inline bool operator!=(StringPtr other) const { return !(*this == other); }
private: private:
Array<char> content; Array<char> content;
}; };
inline bool operator==(const char* a, const String& b) { return b == a; }
inline bool operator!=(const char* a, const String& b) { return b != a; }
String heapString(size_t size);
// Allocate a String of the given size on the heap, not including NUL terminator. The NUL
// terminator will be initialized automatically but the rest of the content is not initialized.
String heapString(const char* value);
String heapString(const char* value, size_t size);
String heapString(StringPtr value);
String heapString(ArrayPtr<const char> value);
// Allocates a copy of the given value on the heap.
// =======================================================================================
// Inline implementation details.
inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {}
inline StringPtr::operator ArrayPtr<const char>() const {
return content.slice(0, content.size() - 1);
}
inline ArrayPtr<const char> StringPtr::asArray() const {
return content.slice(0, content.size() - 1);
}
inline bool StringPtr::operator==(StringPtr other) const {
return content.size() == other.content.size() &&
memcmp(content.begin(), other.content.begin(), content.size() - 1) == 0;
}
inline StringPtr StringPtr::slice(size_t start) const {
return StringPtr(content.slice(start, content.size()));
}
inline ArrayPtr<const char> StringPtr::slice(size_t start, size_t end) const {
return content.slice(start, end);
}
inline String::operator ArrayPtr<char>() {
return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
}
inline String::operator ArrayPtr<const char>() const {
return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1);
}
inline ArrayPtr<char> String::asArray() { inline ArrayPtr<char> String::asArray() {
return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1); return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
} }
inline ArrayPtr<const char> String::asArray() const { inline ArrayPtr<const char> String::asArray() const {
return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1); return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1);
}
inline const char* String::cStr() const { return content == nullptr ? "" : content.begin(); }
inline size_t String::size() const { return content == nullptr ? 0 : content.size() - 1; }
inline char String::operator[](size_t index) const { return content[index]; }
inline char& String::operator[](size_t index) { return content[index]; }
inline char* String::begin() { return content == nullptr ? nullptr : content.begin(); }
inline char* String::end() { return content == nullptr ? nullptr : content.end() - 1; }
inline const char* String::begin() const { return content == nullptr ? nullptr : content.begin(); }
inline const char* String::end() const { return content == nullptr ? nullptr : content.end() - 1; }
inline String::String(char* value, size_t size, const ArrayDisposer& disposer)
: content(value, size + 1, disposer) {
KJ_INLINE_DPRECOND(value[size] == '\0', "String must be NUL-terminated.");
}
inline String heapString(const char* value) {
return heapString(value, strlen(value));
}
inline String heapString(StringPtr value) {
return heapString(value.begin(), value.size());
}
inline String heapString(ArrayPtr<const char> value) {
return heapString(value.begin(), value.size());
} }
} // namespace kj } // namespace kj
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define KJ_PRIVATE
#include "util.h" #include "util.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> #include <string>
...@@ -30,15 +29,11 @@ namespace kj { ...@@ -30,15 +29,11 @@ namespace kj {
namespace internal { namespace internal {
namespace { namespace {
std::string arrayToStr(Array<char> arr) {
return std::string(arr.begin(), arr.size());
}
TEST(Util, Foo) { TEST(Util, Foo) {
EXPECT_EQ("foobar", arrayToStr(str("foo", "bar"))); EXPECT_EQ("foobar", str("foo", "bar"));
EXPECT_EQ("1 2 3 4", arrayToStr(str(1, " ", 2u, " ", 3l, " ", 4ll))); EXPECT_EQ("1 2 3 4", str(1, " ", 2u, " ", 3l, " ", 4ll));
EXPECT_EQ("1.5 foo 1e15 bar -3", arrayToStr(str(1.5f, " foo ", 1e15, " bar ", -3))); EXPECT_EQ("1.5 foo 1e15 bar -3", str(1.5f, " foo ", 1e15, " bar ", -3));
EXPECT_EQ("foo", arrayToStr(str('f', 'o', 'o'))); EXPECT_EQ("foo", str('f', 'o', 'o'));
} }
} // namespace } // namespace
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define KJ_PRIVATE
#include "util.h" #include "util.h"
#include "logging.h" #include "logging.h"
#include <stdio.h> #include <stdio.h>
......
...@@ -124,11 +124,10 @@ inline size_t sum(std::initializer_list<size_t> nums) { ...@@ -124,11 +124,10 @@ inline size_t sum(std::initializer_list<size_t> nums) {
return result; return result;
} }
template <typename Element> inline char* fill(char* ptr) { return ptr; }
Element* fill(Element* ptr) { return ptr; }
template <typename Element, typename First, typename... Rest> template <typename First, typename... Rest>
Element* fill(Element* __restrict__ target, const First& first, Rest&&... rest) { char* fill(char* __restrict__ target, const First& first, Rest&&... rest) {
auto i = first.begin(); auto i = first.begin();
auto end = first.end(); auto end = first.end();
while (i != end) { while (i != end) {
...@@ -137,23 +136,17 @@ Element* fill(Element* __restrict__ target, const First& first, Rest&&... rest) ...@@ -137,23 +136,17 @@ Element* fill(Element* __restrict__ target, const First& first, Rest&&... rest)
return fill(target, std::forward<Rest>(rest)...); return fill(target, std::forward<Rest>(rest)...);
} }
template <typename Element, typename... Params> template <typename... Params>
Array<Element> concat(Params&&... params) { String concat(Params&&... params) {
// Concatenate a bunch of containers into a single Array. The containers can be anything that // Concatenate a bunch of containers into a single Array. The containers can be anything that
// is iterable and whose elements can be converted to `Element`. // is iterable and whose elements can be converted to `Element`.
#ifdef __CDT_PARSER__ String result = heapString(sum({params.size()...}));
// Eclipse reports a bogus error on `size()`.
Array<Element> result;
#else
Array<Element> result = heapArray<Element>(sum({params.size()...}));
#endif
fill(result.begin(), std::forward<Params>(params)...); fill(result.begin(), std::forward<Params>(params)...);
return result; return result;
} }
template <typename Element> inline String concat(String&& arr) {
Array<Element> concat(Array<Element>&& arr) {
return std::move(arr); return std::move(arr);
} }
...@@ -177,6 +170,7 @@ struct Stringifier { ...@@ -177,6 +170,7 @@ struct Stringifier {
inline ArrayPtr<const char> operator*(const CappedArray<char, n>& s) const { return s; } inline ArrayPtr<const char> operator*(const CappedArray<char, n>& s) const { return s; }
inline ArrayPtr<const char> operator*(const char* s) const { return arrayPtr(s, strlen(s)); } inline ArrayPtr<const char> operator*(const char* s) const { return arrayPtr(s, strlen(s)); }
inline ArrayPtr<const char> operator*(const String& s) const { return s.asArray(); } inline ArrayPtr<const char> operator*(const String& s) const { return s.asArray(); }
inline ArrayPtr<const char> operator*(const StringPtr& s) const { return s.asArray(); }
inline FixedArray<char, 1> operator*(char c) const { inline FixedArray<char, 1> operator*(char c) const {
FixedArray<char, 1> result; FixedArray<char, 1> result;
...@@ -209,18 +203,18 @@ CappedArray<char, sizeof(unsigned long) * 4> hex(unsigned long i); ...@@ -209,18 +203,18 @@ CappedArray<char, sizeof(unsigned long) * 4> hex(unsigned long i);
CappedArray<char, sizeof(unsigned long long) * 4> hex(unsigned long long i); CappedArray<char, sizeof(unsigned long long) * 4> hex(unsigned long long i);
template <typename... Params> template <typename... Params>
Array<char> str(Params&&... params) { String str(Params&&... params) {
// Magic function which builds a string from a bunch of arbitrary values. Example: // Magic function which builds a string from a bunch of arbitrary values. Example:
// str(1, " / ", 2, " = ", 0.5) // str(1, " / ", 2, " = ", 0.5)
// returns: // returns:
// "1 / 2 = 0.5" // "1 / 2 = 0.5"
// To teach `str` how to stringify a type, see `Stringifier`. // To teach `str` how to stringify a type, see `Stringifier`.
return concat<char>(STR * std::forward<Params>(params)...); return concat(STR * std::forward<Params>(params)...);
} }
template <typename T> template <typename T>
Array<char> strArray(T&& arr, const char* delim) { String strArray(T&& arr, const char* delim) {
size_t delimLen = strlen(delim); size_t delimLen = strlen(delim);
KJ_STACK_ARRAY(decltype(STR * arr[0]), pieces, arr.size(), 8, 32); KJ_STACK_ARRAY(decltype(STR * arr[0]), pieces, arr.size(), 8, 32);
size_t size = 0; size_t size = 0;
...@@ -230,7 +224,7 @@ Array<char> strArray(T&& arr, const char* delim) { ...@@ -230,7 +224,7 @@ Array<char> strArray(T&& arr, const char* delim) {
size += pieces[i].size(); size += pieces[i].size();
} }
Array<char> result = heapArray<char>(size); String result = heapString(size);
char* pos = result.begin(); char* pos = result.begin();
for (size_t i = 0; i < arr.size(); i++) { for (size_t i = 0; i < arr.size(); i++) {
if (i > 0) { if (i > 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment