some important changes

1. add `colorsys`
2. handle `__all__` in modules
3. `is_pod` for c++17/20
This commit is contained in:
BLUELOVETH 2023-08-02 13:04:39 +08:00
parent 679b8ec2e6
commit f0ca29a30a
10 changed files with 209 additions and 14 deletions

8
docs/modules/colorsys.md Normal file
View File

@ -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

View File

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

View File

@ -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_NULL = (PyObject*)0b000011; // tagged null
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011; inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011; 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 } // namespace pkpy

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ namespace pkpy{
template<typename T> template<typename T>
struct pod_vector{ struct pod_vector{
static_assert(64 % sizeof(T) == 0); 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 constexpr int N = 64 / sizeof(T);
static_assert(N >= 4); static_assert(N >= 4);
int _size; int _size;

166
python/colorsys.py Normal file
View File

@ -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

View File

@ -598,15 +598,28 @@ __NEXT_STEP:;
_name = StrName(byte.arg); _name = StrName(byte.arg);
PUSH(py_import(_name, true)); PUSH(py_import(_name, true));
DISPATCH(); DISPATCH();
TARGET(IMPORT_STAR) TARGET(IMPORT_STAR) {
_0 = POPX(); _0 = POPX();
_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()){ for(auto& [name, value]: _0->attr().items()){
std::string_view s = name.sv(); std::string_view s = name.sv();
if(s.empty() || s[0] == '_') continue; if(s.empty() || s[0] == '_') continue;
frame->f_globals().set(name, value); frame->f_globals().set(name, value);
} }
}
frame->f_globals()._try_perfect_rehash(); frame->f_globals()._try_perfect_rehash();
DISPATCH(); } DISPATCH();
/*****************************************/ /*****************************************/
TARGET(UNPACK_SEQUENCE){ TARGET(UNPACK_SEQUENCE){
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!!

View File

@ -1489,7 +1489,7 @@ void VM::post_init(){
add_module_base64(this); add_module_base64(this);
add_module_timeit(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]; _lazy_modules[name] = kPythonLibs[name];
} }