1
0
Эх сурвалжийг харах

replace format use of `std::stringstream` with `sprintf`

blueloveTH 2 жил өмнө
parent
commit
0af2855ce5

+ 3 - 3
include/pocketpy/cffi.h

@@ -48,9 +48,9 @@ struct VoidP{
     bool operator>=(const VoidP& other) const { return ptr >= other.ptr; }
 
     Str hex() const{
-        std::stringstream ss; // hex
-        ss << std::hex << reinterpret_cast<intptr_t>(ptr);
-        return "0x" + ss.str();
+        SStream ss;
+        ss.write_hex(ptr);
+        return ss.str();
     }
 
     static void _register(VM* vm, PyObject* mod, PyObject* type);

+ 0 - 2
include/pocketpy/common.h

@@ -3,13 +3,11 @@
 #include <cmath>
 #include <cstring>
 
-#include <sstream>
 #include <stdexcept>
 #include <vector>
 #include <string>
 #include <chrono>
 #include <string_view>
-#include <iomanip>
 #include <memory>
 #include <iostream>
 #include <map>

+ 18 - 24
include/pocketpy/str.h

@@ -127,37 +127,31 @@ struct SStream{
     PK_ALWAYS_PASS_BY_POINTER(SStream)
     // pod_vector<T> is allocated by pool64 so the buffer can be moved into Str without a copy
     pod_vector<char> buffer;
+    int _precision = -1;
+
     bool empty() const { return buffer.empty(); }
+    void setprecision(int precision) { _precision = precision; }
 
     SStream(){}
     SStream(int guess_size){ buffer.reserve(guess_size); }
 
     Str str();
 
-    SStream& operator<<(const Str& s);
-    SStream& operator<<(const char* s);
-    SStream& operator<<(i64 val);
-    SStream& operator<<(const std::string& s);
-    SStream& operator<<(std::string_view s);
-    SStream& operator<<(char c);
-    SStream& operator<<(StrName sn);
-    void write_hex(unsigned char c);
-
-    template<typename T>
-    SStream& operator<<(T val){
-        if constexpr(std::is_floating_point_v<T>){
-            if(std::isinf(val) || std::isnan(val)){
-                return (*this) << std::to_string(val);
-            }
-            std::stringstream ss; // float
-            ss << std::setprecision(std::numeric_limits<f64>::max_digits10-1) << val;
-            std::string s = ss.str();
-            if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0";
-            return (*this) << s;
-        }
-        (*this) << std::to_string(val);
-        return *this;
-    }
+    SStream& operator<<(const Str&);
+    SStream& operator<<(const char*);
+    SStream& operator<<(int);
+    SStream& operator<<(unsigned int);
+    SStream& operator<<(unsigned long);
+    SStream& operator<<(i64);
+    SStream& operator<<(f64);
+    SStream& operator<<(const std::string&);
+    SStream& operator<<(std::string_view);
+    SStream& operator<<(char);
+    SStream& operator<<(StrName);
+
+    void write_hex(unsigned char);
+    void write_hex(void*);
+    void write_hex(i64);
 };
 
 template<typename... Args>

+ 2 - 0
src/cffi.cpp

@@ -60,10 +60,12 @@ namespace pkpy{
                 char c = 0;
                 if(s[i]>='0' && s[i]<='9') c += s[i]-'0';
                 else if(s[i]>='A' && s[i]<='F') c += s[i]-'A'+10;
+                else if(s[i]>='a' && s[i]<='f') c += s[i]-'a'+10;
                 else vm->ValueError(fmt("invalid hex char: '", s[i], "'"));
                 c <<= 4;
                 if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0';
                 else if(s[i+1]>='A' && s[i+1]<='F') c += s[i+1]-'A'+10;
+                else if(s[i+1]>='a' && s[i+1]<='f') c += s[i+1]-'a'+10;
                 else vm->ValueError(fmt("invalid hex char: '", s[i+1], "'"));
                 buffer.p[i/2] = c;
             }

+ 12 - 12
src/linalg.cpp

@@ -117,9 +117,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
         }, {}, BindType::STATICMETHOD);
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
-            PyVec2& self = _CAST(PyVec2&, obj);
-            std::stringstream ss;
-            ss << std::fixed << std::setprecision(3);
+            Vec2 self = _CAST(PyVec2&, obj);
+            SStream ss;
+            ss.setprecision(3);
             ss << "vec2(" << self.x << ", " << self.y << ")";
             return VAR(ss.str());
         });
@@ -165,9 +165,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
-            PyVec3& self = _CAST(PyVec3&, obj);
-            std::stringstream ss;
-            ss << std::fixed << std::setprecision(3);
+            Vec3 self = _CAST(PyVec3&, obj);
+            SStream ss;
+            ss.setprecision(3);
             ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")";
             return VAR(ss.str());
         });
@@ -202,9 +202,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
-            PyVec4& self = _CAST(PyVec4&, obj);
-            std::stringstream ss;
-            ss << std::fixed << std::setprecision(3);
+            Vec4 self = _CAST(PyVec4&, obj);
+            SStream ss;
+            ss.setprecision(3);
             ss << "vec4(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")";
             return VAR(ss.str());
         });
