Skip to content
This repository was archived by the owner on Jul 16, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 143 additions & 13 deletions include/dart.h
Original file line number Diff line number Diff line change
Expand Up @@ -3333,6 +3333,24 @@ namespace dart {
>
basic_string() : basic_string("") {}

/**
* @brief
* Constructor can be used to directly initialize a strongly
* typed string with an initial value.
*
* @details
* Internally calls make_string on the underlying packet type
* (if implemented).
*/
template <class Str = String, class EnableIf =
std::enable_if_t<
meta::is_detected<make_string_t, Str, std::string const&>::value
>
>
explicit basic_string(std::string const& str) :
val(value_type::make_string(str))
{}

/**
* @brief
* Constructor can be used to directly initialize a strongly
Expand All @@ -3351,6 +3369,40 @@ namespace dart {
val(value_type::make_string(str))
{}

/**
* @brief
* Constructor can be used to directly initialize a strongly
* typed string with an initial value.
*
* @details
* Internally calls make_string on the underlying packet type
* (if implemented).
*/
template <class Str = String, class EnableIf =
std::enable_if_t<
meta::is_detected<make_string_t, Str, char const*>::value
>
>
basic_string(char const* str) :
val(value_type::make_string(str))
{}

/**
* @brief
* Concatenation constructor.
*
* @details
* Powers dart::operator + for the purposes of string concatenation.
*/
template <class Str = String, class EnableIf =
std::enable_if_t<
meta::is_detected<make_string_t, Str, shim::string_view, shim::string_view>::value
>
>
basic_string(shim::string_view base, shim::string_view app) :
val(value_type::make_string(base, app))
{}

/**
* @brief
* Constructor allows an existing packet instance to be wrapped
Expand Down Expand Up @@ -3511,6 +3563,23 @@ namespace dart {
>
basic_string& operator =(shim::string_view str) &;

/**
* @brief
* "In place" concatenation operator.
*
* @details
* Operator unfortunately does not actually work in place due to the fact
* that Dart strings are always precisely sized, not leaving room for
* additional characters like std::string.
* Concats the given suffix into a new string and assigns to itself
*/
template <class Str = String, class EnableIf =
std::enable_if_t<
meta::is_detected<make_string_t, Str, shim::string_view, shim::string_view>::value
>
>
basic_string& operator +=(shim::string_view str);

/**
* @brief
* Dereference operator.
Expand Down Expand Up @@ -3564,7 +3633,7 @@ namespace dart {
* @brief
* String conversion operator.
*/
explicit operator shim::string_view() const noexcept;
operator shim::string_view() const noexcept;

/**
* @brief
Expand Down Expand Up @@ -3835,7 +3904,7 @@ namespace dart {
std::is_integral<Arg>::value
>* = nullptr
>
explicit basic_number(Arg val) :
basic_number(Arg val) :
val(value_type::make_integer(val))
{}

Expand All @@ -3851,7 +3920,7 @@ namespace dart {
std::is_floating_point<Arg>::value
>* = nullptr
>
explicit basic_number(Arg val) :
basic_number(Arg val) :
val(value_type::make_decimal(val))
{}

Expand Down Expand Up @@ -4030,6 +4099,62 @@ namespace dart {
>
basic_number& operator =(Num val) &;

template <class Arg, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Number, Arg>::value
>
>
basic_number& operator +=(Arg val) noexcept;

template <class Arg, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Number, Arg>::value
>
>
basic_number& operator -=(Arg val) noexcept;

template <class Arg, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Number, Arg>::value
>
>
basic_number& operator *=(Arg val) noexcept;

template <class Arg, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Number, Arg>::value
>
>
basic_number& operator /=(Arg val) noexcept;

template <class Num = Number, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Num, double>::value
>
>
basic_number& operator ++() noexcept;

template <class Num = Number, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Num, double>::value
>
>
basic_number& operator --() noexcept;

template <class Num = Number, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Num, double>::value
>
>
basic_number operator ++(int) noexcept;

template <class Num = Number, class EnableIf =
std::enable_if_t<
meta::is_detected<make_decimal_t, Num, double>::value
>
>
basic_number operator --(int) noexcept;

/**
* @brief
* Dereference operator.
Expand Down Expand Up @@ -4076,14 +4201,19 @@ namespace dart {
/**
* @brief
* Machine type conversion operator.
*
* @details
* Operator logically exists to allow conversion into integral types,
* but is written in terms of operator T() to avoid overload ambiguity issues
*/
explicit operator int64_t() const noexcept;

/**
* @brief
* Machine type conversion operator.
*/
explicit operator double() const noexcept;
template <class T,
std::enable_if_t<
std::is_integral<T>::value
||
std::is_floating_point<T>::value
>* = nullptr
>
operator T() const noexcept;

/**
* @brief
Expand Down Expand Up @@ -5649,7 +5779,7 @@ namespace dart {
enabled
>
>
static basic_heap make_string(shim::string_view val);
static basic_heap make_string(shim::string_view base, shim::string_view app = "");

/**
* @brief
Expand Down Expand Up @@ -7689,7 +7819,7 @@ namespace dart {
basic_heap(detail::array_tag) :
data(make_shareable<RefCount<packet_elements>>())
{}
basic_heap(detail::string_tag, shim::string_view val);
basic_heap(detail::string_tag, shim::string_view base, shim::string_view);
basic_heap(detail::integer_tag, int64_t val) noexcept : data(val) {}
basic_heap(detail::decimal_tag, double val) noexcept : data(val) {}
basic_heap(detail::boolean_tag, bool val) noexcept : data(val) {}
Expand Down Expand Up @@ -10866,7 +10996,7 @@ namespace dart {
enabled
>
>
static basic_packet make_string(shim::string_view val);
static basic_packet make_string(shim::string_view base, shim::string_view app = "");

/**
* @brief
Expand Down
18 changes: 10 additions & 8 deletions include/dart/api.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -431,14 +431,16 @@ namespace dart {
}

template <class Number>
basic_number<Number>::operator int64_t() const noexcept {
if (is_integer()) return integer();
else return static_cast<int64_t>(decimal());
}

template <class Number>
basic_number<Number>::operator double() const noexcept {
return numeric();
template <class T,
std::enable_if_t<
std::is_integral<T>::value
||
std::is_floating_point<T>::value
>*
>
basic_number<Number>::operator T() const noexcept {
if (is_integer()) return static_cast<T>(integer());
else return static_cast<T>(decimal());
}

template <class Object>
Expand Down
7 changes: 4 additions & 3 deletions include/dart/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -1228,10 +1228,11 @@ namespace dart {
}

template <template <class> class RefCount>
raw_type identify_string(shim::string_view val) noexcept {
if (val.size() > std::numeric_limits<uint16_t>::max()) {
raw_type identify_string(shim::string_view base, shim::string_view app = "") noexcept {
auto total = base.size() + app.size();
if (total > std::numeric_limits<uint16_t>::max()) {
return detail::raw_type::big_string;
} else if (val.size() > sso_bytes<RefCount>()) {
} else if (total > sso_bytes<RefCount>()) {
return detail::raw_type::string;
} else {
return detail::raw_type::small_string;
Expand Down
8 changes: 6 additions & 2 deletions include/dart/conversion_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -1080,14 +1080,18 @@ namespace dart {
struct compare_impl<integer_tag> {
template <class Packet>
static bool compare(Packet const& pkt, int64_t val) noexcept {
return pkt.is_integer() && pkt.integer() == val;
if (pkt.is_integer()) return pkt.integer() == val;
else if (pkt.is_decimal()) return pkt.decimal() == val;
else return false;
}
};
template <>
struct compare_impl<decimal_tag> {
template <class Packet>
static bool compare(Packet const& pkt, double val) noexcept {
return pkt.is_decimal() && pkt.decimal() == val;
if (pkt.is_integer()) return pkt.integer() == val;
else if (pkt.is_decimal()) return pkt.decimal() == val;
else return false;
}
};
template <>
Expand Down
25 changes: 14 additions & 11 deletions include/dart/heap/string.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ namespace dart {

template <template <class> class RefCount>
template <bool enabled, class EnableIf>
basic_heap<RefCount> basic_heap<RefCount>::make_string(shim::string_view val) {
return basic_heap(detail::string_tag {}, val);
basic_heap<RefCount> basic_heap<RefCount>::make_string(shim::string_view base, shim::string_view app) {
return basic_heap(detail::string_tag {}, base, app);
}

template <template <class> class RefCount>
Expand Down Expand Up @@ -43,23 +43,25 @@ namespace dart {
}

template <template <class> class RefCount>
basic_heap<RefCount>::basic_heap(detail::string_tag, shim::string_view val) {
auto type = detail::identify_string<RefCount>(val);
basic_heap<RefCount>::basic_heap(detail::string_tag, shim::string_view base, shim::string_view app) {
auto len = base.size() + app.size();
auto type = detail::identify_string<RefCount>(base, app);
switch (type) {
case detail::raw_type::string:
case detail::raw_type::big_string:
{
// String is too large for SSO.
// Allocate some space and copy the string data in.
auto ptr = std::make_unique<char[]>(val.size() + 1);
std::copy(val.begin(), val.end(), ptr.get());
ptr[val.size()] = '\0';
auto ptr = std::make_unique<char[]>(len + 1);
std::copy(base.begin(), base.end(), ptr.get());
std::copy(app.begin(), app.end(), ptr.get() + base.size());
ptr[len] = '\0';

// Move the data in.
// FIXME: Turns out there's no portable way to use std::make_shared
// to allocate an array of characters in C++14.
auto shared = std::shared_ptr<char> {ptr.release(), +[] (char* ptr) { delete[] ptr; }};
data = detail::dynamic_string_layout {std::move(shared), val.size()};
data = detail::dynamic_string_layout {std::move(shared), len};
break;
}
default:
Expand All @@ -68,15 +70,16 @@ namespace dart {

// String is small enough for SSO, copy the string contents into the in-situ buffer.
detail::inline_string_layout layout;
std::copy(val.begin(), val.end(), layout.buffer.begin());
std::copy(base.begin(), base.end(), layout.buffer.begin());
std::copy(app.begin(), app.end(), layout.buffer.begin() + base.size());

// Terminate the string and set the number of remaining bytes.
// These two operations may touch the same byte.
// XXX: Have to access through std::array::data member as writing the null terminator
// is intentionally allowed to access 1 byte out of range if the string is the max
// SSO length, and MSVC asserts on out of bounds accesses in std::array.
layout.buffer.data()[val.size()] = '\0';
layout.left = static_cast<uint8_t>(sso_bytes) - static_cast<uint8_t>(val.size());
layout.buffer.data()[len] = '\0';
layout.left = static_cast<uint8_t>(sso_bytes) - static_cast<uint8_t>(len);
data = layout;
}
}
Expand Down
Loading