Skip to content

Commit

Permalink
[8_12] improve strategy of expanding string for performance
Browse files Browse the repository at this point in the history
* Revert "[8_12] Revert: improve strategy of expanding string for performance"

This reverts commit d4cfb60.

* adjust string layout

* improve performance of string initialization
  • Loading branch information
jingkaimori authored Jul 18, 2024
1 parent b4fa20c commit 3e42c62
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 15 deletions.
62 changes: 50 additions & 12 deletions Kernel/Types/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ round_length (int n) {
return i;
}

string_rep::string_rep (int n2)
: n (n2),
a ((n == 0) ? ((char*) NULL) : tm_new_array<char> (round_length (n))) {}
string_rep::string_rep (int n2) : n (n2), a_N (round_length (n2)), a (nullptr) {
if (a_N != 0) {
a= tm_new_array<char> (a_N);
}
}

void
string_rep::resize (int m) {
Expand All @@ -42,17 +44,53 @@ string_rep::resize (int m) {
if (mm != nn) {
if (mm != 0) {
if (nn != 0) {
a= tm_resize_array<char> (mm, a);
a_N= mm;
a = tm_resize_array<char> (mm, a);
}
else {
a= tm_new_array<char> (mm);
a_N= mm;
a = tm_new_array<char> (mm);
}
}
else if (nn != 0) tm_delete_array (a);
else if (nn != 0) {
tm_delete_array (a);
a_N= 0;
a = NULL;
};
}
n= m;
}

int
string_rep::expand_or_shrink_by (int delta) {
int old_n= n;
n+= delta;
reserve (n);
return old_n;
}

void
string_rep::reserve (int new_n) {
int old_size= a_N;
if (new_n != 0) {
if (old_size == 0) {
a_N= round_length (new_n);
a = tm_new_array<char> (a_N);
}
else if (old_size < new_n) {
a_N= round_length (new_n);
a = tm_resize_array<char> (a_N, a);
}
}
else {
if (old_size != 0) {
tm_delete_array (a);
a = NULL;
a_N= 0;
};
}
}

string::string (char c) {
rep = tm_new<string_rep> (1);
rep->a[0]= c;
Expand Down Expand Up @@ -138,17 +176,17 @@ copy (string s) {

string&
operator<< (string& a, char x) {
a->resize (N (a) + 1);
a[N (a) - 1]= x;
int old_a_N= a->expand_or_shrink_by (1);
a[old_a_N] = x;
return a;
}

string&
operator<< (string& a, string b) {
int i, k1= N (a), k2= N (b);
a->resize (k1 + k2);
for (i= 0; i < k2; i++)
a[i + k1]= b[i];
int b_N = N (b);
int old_a_N= a->expand_or_shrink_by (b_N);
for (int i= 0; i < b_N; i++)
a[i + old_a_N]= b[i];
return a;
}

Expand Down
26 changes: 24 additions & 2 deletions Kernel/Types/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,37 @@ class string;
class string_rep : concrete_struct {
int n;
char* a;
int a_N;

public:
inline string_rep () : n (0), a (NULL) {}
inline string_rep () : n (0), a_N (0), a (NULL) {}
string_rep (int n);
inline ~string_rep () {
if (n != 0) tm_delete_array (a);
if (a_N != 0) tm_delete_array (a);
}
/**
* @brief expand (or shrink) string by delta, but do not release memory when
* string is shrinked.
*
* @return string length before expansion
*/
int expand_or_shrink_by (int delta);

/**
* @brief expand (or shrink) string to given length n, and try to release
* memory when string is shrinked.
*
* @note expand_or_shrink_by may be faster if memory space is reserved
*/
void resize (int n);

/**
* @brief reserve memory space to contain at least n word in the whole string.
* Do not affect length of string, and do not release memory when n is smaller
* than current space.
*/
void reserve (int n);

friend class string;
friend inline int N (string a);
};
Expand Down
2 changes: 1 addition & 1 deletion bench/Kernel/Types/string_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ static ankerl::nanobench::Bench bench;
int
main () {
lolly::init_tbox ();
bench.minEpochTime (std::chrono::milliseconds (20));
bench.run ("construct string", [&] {
string ("abc");
string ();
Expand Down Expand Up @@ -43,7 +44,6 @@ main () {
static string a ("abcdefgh");
a (1, 6);
});
bench.minEpochIterations (40000);
bench.run ("concat string", [&] {
static string a ("abc"), b ("de");
a* b;
Expand Down
75 changes: 75 additions & 0 deletions tests/Kernel/Types/string_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,81 @@ TEST_CASE ("test append") {
CHECK_EQ (str == string ("xyz"), true);
}

TEST_CASE ("test append") {
auto str= string ();
str << 'x';
CHECK (str == "x");
str << string ("yz");
CHECK (str == "xyz");
}

TEST_CASE ("test reserve along with append") {

SUBCASE ("reserved more space") {
auto str= string ();
str->reserve (6);
str << 'x';
CHECK_EQ (str == "x", true);
str << string ("yz");
CHECK_EQ (str == "xyz", true);
str << string (": larger than reserved space");
CHECK_EQ (str == "xyz: larger than reserved space", true);
}
SUBCASE ("reserved the same space") {
auto str= string ("abc");
str->reserve (3);
CHECK_EQ (str == "abc", true);
}
SUBCASE ("reserved less space should take no effect") {
auto str= string ("abc");
str->reserve (2);
CHECK_EQ (str == "abc", true);
}
}

TEST_CASE ("test expand_or_shrink_by along with sub index") {

SUBCASE ("expand") {
auto str = string ("abc");
int previous_n= str->expand_or_shrink_by (1);
CHECK_EQ (previous_n, 3);
str[3]= 'd';
CHECK_EQ (str == "abcd", true);
}
SUBCASE ("shrink") {
auto str = string ("abc");
int previous_n= str->expand_or_shrink_by (-1);
CHECK_EQ (previous_n, 3);
CHECK_EQ (str == "ab", true);
}
SUBCASE ("delta 0 takes no effect") {
auto str = string ("abc");
int previous_n= str->expand_or_shrink_by (0);
CHECK_EQ (previous_n, 3);
CHECK_EQ (str == "abc", true);
}
}

TEST_CASE ("test resize") {

SUBCASE ("expand") {
auto str= string ("abc");
str->resize (4);
str[3]= 'd';
CHECK_EQ (str == "abcd", true);
}
SUBCASE ("shrink") {
auto str= string ("abc");
str->resize (2);
CHECK_EQ (str == "ab", true);
}
SUBCASE ("delta 0 takes no effect") {
auto str= string ("abc");
str->resize (3);
CHECK_EQ (str == "abc", true);
}
}

/******************************************************************************
* Conversions
******************************************************************************/
Expand Down

0 comments on commit 3e42c62

Please sign in to comment.