cpp

Coverage Report

Created: 2022-09-21 22:22

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