Skip to content

Commit

Permalink
(stdlib) Return non-const strings
Browse files Browse the repository at this point in the history
As elaborated on in
https://gitlab.perlang.org/perlang/perlang/-/merge_requests/538,
returning `const` strings can be a bit limiting. This is probably not a
good way to write idiomatic C++ code; I'll readily admit that I haven't
done much C++ programming in the last 20 years.

This change adjusts all return types to use non-`const` strings instead.
The caller can then cast the `unique_ptr<String>` etc. instances to a
`const` value as needed, but the other way around is much more awkward.

https://gitlab.perlang.org/perlang/perlang/-/merge_requests/544
  • Loading branch information
perlun committed Oct 24, 2024
1 parent 0404743 commit 6066409
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 62 deletions.
2 changes: 2 additions & 0 deletions release-notes/v0.6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- De-duplicate string concatenation operator implementations [[!536][536]]
- Avoid unnecessary `strdup()` call in `stdlib_wrappers.cc` [[!538][538]]
- Fix bug in string comparison of dynamic strings [[!540][540]]
- Return non-`const` strings [[!544][544]]

#### CI
- Add `dotnet test` CI job [[!499][499]]
Expand Down Expand Up @@ -119,3 +120,4 @@
[541]: https://gitlab.perlang.org/perlang/perlang/merge_requests/541
[542]: https://gitlab.perlang.org/perlang/perlang/merge_requests/542
[543]: https://gitlab.perlang.org/perlang/perlang/merge_requests/543
[544]: https://gitlab.perlang.org/perlang/perlang/merge_requests/544
22 changes: 11 additions & 11 deletions src/stdlib/src/ascii_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace perlang
{
std::unique_ptr<const ASCIIString> ASCIIString::from_static_string(const char* str)
std::unique_ptr<ASCIIString> ASCIIString::from_static_string(const char* str)
{
if (str == nullptr) {
throw std::invalid_argument("string argument cannot be null");
Expand All @@ -21,7 +21,7 @@ namespace perlang
return std::unique_ptr<ASCIIString>(result);
}

std::unique_ptr<const ASCIIString> ASCIIString::from_owned_string(const char* str, size_t length)
std::unique_ptr<ASCIIString> ASCIIString::from_owned_string(const char* str, size_t length)
{
if (str == nullptr) {
throw std::invalid_argument("str argument cannot be null");
Expand All @@ -32,7 +32,7 @@ namespace perlang
return std::unique_ptr<ASCIIString>(result);
}

std::unique_ptr<const ASCIIString> ASCIIString::from_copied_string(const char* str)
std::unique_ptr<ASCIIString> ASCIIString::from_copied_string(const char* str)
{
if (str == nullptr) {
throw std::invalid_argument("str argument cannot be null");
Expand Down Expand Up @@ -111,7 +111,7 @@ namespace perlang
}
}

std::unique_ptr<const String> ASCIIString::operator+(const String& rhs) const
std::unique_ptr<String> ASCIIString::operator+(const String& rhs) const
{
size_t length = this->length_ + rhs.length();
char *bytes = new char[length + 1];
Expand All @@ -124,7 +124,7 @@ namespace perlang
return from_owned_string(bytes, length);
}

std::unique_ptr<const ASCIIString> ASCIIString::operator+(const ASCIIString& rhs) const
std::unique_ptr<ASCIIString> ASCIIString::operator+(const ASCIIString& rhs) const
{
// Copy-paste is a bit ugly, but the alternative would perhaps also not be so pretty, calling the above method
// and doing some semi-ugly casting of the result.
Expand All @@ -139,37 +139,37 @@ namespace perlang
return from_owned_string(bytes, length);
}

std::unique_ptr<const String> ASCIIString::operator+(int64_t rhs) const
std::unique_ptr<String> ASCIIString::operator+(int64_t rhs) const
{
std::string str = std::to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> ASCIIString::operator+(uint64_t rhs) const
std::unique_ptr<String> ASCIIString::operator+(uint64_t rhs) const
{
std::string str = std::to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> ASCIIString::operator+(float rhs) const
std::unique_ptr<String> ASCIIString::operator+(float rhs) const
{
std::string str = internal::float_to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> ASCIIString::operator+(double rhs) const
std::unique_ptr<String> ASCIIString::operator+(double rhs) const
{
std::string str = internal::double_to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> ASCIIString::operator+(const BigInt& rhs) const
std::unique_ptr<String> ASCIIString::operator+(const BigInt& rhs) const
{
std::string str = rhs.to_string();
return *this + str;
}

std::unique_ptr<const String> ASCIIString::operator+(const std::string& rhs) const
std::unique_ptr<String> ASCIIString::operator+(const std::string& rhs) const
{
size_t length = this->length_ + rhs.length();
char *bytes = new char[length + 1];
Expand Down
26 changes: 13 additions & 13 deletions src/stdlib/src/ascii_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ namespace perlang
// parameter "borrow" the actual bytes_ used by the string. Since no deallocation will take place, and no
// mutation, copying the string at this point would just waste CPU cycles for no added benefit.
[[nodiscard]]
static std::unique_ptr<const ASCIIString> from_static_string(const char* str);
static std::unique_ptr<ASCIIString> from_static_string(const char* str);

// Creates a new ASCIIString from an "owned str", like a str that has been allocated on the heap. The
// ownership of the memory is transferred to the ASCIIString, which is then responsible for deallocating the
// memory when it is no longer needed (i.e. when no references to it remains).
[[nodiscard]]
static std::unique_ptr<const ASCIIString> from_owned_string(const char* str, size_t length);
static std::unique_ptr<ASCIIString> from_owned_string(const char* str, size_t length);

// Creates a new ASCIIString from an existing string, by copying its content to a new buffer allocated on the
// heap. The ASCIIString class takes ownership of the newly allocated buffer, which will be deallocated when the
// ASCIIString runs out of scope.
[[nodiscard]]
static std::unique_ptr<const ASCIIString> from_copied_string(const char* str);
static std::unique_ptr<ASCIIString> from_copied_string(const char* str);

private:
// Private constructor for creating a new ASCIIString from a C-style (NUL-terminated) string. The `owned`
Expand Down Expand Up @@ -75,49 +75,49 @@ namespace perlang

// Concatenates this string with another string. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const String> operator+(const String& rhs) const override;
std::unique_ptr<String> operator+(const String& rhs) const override;

// Concatenates this string with another string. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const ASCIIString> operator+(const ASCIIString& rhs) const;
std::unique_ptr<ASCIIString> operator+(const ASCIIString& rhs) const;

// Concatenates this string with an int32. The memory for the new string is allocated from the heap.
[[nodiscard]]
inline std::unique_ptr<const String> operator+(int32_t rhs) const override
inline std::unique_ptr<String> operator+(int32_t rhs) const override
{
return this->operator+(static_cast<int64_t>(rhs));
}

// Concatenates this string with an int64. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const String> operator+(int64_t rhs) const override;
std::unique_ptr<String> operator+(int64_t rhs) const override;

// Concatenates this string with a uint32. The memory for the new string is allocated from the heap.
[[nodiscard]]
inline std::unique_ptr<const String> operator+(uint32_t rhs) const override
inline std::unique_ptr<String> operator+(uint32_t rhs) const override
{
return this->operator+(static_cast<uint64_t>(rhs));
}

// Concatenates this string with a uint64. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const String> operator+(uint64_t rhs) const override;
std::unique_ptr<String> operator+(uint64_t rhs) const override;

// Concatenates this string with a float. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const String> operator+(float rhs) const override;
std::unique_ptr<String> operator+(float rhs) const override;

// Concatenates this string with a double. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const String> operator+(double rhs) const override;
std::unique_ptr<String> operator+(double rhs) const override;

// Concatenates this string with a BigInt. The memory for the new string is allocated from the heap.
[[nodiscard]]
std::unique_ptr<const String> operator+(const BigInt& rhs) const override;
std::unique_ptr<String> operator+(const BigInt& rhs) const override;

// Concatenates this string with a std::string. The memory for the new string is allocated from the heap.
[[nodiscard]]
inline std::unique_ptr<const String> operator+(const std::string& rhs) const;
inline std::unique_ptr<String> operator+(const std::string& rhs) const;

private:
// The backing byte array for this string. This is to be considered immutable and MUST NOT be modified at any
Expand Down
3 changes: 3 additions & 0 deletions src/stdlib/src/perlang_stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ namespace perlang
// for all the existing String types instead of just receiving `const String`-type parameters.
void print(const String* str);
void print(const ASCIIString& str);
void print(const std::unique_ptr<String>& str);
void print(const std::unique_ptr<const String>& str);
void print(const std::unique_ptr<ASCIIString>& str);
void print(const std::unique_ptr<const ASCIIString>& str);
void print(const std::unique_ptr<UTF8String>& str);
void print(const std::unique_ptr<const UTF8String>& str);
void print(const std::shared_ptr<const String>& str);
void print(const std::shared_ptr<const UTF8String>& str);
Expand Down
16 changes: 8 additions & 8 deletions src/stdlib/src/perlang_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,40 +29,40 @@ namespace perlang

// Concatenate this string with another string. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(const String& rhs) const = 0;
virtual std::unique_ptr<String> operator+(const String& rhs) const = 0;

// Concatenates this string with an int32. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(int32_t rhs) const
virtual std::unique_ptr<String> operator+(int32_t rhs) const
{
return this->operator+(static_cast<int64_t>(rhs));
}

// Concatenates this string with an int64. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(int64_t rhs) const = 0;
virtual std::unique_ptr<String> operator+(int64_t rhs) const = 0;

// Concatenates this string with a uint32. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(uint32_t rhs) const
virtual std::unique_ptr<String> operator+(uint32_t rhs) const
{
return this->operator+(static_cast<uint64_t>(rhs));
}

// Concatenates this string with a uint64. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(uint64_t rhs) const = 0;
virtual std::unique_ptr<String> operator+(uint64_t rhs) const = 0;

// Concatenates this string with a float. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(float rhs) const = 0;
virtual std::unique_ptr<String> operator+(float rhs) const = 0;

// Concatenates this string with a double. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(double rhs) const = 0;
virtual std::unique_ptr<String> operator+(double rhs) const = 0;

// Concatenates this string with a BigInt. The memory for the new string is allocated from the heap.
[[nodiscard]]
virtual std::unique_ptr<const String> operator+(const BigInt& rhs) const = 0;
virtual std::unique_ptr<String> operator+(const BigInt& rhs) const = 0;
};
}
15 changes: 15 additions & 0 deletions src/stdlib/src/print.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,31 @@ namespace perlang
print(&str);
}

void print(const std::unique_ptr<String>& str)
{
print(str.get());
}

void print(const std::unique_ptr<const String>& str)
{
print(str.get());
}

void print(const std::unique_ptr<ASCIIString>& str)
{
print(str.get());
}

void print(const std::unique_ptr<const ASCIIString>& str)
{
print(str.get());
}

void print(const std::unique_ptr<UTF8String>& str)
{
print(str.get());
}

void print(const std::unique_ptr<const UTF8String>& str)
{
print(str.get());
Expand Down
30 changes: 15 additions & 15 deletions src/stdlib/src/utf8_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace perlang
{
std::unique_ptr<const UTF8String> UTF8String::from_static_string(const char* s)
std::unique_ptr<UTF8String> UTF8String::from_static_string(const char* s)
{
if (s == nullptr) {
throw std::invalid_argument("string argument cannot be null");
Expand All @@ -30,7 +30,7 @@ namespace perlang
return std::unique_ptr<UTF8String>(result);
}

std::unique_ptr<const UTF8String> UTF8String::from_copied_string(const char* str)
std::unique_ptr<UTF8String> UTF8String::from_copied_string(const char* str)
{
if (str == nullptr) {
throw std::invalid_argument("str argument cannot be null");
Expand Down Expand Up @@ -99,7 +99,7 @@ namespace perlang
return !(rhs == *this);
}

std::unique_ptr<const String> UTF8String::operator+(const String& rhs) const
std::unique_ptr<String> UTF8String::operator+(const String& rhs) const
{
size_t length = this->length_ + rhs.length();
char *bytes = new char[length + 1];
Expand All @@ -112,7 +112,7 @@ namespace perlang
return from_owned_string(bytes, length);
}

std::unique_ptr<const UTF8String> UTF8String::operator+(const UTF8String& rhs) const
std::unique_ptr<UTF8String> UTF8String::operator+(const UTF8String& rhs) const
{
size_t length = this->length_ + rhs.length();
char *bytes = new char[length + 1];
Expand All @@ -124,31 +124,31 @@ namespace perlang
return from_owned_string(bytes, length);
}

std::unique_ptr<const String> UTF8String::operator+(const int64_t rhs) const
std::unique_ptr<String> UTF8String::operator+(const int64_t rhs) const
{
std::string str = std::to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> UTF8String::operator+(const uint64_t rhs) const
std::unique_ptr<String> UTF8String::operator+(const uint64_t rhs) const
{
std::string str = std::to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> UTF8String::operator+(float rhs) const
std::unique_ptr<String> UTF8String::operator+(float rhs) const
{
std::string str = internal::float_to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> UTF8String::operator+(double rhs) const
std::unique_ptr<String> UTF8String::operator+(double rhs) const
{
std::string str = internal::double_to_string(rhs);
return *this + str;
}

std::unique_ptr<const String> UTF8String::operator+(const std::string& rhs) const
std::unique_ptr<String> UTF8String::operator+(const std::string& rhs) const
{
size_t length = this->length_ + rhs.length();
char *bytes = new char[length + 1];
Expand All @@ -160,37 +160,37 @@ namespace perlang
return from_owned_string(bytes, length);
}

std::unique_ptr<const String> UTF8String::operator+(const BigInt& rhs) const
std::unique_ptr<String> UTF8String::operator+(const BigInt& rhs) const
{
std::string str = rhs.to_string();
return *this + str;
}

std::unique_ptr<const UTF8String> operator+(const int64_t lhs, const UTF8String& rhs)
std::unique_ptr<UTF8String> operator+(const int64_t lhs, const UTF8String& rhs)
{
std::string str = std::to_string(lhs);
return str + rhs;
}

std::unique_ptr<const UTF8String> operator+(const uint64_t lhs, const UTF8String& rhs)
std::unique_ptr<UTF8String> operator+(const uint64_t lhs, const UTF8String& rhs)
{
std::string str = std::to_string(lhs);
return str + rhs;
}

std::unique_ptr<const UTF8String> operator+(const float lhs, const UTF8String& rhs)
std::unique_ptr<UTF8String> operator+(const float lhs, const UTF8String& rhs)
{
std::string str = internal::float_to_string(lhs);
return str + rhs;
}

std::unique_ptr<const UTF8String> operator+(const double lhs, const UTF8String& rhs)
std::unique_ptr<UTF8String> operator+(const double lhs, const UTF8String& rhs)
{
std::string str = internal::double_to_string(lhs);
return str + rhs;
}

std::unique_ptr<const UTF8String> operator+(const std::string& lhs, const UTF8String& rhs)
std::unique_ptr<UTF8String> operator+(const std::string& lhs, const UTF8String& rhs)
{
size_t length = lhs.length() + rhs.length();
char *bytes = new char[length + 1];
Expand Down
Loading

0 comments on commit 6066409

Please sign in to comment.