From e4b6d566a77f62c6685ec8384e4274840022e5e9 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 15 Oct 2023 21:36:30 +0800 Subject: [PATCH] add `SStream` --- include/pocketpy/cffi.h | 4 +- include/pocketpy/str.h | 64 ++++++++++++++++++++++----- include/pocketpy/vector.h | 13 ++++++ src/pocketpy.cpp | 2 +- src/str.cpp | 21 --------- tests/99_builtin_func.py | 93 --------------------------------------- 6 files changed, 68 insertions(+), 129 deletions(-) diff --git a/include/pocketpy/cffi.h b/include/pocketpy/cffi.h index 38b04987..a24b92b2 100644 --- a/include/pocketpy/cffi.h +++ b/include/pocketpy/cffi.h @@ -18,8 +18,8 @@ namespace pkpy { } \ static PyObject* register_class(VM* vm, PyObject* mod, Type base=0) { \ if(OBJ_NAME(mod) != #mod) { \ - auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \ - throw std::runtime_error(msg); \ + Str msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \ + throw std::runtime_error(msg.str()); \ } \ PyObject* type = vm->new_type_object(mod, #name, base); \ T::_register(vm, mod, type); \ diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index e0463858..f867e5f4 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -85,13 +85,6 @@ struct Str{ int u8_length() const; }; -template -std::string fmt(Args&&... args) { - std::stringstream ss; - (ss << ... << args); - return ss.str(); -} - struct StrName { uint16_t index; StrName(); @@ -127,13 +120,60 @@ struct StrName { static uint32_t _pesudo_random_index; }; -struct FastStrStream{ - pod_vector parts; - FastStrStream& operator<<(const Str& s); - bool empty() const { return parts.empty(); } - Str str() const; +struct SStream{ + PK_ALWAYS_PASS_BY_POINTER(SStream) + // pod_vector is allocated by pool64 so the buffer can be moved into Str without a copy + pod_vector buffer; + bool empty() const { return buffer.empty(); } + + SStream(){} + SStream(int guess_size){ buffer.reserve(guess_size); } + + Str str(){ + // after this call, the buffer is no longer valid + auto detached = buffer.detach(); + return Str(detached.first, detached.second); + } + + SStream& operator<<(const Str& s){ + buffer.extend(s.begin(), s.end()); + return *this; + } + + SStream& operator<<(const char* s){ + buffer.extend(s, s + strlen(s)); + return *this; + } + + SStream& operator<<(const std::string& s){ + buffer.extend(s.data(), s.data() + s.size()); + return *this; + } + + SStream& operator<<(std::string_view s){ + buffer.extend(s.data(), s.data() + s.size()); + return *this; + } + + SStream& operator<<(char c){ + buffer.push_back(c); + return *this; + } + + template + SStream& operator<<(T val){ + (*this) << std::to_string(val); + return *this; + } }; +template +Str fmt(Args&&... args) { + SStream ss; + (ss << ... << args); + return ss.str(); +} + struct CString{ const char* ptr; CString(const char* ptr): ptr(ptr) {} diff --git a/include/pocketpy/vector.h b/include/pocketpy/vector.h index 32b824a7..84814d58 100644 --- a/include/pocketpy/vector.h +++ b/include/pocketpy/vector.h @@ -72,10 +72,15 @@ struct pod_vector{ void pop_back() { _size--; } T popx_back() { T t = std::move(_data[_size-1]); _size--; return t; } + void extend(const pod_vector& other){ for(int i=0; i detach() noexcept { + T* p = _data; + int size = _size; + _data = nullptr; + _size = 0; + return {p, size}; + } + ~pod_vector() { if(_data!=nullptr) pool64_dealloc(_data); } diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index a14a0895..da384f37 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -677,7 +677,7 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("str", "join", [](VM* vm, ArgsView args) { auto _lock = vm->heap.gc_scope_lock(); const Str& self = _CAST(Str&, args[0]); - FastStrStream ss; + SStream ss; PyObject* it = vm->py_iter(args[1]); // strong ref PyObject* obj = vm->py_next(it); while(obj != vm->StopIteration){ diff --git a/src/str.cpp b/src/str.cpp index 96ba57d8..63259965 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -404,25 +404,4 @@ int utf8len(unsigned char c, bool suppress){ const std::string& str = _r_interned()[index]; return std::string_view(str); } - - FastStrStream& FastStrStream::operator<<(const Str& s){ - parts.push_back(&s); - return *this; - } - - Str FastStrStream::str() const{ - int len = 0; - bool is_ascii = true; - for(auto& s: parts){ - len += s->length(); - is_ascii &= s->is_ascii; - } - Str result(len, is_ascii); - char* p = result.data; - for(auto& s: parts){ - memcpy(p, s->data, s->length()); - p += s->length(); - } - return result; - } } // namespace pkpy \ No newline at end of file diff --git a/tests/99_builtin_func.py b/tests/99_builtin_func.py index 345b017e..5b9a1650 100644 --- a/tests/99_builtin_func.py +++ b/tests/99_builtin_func.py @@ -220,33 +220,6 @@ for i in range(128): assert l == ['0 \x00', '1 \x01', '2 \x02', '3 \x03', '4 \x04', '5 \x05', '6 \x06', '7 \x07', '8 \x08', '9 \t', '10 \n', '11 \x0b', '12 \x0c', '13 \r', '14 \x0e', '15 \x0f', '16 \x10', '17 \x11', '18 \x12', '19 \x13', '20 \x14', '21 \x15', '22 \x16', '23 \x17', '24 \x18', '25 \x19', '26 \x1a', '27 \x1b', '28 \x1c', '29 \x1d', '30 \x1e', '31 \x1f', '32 ', '33 !', '34 "', '35 #', '36 $', '37 %', '38 &', "39 '", '40 (', '41 )', '42 *', '43 +', '44 ,', '45 -', '46 .', '47 /', '48 0', '49 1', '50 2', '51 3', '52 4', '53 5', '54 6', '55 7', '56 8', '57 9', '58 :', '59 ;', '60 <', '61 =', '62 >', '63 ?', '64 @', '65 A', '66 B', '67 C', '68 D', '69 E', '70 F', '71 G', '72 H', '73 I', '74 J', '75 K', '76 L', '77 M', '78 N', '79 O', '80 P', '81 Q', '82 R', '83 S', '84 T', '85 U', '86 V', '87 W', '88 X', '89 Y', '90 Z', '91 [', '92 \\', '93 ]', '94 ^', '95 _', '96 `', '97 a', '98 b', '99 c', '100 d', '101 e', '102 f', '103 g', '104 h', '105 i', '106 j', '107 k', '108 l', '109 m', '110 n', '111 o', '112 p', '113 q', '114 r', '115 s', '116 t', '117 u', '118 v', '119 w', '120 x', '121 y', '122 z', '123 {', '124 |', '125 }', '126 ~', '127 \x7f'] - - - - - - - - - -# 未完全测试准确性----------------------------------------------- -# 116: 269: _vm->bind_builtin_func<1>("bin", [](VM* vm, ArgsView args) { -# #####: 270: std::stringstream ss; -# #####: 271: i64 x = CAST(i64, args[0]); -# #####: 272: if(x < 0){ ss << "-"; x = -x; } -# #####: 273: ss << "0b"; -# #####: 274: std::string bits; -# #####: 275: while(x){ -# #####: 276: bits += (x & 1) ? '1' : '0'; -# #####: 277: x >>= 1; -# -: 278: } -# #####: 279: std::reverse(bits.begin(), bits.end()); -# #####: 280: if(bits.empty()) bits = "0"; -# #####: 281: ss << bits; -# #####: 282: return VAR(ss.str()); -# #####: 283: }); -# test bin: - assert type(bin(1234)) is str # 无法测试, 不能覆盖----------------------------------------------- @@ -265,15 +238,6 @@ assert type(bin(1234)) is str # 10: 297: }); # test dir: - -# 未完全测试准确性----------------------------------------------- -# 116: 299: _vm->bind__repr__(_vm->tp_object, [](VM* vm, PyObject* obj) { -# #####: 300: if(is_tagged(obj)) FATAL_ERROR(); -# #####: 301: std::stringstream ss; -# #####: 302: ss << "<" << OBJ_NAME(vm->_t(obj)) << " object at 0x"; -# #####: 303: ss << std::hex << reinterpret_cast(obj) << ">"; -# #####: 304: return VAR(ss.str()); -# #####: 305: }); # test __repr__: class A(): def __init__(self): @@ -361,14 +325,6 @@ except: pass # /************ str ************/ -# 未完全测试准确性----------------------------------------------- -# 116: 495: _vm->bind_method<1>("str", "__rmul__", [](VM* vm, ArgsView args) { -# #####: 496: const Str& self = _CAST(Str&, args[0]); -# #####: 497: i64 n = CAST(i64, args[1]); -# #####: 498: std::stringstream ss; -# #####: 499: for(i64 i = 0; i < n; i++) ss << self.sv(); -# #####: 500: return VAR(ss.str()); -# #####: 501: }); # test str.__rmul__: assert type(12 * '12') is str @@ -600,16 +556,6 @@ assert type(hash(bytes([0x41, 0x42, 0x43]))) is int # 未完全测试准确性----------------------------------------------- -# 116: 928: _vm->bind__repr__(_vm->tp_bytes, [](VM* vm, PyObject* obj) { -# #####: 929: const Bytes& self = _CAST(Bytes&, obj); -# #####: 930: std::stringstream ss; -# #####: 931: ss << "b'"; -# #####: 932: for(int i=0; ibind__repr__(_vm->tp_slice, [](VM* vm, PyObject* obj) { -# #####: 958: const Slice& self = _CAST(Slice&, obj); -# #####: 959: std::stringstream ss; -# #####: 960: ss << "slice("; -# #####: 961: ss << CAST(Str, vm->py_repr(self.start)) << ", "; -# #####: 962: ss << CAST(Str, vm->py_repr(self.stop)) << ", "; -# #####: 963: ss << CAST(Str, vm->py_repr(self.step)) << ")"; -# #####: 964: return VAR(ss.str()); -# #####: 965: }); # test slice.__repr__ assert type(repr(slice(1,1,1))) is str @@ -744,19 +681,6 @@ except TypeError: pass # 未完全测试准确性----------------------------------------------- -# 116: 1009: _vm->bind__repr__(_vm->tp_mappingproxy, [](VM* vm, PyObject* obj) { -# #####: 1010: MappingProxy& self = _CAST(MappingProxy&, obj); -# #####: 1011: std::stringstream ss; -# #####: 1012: ss << "mappingproxy({"; -# -: 1013: bool first = true; -# #####: 1014: for(auto& item : self.attr().items()){ -# #####: 1015: if(!first) ss << ", "; -# -: 1016: first = false; -# #####: 1017: ss << item.first.escape() << ": " << CAST(Str, vm->py_repr(item.second)); -# -: 1018: } -# #####: 1019: ss << "})"; -# #####: 1020: return VAR(ss.str()); -# #####: 1021: }); # test mappingproxy.__repr__: class A(): def __init__(self): @@ -859,23 +783,6 @@ except: pass # 未完全测试准确性----------------------------------------------- -# 116: 1151: _vm->bind__repr__(_vm->tp_dict, [](VM* vm, PyObject* obj) { -# #####: 1152: Dict& self = _CAST(Dict&, obj); -# #####: 1153: std::stringstream ss; -# #####: 1154: ss << "{"; -# #####: 1155: bool first = true; -# -: 1156: -# #####: 1157: self.apply([&](PyObject* k, PyObject* v){ -# #####: 1158: if(!first) ss << ", "; -# #####: 1159: first = false; -# #####: 1160: Str key = CAST(Str&, vm->py_repr(k)); -# #####: 1161: Str value = CAST(Str&, vm->py_repr(v)); -# #####: 1162: ss << key << ": " << value; -# #####: 1163: }); -# -: 1164: -# #####: 1165: ss << "}"; -# #####: 1166: return VAR(ss.str()); -# #####: 1167: }); # test dict.__repr__ assert type(repr({1:2, 3:4})) is str