cpp

Coverage Report

Created: 2022-11-10 11:34

/home/andy/git/oilshell/oil/mycpp/leaky_builtins.cc
Line
Count
Source (jump to first uncovered line)
1
#include <ctype.h>  // isspace()
2
3
#include "mycpp/runtime.h"
4
5
// Translation of Python's print().
6
73
void print(Str* s) {
7
73
  fputs(s->data(), stdout);
8
73
  fputs("\n", stdout);
9
73
}
10
11
// Like print(..., file=sys.stderr), but Python code explicitly calls it.
12
219
void println_stderr(Str* s) {
13
219
  fputs(s->data(), stderr);
14
219
  fputs("\n", stderr);
15
219
}
16
17
18
Str* str(int i) {
18
18
  Str* s = OverAllocatedStr(kIntBufSize);
19
18
  int length = snprintf(s->data(), kIntBufSize, "%d", i);
20
18
  s->SetObjLenFromStrLen(length);
21
18
  return s;
22
18
}
23
24
7
Str* repr(Str* s) {
25
7
  mylib::FormatStringer f;
26
7
  f.format_r(s);
27
7
  return f.getvalue();
28
7
}
29
30
// Helper for str_to_int() that doesn't use exceptions.
31
39
bool StringToInteger(char* s, int length, int base, int* result) {
32
39
  if (length == 0) {
33
1
    return false;  // empty string isn't a valid integer
34
1
  }
35
36
38
  char* pos;  // mutated by strtol
37
38
  long v = strtol(s, &pos, base);
38
39
  // Unconditionally set out param.  Caller should use the return value!
40
38
  *result = v;
41
42
38
  switch (v) {
43
1
  case LONG_MIN:
44
1
    return false;  // underflow
45
1
  case LONG_MAX:
46
1
    return false;  // overflow
47
38
  }
48
49
36
  const char* end = s + length;
50
36
  if (pos == end) {
51
31
    return true;  // strtol() consumed ALL characters.
52
31
  }
53
54
7
  while (pos < end) {
55
6
    if (!isspace(*pos)) {
56
4
      return false;  // Trailing non-space
57
4
    }
58
2
    pos++;
59
2
  }
60
61
1
  return true;  // Trailing space is OK
62
5
}
63
64
4
int to_int(Str* s, int base) {
65
4
  int i;
66
4
  if (StringToInteger(s->data_, len(s), base, &i)) {
67
4
    return i;
68
4
  } else {
69
0
    throw Alloc<ValueError>();
70
0
  }
71
4
}
72
73
24
int to_int(Str* s) {
74
24
  int i;
75
24
  if (StringToInteger(s->data_, len(s), 10, &i)) {
76
22
    return i;
77
22
  } else {
78
2
    throw Alloc<ValueError>();
79
2
  }
80
24
}
81
82
431
Str* chr(int i) {
83
  // NOTE: i should be less than 256, in which we could return an object from
84
  // GLOBAL_STR() pool, like StrIter
85
431
  auto result = NewStr(1);
86
431
  result->data_[0] = i;
87
431
  return result;
88
431
}
89
90
434
int ord(Str* s) {
91
434
  assert(len(s) == 1);
92
  // signed to unsigned conversion, so we don't get values like -127
93
0
  uint8_t c = static_cast<uint8_t>(s->data_[0]);
94
434
  return c;
95
434
}
96
97
0
bool to_bool(Str* s) {
98
0
  return len(s) != 0;
99
0
}
100
101
0
double to_float(Str* s) {
102
0
  double result = atof(s->data_);
103
0
  return result;
104
0
}
105
106
// e.g. ('a' in 'abc')
107
72
bool str_contains(Str* haystack, Str* needle) {
108
  // Common case
109
72
  if (len(needle) == 1) {
110
66
    return memchr(haystack->data_, needle->data_[0], len(haystack));
111
66
  }
112
113
6
  if (len(needle) > len(haystack)) {
114
1
    return false;
115
1
  }
116
117
  // General case. TODO: We could use a smarter substring algorithm.
118
119
5
  const char* end = haystack->data_ + len(haystack);
120
5
  const char* last_possible = end - len(needle);
121
5
  const char* p = haystack->data_;
122
123
11
  while (p <= last_possible) {
124
10
    if (memcmp(p, needle->data_, len(needle)) == 0) {
125
4
      return true;
126
4
    }
127
6
    p++;
128
6
  }
129
1
  return false;
130
5
}
131
132
43
Str* str_repeat(Str* s, int times) {
133
  // Python allows -1 too, and Oil used that
134
43
  if (times <= 0) {
135
15
    return kEmptyString;
136
15
  }
137
28
  int len_ = len(s);
138
28
  int new_len = len_ * times;
139
28
  Str* result = NewStr(new_len);
140
141
28
  char* dest = result->data_;
142
117
  for (int i = 0; i < times; i++) {
143
89
    memcpy(dest, s->data_, len_);
144
89
    dest += len_;
145
89
  }
146
28
  return result;
147
43
}
148
149
// for os_path.join()
150
// NOTE(Jesse): Perfect candidate for BoundedBuffer
151
9
Str* str_concat3(Str* a, Str* b, Str* c) {
152
9
  int a_len = len(a);
153
9
  int b_len = len(b);
154
9
  int c_len = len(c);
155
156
9
  int new_len = a_len + b_len + c_len;
157
9
  Str* result = NewStr(new_len);
158
9
  char* pos = result->data_;
159
160
9
  memcpy(pos, a->data_, a_len);
161
9
  pos += a_len;
162
163
9
  memcpy(pos, b->data_, b_len);
164
9
  pos += b_len;
165
166
9
  memcpy(pos, c->data_, c_len);
167
168
9
  assert(pos + c_len == result->data_ + new_len);
169
170
0
  return result;
171
9
}
172
173
59
Str* str_concat(Str* a, Str* b) {
174
59
  int a_len = len(a);
175
59
  int b_len = len(b);
176
59
  int new_len = a_len + b_len;
177
59
  Str* result = NewStr(new_len);
178
59
  char* buf = result->data_;
179
180
59
  memcpy(buf, a->data_, a_len);
181
59
  memcpy(buf + a_len, b->data_, b_len);
182
183
59
  return result;
184
59
}
185
186
//
187
// Comparators
188
//
189
190
1.25k
bool str_equals(Str* left, Str* right) {
191
  // Fast path for identical strings.  String deduplication during GC could
192
  // make this more likely.  String interning could guarantee it, allowing us
193
  // to remove memcmp().
194
1.25k
  if (left == right) {
195
27
    return true;
196
27
  }
197
198
  // obj_len_ equal implies string lengths are equal
199
200
1.23k
  if (left->obj_len_ == right->obj_len_) {
201
441
    assert(len(left) == len(right));
202
0
    return memcmp(left->data_, right->data_, len(left)) == 0;
203
441
  }
204
205
790
  return false;
206
1.23k
}
207
208
4
bool maybe_str_equals(Str* left, Str* right) {
209
4
  if (left && right) {
210
2
    return str_equals(left, right);
211
2
  }
212
213
2
  if (!left && !right) {
214
0
    return true;  // None == None
215
0
  }
216
217
2
  return false;  // one is None and one is a Str*
218
2
}
219
220
// TODO(Jesse): Make an inline version of this
221
863
bool are_equal(Str* left, Str* right) {
222
863
  return str_equals(left, right);
223
863
}
224
225
// TODO(Jesse): Make an inline version of this
226
19
bool are_equal(int left, int right) {
227
19
  return left == right;
228
19
}
229
230
// TODO(Jesse): Make an inline version of this
231
159
bool keys_equal(int left, int right) {
232
159
  return left == right;
233
159
}
234
235
// TODO(Jesse): Make an inline version of this
236
820
bool keys_equal(Str* left, Str* right) {
237
820
  return are_equal(left, right);
238
820
}
239
240
0
bool are_equal(Tuple2<Str*, int>* t1, Tuple2<Str*, int>* t2) {
241
0
  bool result = are_equal(t1->at0(), t2->at0());
242
0
  result = result && (t1->at1() == t2->at1());
243
0
  return result;
244
0
}
245
246
59
bool str_equals0(const char* c_string, Str* s) {
247
59
  int n = strlen(c_string);
248
59
  if (len(s) == n) {
249
59
    return memcmp(s->data_, c_string, n) == 0;
250
59
  } else {
251
0
    return false;
252
0
  }
253
59
}