aboutsummaryrefslogtreecommitdiff
path: root/pseudocode-lib/string.cc
diff options
context:
space:
mode:
Diffstat (limited to 'pseudocode-lib/string.cc')
-rw-r--r--pseudocode-lib/string.cc158
1 files changed, 158 insertions, 0 deletions
diff --git a/pseudocode-lib/string.cc b/pseudocode-lib/string.cc
new file mode 100644
index 0000000..f2f03f6
--- /dev/null
+++ b/pseudocode-lib/string.cc
@@ -0,0 +1,158 @@
+#include <algorithm>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <exception>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+extern "C" int __cps_user_line;
+
+namespace {
+template <class Operation>
+decltype(auto) checked(Operation &&Op) {
+ try {
+ return std::forward<Operation>(Op)();
+ } catch (const std::exception &Error) {
+ std::fprintf(stderr, "[Fatal] line %d: %s\n", __cps_user_line, Error.what());
+ throw 0;
+ }
+}
+std::string &text(void *Handle) { return *static_cast<std::string *>(Handle); }
+}
+
+extern "C" {
+void *_string_impl_new() {
+ return checked([] { return new std::string; });
+}
+void *_string_impl_copy(void *Other) {
+ return checked([&] { return new std::string(text(Other)); });
+}
+void *_string_impl_from_cstr(const char *Text) {
+ return checked([&] { return new std::string(Text); });
+}
+void *_string_impl_from_count_char(long long Count, char Ch) {
+ return checked([&] {
+ if (Count < 0) throw std::invalid_argument("negative string length");
+ return new std::string(static_cast<std::size_t>(Count), Ch);
+ });
+}
+void _string_impl_delete(void *Handle) {
+ checked([&] { delete static_cast<std::string *>(Handle); });
+}
+void _string_impl_assign(void *Target, void *Other) {
+ checked([&] { text(Target) = text(Other); });
+}
+void _string_impl_assign_cstr(void *Target, const char *Text) {
+ checked([&] { text(Target) = Text; });
+}
+void _string_impl_concat(void *Target, void *A, void *B) {
+ checked([&] { text(Target) = text(A) + text(B); });
+}
+void _string_impl_from_int(void *Target, long long Number) {
+ checked([&] { text(Target) = std::to_string(Number); });
+}
+void _string_impl_from_real(void *Target, double Number) {
+ checked([&] { text(Target) = std::to_string(Number); });
+}
+double _string_impl_to_real(void *Handle) {
+ return checked([&] {
+ std::size_t Consumed = 0;
+ double Number = std::stod(text(Handle), &Consumed);
+ if (Consumed != text(Handle).size())
+ throw std::invalid_argument("unconsumed characters in string conversion");
+ return Number;
+ });
+}
+long long _string_impl_length(void *Handle) {
+ return checked([&] { return static_cast<long long>(text(Handle).size()); });
+}
+void _string_impl_left(void *Target, void *Handle, long long Count) {
+ checked([&] {
+ const auto &Source = text(Handle);
+ auto Length = Count <= 0 ? 0 : std::min(static_cast<std::size_t>(Count), Source.size());
+ text(Target) = Source.substr(0, Length);
+ });
+}
+void _string_impl_right(void *Target, void *Handle, long long Count) {
+ checked([&] {
+ const auto &Source = text(Handle);
+ auto Length = Count <= 0 ? 0 : std::min(static_cast<std::size_t>(Count), Source.size());
+ text(Target) = Source.substr(Source.size() - Length, Length);
+ });
+}
+void _string_impl_mid(void *Target, void *Handle, long long Start, long long Count) {
+ checked([&] {
+ const auto &Source = text(Handle);
+ auto Position = Start <= 1 ? 0 : std::min(static_cast<std::size_t>(Start - 1), Source.size());
+ auto Length = Count <= 0 ? 0 : std::min(static_cast<std::size_t>(Count), Source.size() - Position);
+ text(Target) = Source.substr(Position, Length);
+ });
+}
+void _string_impl_lcase(void *Target, void *Handle) {
+ checked([&] {
+ text(Target) = text(Handle);
+ for (char &Ch : text(Target))
+ Ch = static_cast<char>(std::tolower(static_cast<unsigned char>(Ch)));
+ });
+}
+char _string_impl_lcase_char(char Ch) {
+ return checked([&] {
+ return static_cast<char>(std::tolower(static_cast<unsigned char>(Ch)));
+ });
+}
+void _string_impl_ucase(void *Target, void *Handle) {
+ checked([&] {
+ text(Target) = text(Handle);
+ for (char &Ch : text(Target))
+ Ch = static_cast<char>(std::toupper(static_cast<unsigned char>(Ch)));
+ });
+}
+char _string_impl_ucase_char(char Ch) {
+ return checked([&] {
+ return static_cast<char>(std::toupper(static_cast<unsigned char>(Ch)));
+ });
+}
+long long _string_impl_asc(void *Handle) {
+ return checked([&]() -> long long {
+ const auto &Source = text(Handle);
+ return Source.empty() ? 0 : static_cast<unsigned char>(Source.front());
+ });
+}
+long long _string_impl_asc_char(char Ch) {
+ return checked([&]() -> long long { return static_cast<unsigned char>(Ch); });
+}
+void _string_impl_chr(void *Target, long long Code) {
+ checked([&] {
+ text(Target).assign(1, static_cast<char>(static_cast<unsigned char>(Code)));
+ });
+}
+int _string_impl_is_num(void *Handle) {
+ return checked([&]() -> int {
+ const auto &Source = text(Handle);
+ char *End = nullptr;
+ std::strtod(Source.c_str(), &End);
+ return !Source.empty() && End == Source.c_str() + Source.size();
+ });
+}
+const char *_string_impl_c_str(void *Handle) {
+ return text(Handle).c_str();
+}
+int _string_impl_compare(void *A, void *B) {
+ return checked([&] { return text(A).compare(text(B)); });
+}
+void _string_impl_input(void *Handle) {
+ checked([&] {
+ std::string Value;
+ int Ch;
+ do { Ch = std::getchar(); } while (Ch != EOF && std::isspace(static_cast<unsigned char>(Ch)));
+ while (Ch != EOF && !std::isspace(static_cast<unsigned char>(Ch))) {
+ Value.push_back(static_cast<char>(Ch));
+ Ch = std::getchar();
+ }
+ if (Ch != EOF) std::ungetc(Ch, stdin);
+ text(Handle) = std::move(Value);
+ });
+}
+}