Skip to content

Commit

Permalink
[my_runtime] Port more Str methods
Browse files Browse the repository at this point in the history
- char methods like isalpha
- strip() methods

It's nice to knock off the cstring-TODOs too!
  • Loading branch information
Andy Chu committed Nov 26, 2020
1 parent 0e40749 commit 9688d66
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 53 deletions.
13 changes: 13 additions & 0 deletions mycpp/gc_heap.h
Expand Up @@ -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<Str*>* 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)
};

Expand Down
123 changes: 122 additions & 1 deletion mycpp/my_runtime.cc
Expand Up @@ -2,7 +2,7 @@

#include "my_runtime.h"

#include <ctype.h> // isspace()
#include <ctype.h> // isspace(), isdigit()
#include <cstdarg> // va_list, etc.

GLOBAL_STR(kEmptyString, "");
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 10 additions & 0 deletions mycpp/my_runtime.h
Expand Up @@ -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
//
Expand Down
74 changes: 58 additions & 16 deletions mycpp/my_runtime_test.cc
Expand Up @@ -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)));

Expand All @@ -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");
Expand Down Expand Up @@ -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());
Expand All @@ -183,11 +219,7 @@ TEST str_iters_test() {
PASS();
}

void ListFunc(std::initializer_list<Str*> init) {
log("init.size() = %d", init.size());
}

TEST list_funcs_test() {
TEST list_methods_test() {
auto ints = Alloc<List<int>>();
ints->extend(std::initializer_list<int>{5, 6, 7, 8});

Expand Down Expand Up @@ -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<Str*> init) {
log("init.size() = %d", init.size());
}

TEST list_funcs_test() {
auto L = list_repeat<Str*>(nullptr, 3);
ASSERT_EQ(3, len(L));

Expand Down Expand Up @@ -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);
Expand Down
36 changes: 0 additions & 36 deletions mycpp/mylib_test.cc
Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit 9688d66

Please sign in to comment.