@@ -261,9 +261,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
-            PyMat3x3& self = _CAST(PyMat3x3&, obj);
-            std::stringstream ss;
-            ss << std::fixed << std::setprecision(3);
+            const PyMat3x3& self = _CAST(PyMat3x3&, obj);
+            SStream ss;
+            ss.setprecision(3);
             ss << "mat3x3([" << self._11 << ", " << self._12 << ", " << self._13 << ",\n";
             ss << "        " << self._21 << ", " << self._22 << ", " << self._23 << ",\n";
             ss << "        " << self._31 << ", " << self._32 << ", " << self._33 << "])";

+ 7 - 6
src/pocketpy.cpp

@@ -254,9 +254,9 @@ void init_builtins(VM* _vm) {
     });
 
     _vm->bind_func<1>(_vm->builtins, "hex", [](VM* vm, ArgsView args) {
-        std::stringstream ss; // hex
-        ss << std::hex << CAST(i64, args[0]);
-        return VAR("0x" + ss.str());
+        SStream ss;
+        ss.write_hex(CAST(i64, args[0]));
+        return VAR(ss.str());
     });
 
     _vm->bind_func<1>(_vm->builtins, "iter", [](VM* vm, ArgsView args) {
@@ -300,9 +300,10 @@ void init_builtins(VM* _vm) {
     // tp_object
     _vm->bind__repr__(VM::tp_object, [](VM* vm, PyObject* obj) {
         if(is_tagged(obj)) PK_FATAL_ERROR();
-        std::stringstream ss; // hex
-        ss << "<" << _type_name(vm, vm->_tp(obj)) << " object at 0x";
-        ss << std::hex << reinterpret_cast<intptr_t>(obj) << ">";
+        SStream ss;
+        ss << "<" << _type_name(vm, vm->_tp(obj)) << " object at ";
+        ss.write_hex(obj);
+        ss << ">";
         return VAR(ss.str());
     });
 

+ 57 - 0
src/str.cpp

@@ -469,6 +469,19 @@ int utf8len(unsigned char c, bool suppress){
         return *this << sn.sv();
     }
 
+    SStream& SStream::operator<<(unsigned int val){
+        return (*this) << static_cast<i64>(val);
+    }
+
+    SStream& SStream::operator<<(unsigned long val){
+        // unsigned long could be out of range of `i64`, use `std::to_string` instead
+        return (*this) << std::to_string(val);
+    }
+
+    SStream& SStream::operator<<(int val){
+        return (*this) << static_cast<i64>(val);
+    }
+
     SStream& SStream::operator<<(i64 val){
         // str(-2**64).__len__() == 21
         buffer.reserve(buffer.size() + 24);
@@ -489,9 +502,53 @@ int utf8len(unsigned char c, bool suppress){
         return *this;
     }
 
+    SStream& SStream::operator<<(f64 val){
+        if(std::isinf(val) || std::isnan(val)){
+            return (*this) << std::to_string(val);
+        }
+        char b[32];
+        if(_precision == -1){
+            int prec = std::numeric_limits<f64>::max_digits10-1;
+            sprintf(b, "%.*g", prec, val);
+        }else{
+            int prec = _precision;
+            sprintf(b, "%.*f", prec, val);
+        }
+        (*this) << b;
+        if(std::all_of(b+1, b+strlen(b), isdigit)){
+            (*this) << ".0";
+        }
+        return *this;
+    }
+
     void SStream::write_hex(unsigned char c){
         *this << "0123456789ABCDEF"[c >> 4];
         *this << "0123456789ABCDEF"[c & 0xf];
     }
 
+    void SStream::write_hex(void* p){
+        (*this) << "0x";
+        uintptr_t p_t = reinterpret_cast<uintptr_t>(p);
+        for(int i=sizeof(void*)-1; i>=0; i--){
+            unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
+            write_hex(cpnt);
+        }
+    }
+
+    void SStream::write_hex(i64 val){
+        if(val < 0){
+            (*this) << "-";
+            val = -val;
+        }
+        (*this) << "0x";
+        if(val == 0){
+            (*this) << "0";
+            return;
+        }
+        for(int i=56; i>=0; i-=8){
+            unsigned char cpnt = (val >> i) & 0xff;
+            if(cpnt != 0) write_hex(cpnt);
+        }
+    }
+
 } // namespace pkpy

+ 3 - 3
src/vm.cpp

@@ -1,5 +1,4 @@
 #include "pocketpy/vm.h"
-#include "pocketpy/config.h"
 
 namespace pkpy{
 
@@ -507,8 +506,9 @@ PyObject* VM::_format_string(Str spec, PyObject* obj){
     if(type == 'f'){
         f64 val = CAST(f64, obj);
         if(precision < 0) precision = 6;
-        std::stringstream ss; // float
-        ss << std::fixed << std::setprecision(precision) << val;
+        SStream ss;
+        ss.setprecision(precision);
+        ss << val;
         ret = ss.str();
     }else if(type == 'd'){
         ret = std::to_string(CAST(i64, obj));