class std+, strings { private import rt::c; struct strings { mem dmem; offsets vector; index size_t; } func constructor() { constructor(this); this.mem.page = 0x2000; this.index = -1; } func destructor() { destructor(this); } func clear(free_mem bool = false) { if free_mem { this.mem->free(); else this.mem.used = 0; } this.offsets->clear(free_mem); this.index = -1; } func add(str. char, len size_t = 0) .char { var used size_t = this.mem.used; this.offsets->push_back(used); if !len; len = strlen(str); if len; this.mem->write(str, len); .this.mem->alloc_t() = 0; return this.mem.ptr + used; } func load_file(file_name. char, trim bool = true, ignore_blank bool = true) int { var stream void = fopen(file_name, "rb"); if stream == null; return -1; defer fclose(stream); if fgetc(stream) ~= 0xef or fgetc(stream) ~= 0xbb or fgetc(stream) ~= 0xbf { if fseek(stream, 0, SEEK_SET) < 0; return -1; } var count size_t = this.offsets->count(); var buf(0x2000) char; for ;; { if fgets(&buf, 0x2000, stream) == null; break; var line. char = &buf; var len size_t = strlen(line); if len and line[len - 1] == 10 { if len > 1 and line[len - 2] == 13 { len -= 2; else len -= 1; } line[len] = 0; } if trim { while isspace(.line); line += 1, len--; while len { if !isspace(line[len - 1]); break; len--; } } if !len and ignore_blank; continue; this->add(line, len); } return this.offsets->count() - count; } func split(str. char, del. char) uint { func = 1; var len size_t = strlen(del); var tmp. char; while (tmp = strstr(str, del)) ~= null; this->add(str, tmp - str), str = tmp + len, func++; this->add(str); } inline count() size_t { return this.offsets->count(); } inline empty() bool { return this.offsets->count() == 0; } inline item(index size_t) .char { return this.mem.ptr + .this.offsets->at(index); } func next_item(loop bool = false) .char { var count size_t = this->count(); if !count; return null; var index size_t = this.index; if index < count { func = this->item(index), this.index++; else this.index = 0; if index == -1 or loop { func = this->next_item(); else func = null; } } } func prev_item() .char { var index size_t = this.index; if index == -1; return null; var count size_t = this->count(); if !count; return null; if index and index < count { return this->item(index - 1); else return this->item(count - 1); } } func rollback() { var count size_t = this->count(); if count { if this.index ~= -1 { if this.index and this.index < count { this.index--; else this.index = count - 1; } } else this.index = -1; } } func first_item() .char { if !this->count(); return null; return this->item(0); } func last_item() .char { var count size_t = this->count(); if !count; return null; return this->item(count - 1); } func rnd_item() .char { var count size_t = this->count(); if !count; return null; return this->item(random(count)); } func join(str. string, del. char = null) .char { forvar index size_t = 0, count size_t = this->count(); index < count; index++ { str->append(this->item(index)); if del ~= null; str->append(del); } return str->ptr(); } func exists(str. char, index. size_t = null) bool { forvar i size_t = 0, c size_t = this->count(); i < c; i++ { if !strcmp(this->item(i), str) { if index ~= null; .index = i; return true; } } return false; } func existsi(str. char, index. size_t = null) bool { forvar i size_t = 0, c size_t = this->count(); i < c; i++ { if !strcasecmp(this->item(i), str) { if index ~= null; .index = i; return true; } } return false; } // fixme inline remove(index size_t) bool { return this.offsets->erase(index); } }