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

some important changes

1. add `colorsys`
2. handle `__all__` in modules
3. `is_pod` for c++17/20
BLUELOVETH 2 жил өмнө
parent
commit
f0ca29a30a

+ 8 - 0
docs/modules/colorsys.md

@@ -0,0 +1,8 @@
+---
+icon: package
+label: colorsys
+---
+
+The same as the standard library module `colorsys` in python 3.11.
+
+https://github.com/python/cpython/blob/3.11/Lib/colorsys.py

+ 3 - 3
include/pocketpy/cffi.h

@@ -83,7 +83,7 @@ struct C99Struct{
 
     template<typename T>
     C99Struct(std::monostate _, const T& data): C99Struct(sizeof(T)){
-        static_assert(std::is_pod_v<T>);
+        static_assert(is_pod<T>::value);
         static_assert(!std::is_pointer_v<T>);
         memcpy(p, &data, this->size);
     }
@@ -156,13 +156,13 @@ T to_void_p(VM* vm, PyObject* var){
 
 template<typename T>
 T to_c99_struct(VM* vm, PyObject* var){
-    static_assert(std::is_pod_v<T>);
+    static_assert(is_pod<T>::value);
     C99Struct& pod = CAST(C99Struct&, var);
     return *reinterpret_cast<T*>(pod.p);
 }
 
 template<typename T>
-std::enable_if_t<std::is_pod_v<T> && !std::is_pointer_v<T>, PyObject*> py_var(VM* vm, const T& data){
+std::enable_if_t<is_pod<T>::value && !std::is_pointer_v<T>, PyObject*> py_var(VM* vm, const T& data){
     return VAR_T(C99Struct, std::monostate(), data);
 }
 /*****************************************************************/

+ 7 - 0
include/pocketpy/common.h

@@ -156,4 +156,11 @@ inline bool is_both_float(PyObject* a, PyObject* b) noexcept {
 inline PyObject* const PY_NULL = (PyObject*)0b000011;		// tagged null
 inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
 inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
+
+// is_pod<> for c++17 and c++20
+template<typename T>
+struct is_pod {
+	static constexpr bool value = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
+};
+
 } // namespace pkpy

+ 1 - 1
include/pocketpy/namedict.h

@@ -19,7 +19,7 @@ struct NameDictImpl {
     using Item = std::pair<StrName, T>;
     static constexpr uint16_t __Capacity = 8;
     // ensure the initial capacity is ok for memory pool
-    static_assert(std::is_pod_v<T>);
+    static_assert(is_pod<T>::value);
     static_assert(sizeof(Item) * __Capacity <= 128);
 
     float _load_factor;

+ 2 - 2
include/pocketpy/obj.h

@@ -214,7 +214,7 @@ __T py_cast(VM* vm, PyObject* obj) {
     }else if constexpr(is_py_class<T>::value){
         T::_check_type(vm, obj);
         return PK_OBJ_GET(T, obj);
-    }else if constexpr(std::is_pod_v<T>){
+    }else if constexpr(is_pod<T>::value){
         return to_c99_struct<T>(vm, obj);
     }else {
         return Discarded();
@@ -230,7 +230,7 @@ __T _py_cast(VM* vm, PyObject* obj) {
         return to_void_p<__T>(vm, obj);
     }else if constexpr(is_py_class<T>::value){
         return PK_OBJ_GET(T, obj);
-    }else if constexpr(std::is_pod_v<T>){
+    }else if constexpr(is_pod<T>::value){
         return to_c99_struct<T>(vm, obj);
     }else {
         return Discarded();

+ 1 - 0
include/pocketpy/str.h

@@ -182,6 +182,7 @@ const StrName __divmod__ = StrName::get("__divmod__");
 const StrName __enter__ = StrName::get("__enter__");
 const StrName __exit__ = StrName::get("__exit__");
 const StrName __name__ = StrName::get("__name__");
+const StrName __all__ = StrName::get("__all__");
 
 const StrName pk_id_add = StrName::get("add");
 const StrName pk_id_set = StrName::get("set");

+ 1 - 1
include/pocketpy/vector.h

@@ -8,7 +8,7 @@ namespace pkpy{
 template<typename T>
 struct pod_vector{
     static_assert(64 % sizeof(T) == 0);
-    static_assert(std::is_pod_v<T>);
+    static_assert(is_pod<T>::value);
     static constexpr int N = 64 / sizeof(T);
     static_assert(N >= 4);
     int _size;

+ 166 - 0
python/colorsys.py

@@ -0,0 +1,166 @@
+"""Conversion functions between RGB and other color systems.
+
+This modules provides two functions for each color system ABC:
+
+  rgb_to_abc(r, g, b) --> a, b, c
+  abc_to_rgb(a, b, c) --> r, g, b
+
+All inputs and outputs are triples of floats in the range [0.0...1.0]
+(with the exception of I and Q, which covers a slightly larger range).
+Inputs outside the valid range may cause exceptions or invalid outputs.
+
+Supported color systems:
+RGB: Red, Green, Blue components
+YIQ: Luminance, Chrominance (used by composite video signals)
+HLS: Hue, Luminance, Saturation
+HSV: Hue, Saturation, Value
+"""
+
+# References:
+# http://en.wikipedia.org/wiki/YIQ
+# http://en.wikipedia.org/wiki/HLS_color_space
+# http://en.wikipedia.org/wiki/HSV_color_space
+
+__all__ = ["rgb_to_yiq","yiq_to_rgb","rgb_to_hls","hls_to_rgb",
+           "rgb_to_hsv","hsv_to_rgb"]
+
+# Some floating point constants
+
+ONE_THIRD = 1.0/3.0
+ONE_SIXTH = 1.0/6.0
+TWO_THIRD = 2.0/3.0
+
+# YIQ: used by composite video signals (linear combinations of RGB)
+# Y: perceived grey level (0.0 == black, 1.0 == white)
+# I, Q: color components
+#
+# There are a great many versions of the constants used in these formulae.
+# The ones in this library uses constants from the FCC version of NTSC.
+
+def rgb_to_yiq(r, g, b):
+    y = 0.30*r + 0.59*g + 0.11*b
+    i = 0.74*(r-y) - 0.27*(b-y)
+    q = 0.48*(r-y) + 0.41*(b-y)
+    return (y, i, q)
+
+def yiq_to_rgb(y, i, q):
+    # r = y + (0.27*q + 0.41*i) / (0.74*0.41 + 0.27*0.48)
+    # b = y + (0.74*q - 0.48*i) / (0.74*0.41 + 0.27*0.48)
+    # g = y - (0.30*(r-y) + 0.11*(b-y)) / 0.59
+
+    r = y + 0.9468822170900693*i + 0.6235565819861433*q
+    g = y - 0.27478764629897834*i - 0.6356910791873801*q
+    b = y - 1.1085450346420322*i + 1.7090069284064666*q
+
+    if r < 0.0:
+        r = 0.0
+    if g < 0.0:
+        g = 0.0
+    if b < 0.0:
+        b = 0.0
+    if r > 1.0:
+        r = 1.0
+    if g > 1.0:
+        g = 1.0
+    if b > 1.0:
+        b = 1.0
+    return (r, g, b)
+
+
+# HLS: Hue, Luminance, Saturation
+# H: position in the spectrum
+# L: color lightness
+# S: color saturation
+
+def rgb_to_hls(r, g, b):
+    maxc = max(r, g, b)
+    minc = min(r, g, b)
+    sumc = (maxc+minc)
+    rangec = (maxc-minc)
+    l = sumc/2.0
+    if minc == maxc:
+        return 0.0, l, 0.0
+    if l <= 0.5:
+        s = rangec / sumc
+    else:
+        s = rangec / (2.0-maxc-minc)  # Not always 2.0-sumc: gh-106498.
+    rc = (maxc-r) / rangec
+    gc = (maxc-g) / rangec
+    bc = (maxc-b) / rangec
+    if r == maxc:
+        h = bc-gc
+    elif g == maxc:
+        h = 2.0+rc-bc
+    else:
+        h = 4.0+gc-rc
+    h = (h/6.0) % 1.0
+    return h, l, s
+
+def hls_to_rgb(h, l, s):
+    if s == 0.0:
+        return l, l, l
+    if l <= 0.5:
+        m2 = l * (1.0+s)
+    else:
+        m2 = l+s-(l*s)
+    m1 = 2.0*l - m2
+    return (_v(m1, m2, h+ONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))
+
+def _v(m1, m2, hue):
+    hue = hue % 1.0
+    if hue < ONE_SIXTH:
+        return m1 + (m2-m1)*hue*6.0
+    if hue < 0.5:
+        return m2
+    if hue < TWO_THIRD:
+        return m1 + (m2-m1)*(TWO_THIRD-hue)*6.0
+    return m1
+
+
+# HSV: Hue, Saturation, Value
+# H: position in the spectrum
+# S: color saturation ("purity")
+# V: color brightness
+
+def rgb_to_hsv(r, g, b):
+    maxc = max(r, g, b)
+    minc = min(r, g, b)
+    rangec = (maxc-minc)
+    v = maxc
+    if minc == maxc:
+        return 0.0, 0.0, v
+    s = rangec / maxc
+    rc = (maxc-r) / rangec
+    gc = (maxc-g) / rangec
+    bc = (maxc-b) / rangec
+    if r == maxc:
+        h = bc-gc
+    elif g == maxc:
+        h = 2.0+rc-bc
+    else:
+        h = 4.0+gc-rc
+    h = (h/6.0) % 1.0
+    return h, s, v
+
+def hsv_to_rgb(h, s, v):
+    if s == 0.0:
+        return v, v, v
+    i = int(h*6.0) # XXX assume int() truncates!
+    f = (h*6.0) - i
+    p = v*(1.0 - s)
+    q = v*(1.0 - s*f)
+    t = v*(1.0 - s*(1.0-f))
+    i = i%6
+    if i == 0:
+        return v, t, p
+    if i == 1:
+        return q, v, p
+    if i == 2:
+        return p, v, t
+    if i == 3:
+        return p, q, v
+    if i == 4:
+        return t, p, v
+    if i == 5:
+        return v, p, q
+    # Cannot get here

+ 19 - 6
src/ceval.cpp

@@ -598,15 +598,28 @@ __NEXT_STEP:;
         _name = StrName(byte.arg);
         PUSH(py_import(_name, true));
         DISPATCH();
-    TARGET(IMPORT_STAR)
+    TARGET(IMPORT_STAR) {
         _0 = POPX();
-        for(auto& [name, value]: _0->attr().items()){
-            std::string_view s = name.sv();
-            if(s.empty() || s[0] == '_') continue;
-            frame->f_globals().set(name, value);
+        _1 = _0->attr().try_get(__all__);
+        if(_1 != nullptr){
+            for(PyObject* key: CAST(List&, _1)){
+                _name = StrName::get(CAST(Str&, key).sv());
+                PyObject* value = _0->attr().try_get(_name);
+                if(value == nullptr){
+                    _error("ImportError", fmt("cannot import name ", _name.escape()));
+                }else{
+                    frame->f_globals().set(_name, value);
+                }
+            }
+        }else{
+            for(auto& [name, value]: _0->attr().items()){
+                std::string_view s = name.sv();
+                if(s.empty() || s[0] == '_') continue;
+                frame->f_globals().set(name, value);
+            }
         }
         frame->f_globals()._try_perfect_rehash();
-        DISPATCH();
+    } DISPATCH();
     /*****************************************/
     TARGET(UNPACK_SEQUENCE){
         auto _lock = heap.gc_scope_lock();  // lock the gc via RAII!!

+ 1 - 1
src/pocketpy.cpp

@@ -1489,7 +1489,7 @@ void VM::post_init(){
     add_module_base64(this);
     add_module_timeit(this);
 
-    for(const char* name: {"this", "functools", "collections", "heapq", "bisect", "pickle", "_long"}){
+    for(const char* name: {"this", "functools", "collections", "heapq", "bisect", "pickle", "_long", "colorsys"}){
         _lazy_modules[name] = kPythonLibs[name];
     }