From f0ca29a30a5a52ca07dd77080f8cabb21d9a6db7 Mon Sep 17 00:00:00 2001 From: BLUELOVETH Date: Wed, 2 Aug 2023 13:04:39 +0800 Subject: [PATCH] some important changes 1. add `colorsys` 2. handle `__all__` in modules 3. `is_pod` for c++17/20 --- docs/modules/colorsys.md | 8 ++ include/pocketpy/cffi.h | 6 +- include/pocketpy/common.h | 7 ++ include/pocketpy/namedict.h | 2 +- include/pocketpy/obj.h | 4 +- include/pocketpy/str.h | 1 + include/pocketpy/vector.h | 2 +- python/colorsys.py | 166 ++++++++++++++++++++++++++++++++++++ src/ceval.cpp | 25 ++++-- src/pocketpy.cpp | 2 +- 10 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 docs/modules/colorsys.md create mode 100644 python/colorsys.py diff --git a/docs/modules/colorsys.md b/docs/modules/colorsys.md new file mode 100644 index 00000000..12b74be1 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/include/pocketpy/cffi.h b/include/pocketpy/cffi.h index 1aade54c..da76a9d8 100644 --- a/include/pocketpy/cffi.h +++ b/include/pocketpy/cffi.h @@ -83,7 +83,7 @@ struct C99Struct{ template C99Struct(std::monostate _, const T& data): C99Struct(sizeof(T)){ - static_assert(std::is_pod_v); + static_assert(is_pod::value); static_assert(!std::is_pointer_v); memcpy(p, &data, this->size); } @@ -156,13 +156,13 @@ T to_void_p(VM* vm, PyObject* var){ template T to_c99_struct(VM* vm, PyObject* var){ - static_assert(std::is_pod_v); + static_assert(is_pod::value); C99Struct& pod = CAST(C99Struct&, var); return *reinterpret_cast(pod.p); } template -std::enable_if_t && !std::is_pointer_v, PyObject*> py_var(VM* vm, const T& data){ +std::enable_if_t::value && !std::is_pointer_v, PyObject*> py_var(VM* vm, const T& data){ return VAR_T(C99Struct, std::monostate(), data); } /*****************************************************************/ diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index a58b987b..094c5c4b 100644 --- a/include/pocketpy/common.h +++ b/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 +struct is_pod { + static constexpr bool value = std::is_trivially_copyable_v && std::is_standard_layout_v; +}; + } // namespace pkpy diff --git a/include/pocketpy/namedict.h b/include/pocketpy/namedict.h index 07c54466..32958510 100644 --- a/include/pocketpy/namedict.h +++ b/include/pocketpy/namedict.h @@ -19,7 +19,7 @@ struct NameDictImpl { using Item = std::pair; static constexpr uint16_t __Capacity = 8; // ensure the initial capacity is ok for memory pool - static_assert(std::is_pod_v); + static_assert(is_pod::value); static_assert(sizeof(Item) * __Capacity <= 128); float _load_factor; diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index 094da466..54cf7484 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -214,7 +214,7 @@ __T py_cast(VM* vm, PyObject* obj) { }else if constexpr(is_py_class::value){ T::_check_type(vm, obj); return PK_OBJ_GET(T, obj); - }else if constexpr(std::is_pod_v){ + }else if constexpr(is_pod::value){ return to_c99_struct(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::value){ return PK_OBJ_GET(T, obj); - }else if constexpr(std::is_pod_v){ + }else if constexpr(is_pod::value){ return to_c99_struct(vm, obj); }else { return Discarded(); diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index c8f7b316..4d0a6c82 100644 --- a/include/pocketpy/str.h +++ b/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"); diff --git a/include/pocketpy/vector.h b/include/pocketpy/vector.h index 549f4f71..6715374d 100644 --- a/include/pocketpy/vector.h +++ b/include/pocketpy/vector.h @@ -8,7 +8,7 @@ namespace pkpy{ template struct pod_vector{ static_assert(64 % sizeof(T) == 0); - static_assert(std::is_pod_v); + static_assert(is_pod::value); static constexpr int N = 64 / sizeof(T); static_assert(N >= 4); int _size; diff --git a/python/colorsys.py b/python/colorsys.py new file mode 100644 index 00000000..3945261e --- /dev/null +++ b/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 \ No newline at end of file diff --git a/src/ceval.cpp b/src/ceval.cpp index 9c2a1633..93d8f120 100644 --- a/src/ceval.cpp +++ b/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!! diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index e4055904..3fd9d506 100644 --- a/src/pocketpy.cpp +++ b/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]; }