From 9688d66591e6330007264aee0683a60ffcaef3fd Mon Sep 17 00:00:00 2001 From: Andy Chu Date: Thu, 26 Nov 2020 13:35:01 -0800 Subject: [PATCH] [my_runtime] Port more Str methods - char methods like isalpha - strip() methods It's nice to knock off the cstring-TODOs too! --- mycpp/gc_heap.h | 13 +++++ mycpp/my_runtime.cc | 123 ++++++++++++++++++++++++++++++++++++++- mycpp/my_runtime.h | 10 ++++ mycpp/my_runtime_test.cc | 74 ++++++++++++++++++----- mycpp/mylib_test.cc | 36 ------------ 5 files changed, 203 insertions(+), 53 deletions(-) diff --git a/mycpp/gc_heap.h b/mycpp/gc_heap.h index 9aad19ea27..462a06a4e9 100644 --- a/mycpp/gc_heap.h +++ b/mycpp/gc_heap.h @@ -527,12 +527,25 @@ class Str : public gc_heap::Obj { Str* index(int i); Str* slice(int begin); Str* slice(int begin, int end); + + Str* strip(); + // Used for CommandSub in osh/cmd_exec.py + Str* rstrip(Str* chars); + Str* rstrip(); + Str* replace(Str* old, Str* new_str); Str* join(List* items); + bool isdigit(); + bool isalpha(); + bool isupper(); int unique_id_; // index into intern table ? char data_[1]; // flexible array + private: + int _strip_left_pos(); + int _strip_right_pos(); + DISALLOW_COPY_AND_ASSIGN(Str) }; diff --git a/mycpp/my_runtime.cc b/mycpp/my_runtime.cc index 65dbdbc1f3..41e97417f4 100644 --- a/mycpp/my_runtime.cc +++ b/mycpp/my_runtime.cc @@ -2,7 +2,7 @@ #include "my_runtime.h" -#include // isspace() +#include // isspace(), isdigit() #include // va_list, etc. GLOBAL_STR(kEmptyString, ""); @@ -111,6 +111,127 @@ Str* str_repeat(Str* s, int times) { return result; } +// +// Str methods +// + +bool Str::isdigit() { + int n = len(this); + if (n == 0) { + return false; // special case + } + for (int i = 0; i < n; ++i) { + if (!::isdigit(data_[i])) { + return false; + } + } + return true; +} +bool Str::isalpha() { + int n = len(this); + if (n == 0) { + return false; // special case + } + for (int i = 0; i < n; ++i) { + if (!::isalpha(data_[i])) { + return false; + } + } + return true; +} + +// e.g. for osh/braces.py +bool Str::isupper() { + int n = len(this); + if (n == 0) { + return false; // special case + } + for (int i = 0; i < n; ++i) { + if (!::isupper(data_[i])) { + return false; + } + } + return true; +} + +// Helper for lstrip() and strip() +int Str::_strip_left_pos() { + assert(len(this) > 0); + + int i = 0; + int n = len(this); + bool done = false; + while (i < n && !done) { + switch (data_[i]) { + case ' ': + case '\t': + case '\r': + case '\n': + i++; + default: + done = true; + break; + } + } + return i; +} + +// Helper for rstrip() and strip() +int Str::_strip_right_pos() { + assert(len(this) > 0); + + int last = len(this) - 1; + int i = last; + bool done = false; + while (i > 0 && !done) { + switch (data_[i]) { + case ' ': + case '\t': + case '\r': + case '\n': + i--; + default: + done = true; + break; + } + } + return i; +} + +Str* Str::strip() { + int n = len(this); + if (n == 0) { + return this; + } + + int left_pos = _strip_left_pos(); + int right_pos = _strip_right_pos(); + if (left_pos == 0 && right_pos == n - 1) { + return this; + } + + // Copy part of data + int new_len = right_pos - left_pos + 1; + return NewStr(data_ + left_pos, new_len); +} + +// Used for CommandSub in osh/cmd_exec.py +Str* Str::rstrip(Str* chars) { + assert(0); +} + +Str* Str::rstrip() { + int n = len(this); + if (n == 0) { + return this; + } + int right_pos = _strip_right_pos(); + if (right_pos == n - 1) { // nothing stripped + return this; + } + return NewStr(data_, right_pos + 1); // Copy part of data_ +} + // Get a string with one character Str* Str::index(int i) { if (i < 0) { diff --git a/mycpp/my_runtime.h b/mycpp/my_runtime.h index e9b5ec2bf7..12f59f893c 100644 --- a/mycpp/my_runtime.h +++ b/mycpp/my_runtime.h @@ -107,6 +107,16 @@ void mysort(T* begin, T* end) { std::sort(begin, end, _cmp); } +// Is this only used by unit tests? +inline bool str_equals0(const char* c_string, Str* s) { + int n = strlen(c_string); + if (len(s) == n) { + return memcmp(s->data_, c_string, n) == 0; + } else { + return false; + } +} + // // Free Standing Str, List, and Dict Functions // diff --git a/mycpp/my_runtime_test.cc b/mycpp/my_runtime_test.cc index eea0f90fba..3db01cd3b5 100644 --- a/mycpp/my_runtime_test.cc +++ b/mycpp/my_runtime_test.cc @@ -122,7 +122,17 @@ TEST str_replace_test() { PASS(); } -TEST str_funcs_test() { +TEST str_methods_test() { + log("char funcs"); + ASSERT(!(NewStr(""))->isupper()); + ASSERT(!(NewStr("a"))->isupper()); + ASSERT((NewStr("A"))->isupper()); + ASSERT((NewStr("AB"))->isupper()); + + ASSERT((NewStr("abc"))->isalpha()); + ASSERT((NewStr("3"))->isdigit()); + ASSERT(!(NewStr(""))->isdigit()); + log("slice()"); ASSERT(str_equals(NewStr("f"), kString1->index(0))); @@ -134,20 +144,25 @@ TEST str_funcs_test() { ASSERT(str_equals(NewStr("o"), kString1->slice(-3, -2))); ASSERT(str_equals(NewStr("fo"), kString1->slice(-4, -2))); - ASSERT(str_equals(NewStr("foodfood"), str_concat(kString1, kString1))); + log("strip()"); + Str* s2 = NewStr(" abc "); + ASSERT(str_equals0(" abc", s2->rstrip())); - log("str_repeat()"); - Str* s = NewStr("abc"); + Str* s3 = NewStr(" def"); + ASSERT(str_equals0(" def", s3->rstrip())); - // -1 is allowed by Python and used by Oil! - ASSERT(str_equals(kEmptyString, str_repeat(s, -1))); - ASSERT(str_equals(kEmptyString, str_repeat(s, 0))); + Str* s4 = NewStr(""); + ASSERT(str_equals0("", s4->rstrip())); - Str* r1 = str_repeat(s, 1); - ASSERT(str_equals(s, r1)); + Str* s5 = NewStr(""); + ASSERT(str_equals0("", s5->strip())); - Str* r3 = str_repeat(s, 3); - ASSERT(str_equals(NewStr("abcabcabc"), r3)); + Str* st1 = (NewStr(" 123 "))->strip(); + ASSERT(str_equals0("123", st1)); + Str* st2 = (NewStr(" 123"))->strip(); + ASSERT(str_equals0("123", st2)); + Str* st3 = (NewStr("123 "))->strip(); + ASSERT(str_equals0("123", st3)); log("join()"); auto foo = NewStr("foo"); @@ -175,6 +190,27 @@ TEST str_funcs_test() { PASS(); } +TEST str_funcs_test() { + log("str_concat()"); + ASSERT(str_equals(NewStr("foodfood"), str_concat(kString1, kString1))); + ASSERT(str_equals(kEmptyString, str_concat(kEmptyString, kEmptyString))); + + log("str_repeat()"); + Str* s = NewStr("abc"); + + // -1 is allowed by Python and used by Oil! + ASSERT(str_equals(kEmptyString, str_repeat(s, -1))); + ASSERT(str_equals(kEmptyString, str_repeat(s, 0))); + + Str* r1 = str_repeat(s, 1); + ASSERT(str_equals(s, r1)); + + Str* r3 = str_repeat(s, 3); + ASSERT(str_equals(NewStr("abcabcabc"), r3)); + + PASS(); +} + TEST str_iters_test() { for (StrIter it(kString1); !it.Done(); it.Next()) { print(it.Value()); @@ -183,11 +219,7 @@ TEST str_iters_test() { PASS(); } -void ListFunc(std::initializer_list init) { - log("init.size() = %d", init.size()); -} - -TEST list_funcs_test() { +TEST list_methods_test() { auto ints = Alloc>(); ints->extend(std::initializer_list{5, 6, 7, 8}); @@ -238,6 +270,14 @@ TEST list_funcs_test() { ASSERT_EQ(0, len(ints)); ASSERT_EQ(0, ints->slab_->items_[0]); // make sure it's zero'd + PASS(); +} + +void ListFunc(std::initializer_list init) { + log("init.size() = %d", init.size()); +} + +TEST list_funcs_test() { auto L = list_repeat(nullptr, 3); ASSERT_EQ(3, len(L)); @@ -411,8 +451,10 @@ int main(int argc, char** argv) { RUN_TEST(print_test); RUN_TEST(str_to_int_test); RUN_TEST(str_replace_test); + RUN_TEST(str_methods_test); RUN_TEST(str_funcs_test); RUN_TEST(str_iters_test); + RUN_TEST(list_methods_test); RUN_TEST(list_funcs_test); RUN_TEST(list_iters_test); RUN_TEST(sort_test); diff --git a/mycpp/mylib_test.cc b/mycpp/mylib_test.cc index af7c427fe6..751c32949b 100644 --- a/mycpp/mylib_test.cc +++ b/mycpp/mylib_test.cc @@ -117,23 +117,6 @@ TEST test_str_to_int() { } TEST test_str_funcs() { - ASSERT(!(new Str(""))->isupper()); - ASSERT(!(new Str("a"))->isupper()); - ASSERT((new Str("A"))->isupper()); - ASSERT((new Str("AB"))->isupper()); - - ASSERT((new Str("abc"))->isalpha()); - - Str* s = new Str("abc"); - Str* r0 = str_repeat(s, 0); - ASSERT(str_equals0("", r0)); - - Str* r1 = str_repeat(s, 1); - ASSERT(str_equals0("abc", r1)); - - Str* r3 = str_repeat(s, 3); - ASSERT(str_equals0("abcabcabc", r3)); - Str* int_str; int_str = str((1 << 31) - 1); ASSERT(str_equals0("2147483647", int_str)); @@ -172,25 +155,6 @@ TEST test_str_funcs() { Str* re2 = s1->replace(new Str("bc"), new Str("--")); // ASSERT(str_equals(new Str("a--\0--d", 7), re1)); - Str* s2 = new Str(" abc "); - ASSERT(str_equals0(" abc", s2->rstrip())); - - Str* s3 = new Str(" def"); - ASSERT(str_equals0(" def", s3->rstrip())); - - Str* s4 = new Str(""); - ASSERT(str_equals0("", s4->rstrip())); - - Str* s5 = new Str(""); - ASSERT(str_equals0("", s5->strip())); - - Str* st1 = (new Str(" 123 "))->strip(); - ASSERT(str_equals0("123", st1)); - Str* st2 = (new Str(" 123"))->strip(); - ASSERT(str_equals0("123", st2)); - Str* st3 = (new Str("123 "))->strip(); - ASSERT(str_equals0("123", st3)); - ASSERT(s->startswith(new Str(""))); ASSERT(s->startswith(new Str("ab"))); ASSERT(s->startswith(s));