mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-05 19:20:17 +00:00
Add some dict bindings
This commit is contained in:
parent
8ae999ecdf
commit
f88b1a1436
@ -35,7 +35,7 @@ endif()
|
|||||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
||||||
file(GLOB_RECURSE POCKETPY_SRC_CPP ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp)
|
file(GLOB_RECURSE POCKETPY_SRC_CPP ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp)
|
||||||
file(GLOB_RECURSE POCKETPY_SRC_C ${CMAKE_CURRENT_LIST_DIR}/src/*.c)
|
file(GLOB_RECURSE POCKETPY_SRC_C ${CMAKE_CURRENT_LIST_DIR}/src/*.c)
|
||||||
set(POCKETPY_SRC ${POCKETPY_SRC_CPP} ${POCKETPY_SRC_C})
|
set(POCKETPY_SRC ${POCKETPY_SRC_C})
|
||||||
|
|
||||||
option(PK_USE_CJSON "" OFF)
|
option(PK_USE_CJSON "" OFF)
|
||||||
if(PK_USE_CJSON)
|
if(PK_USE_CJSON)
|
||||||
@ -95,7 +95,7 @@ elseif(PK_BUILD_STATIC_LIB)
|
|||||||
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
||||||
else()
|
else()
|
||||||
set(PROJECT_EXE_NAME main)
|
set(PROJECT_EXE_NAME main)
|
||||||
add_executable(${PROJECT_EXE_NAME} src2/main.cpp)
|
add_executable(${PROJECT_EXE_NAME} src2/main.c)
|
||||||
if (BUILD_TESTING_SANITIZE)
|
if (BUILD_TESTING_SANITIZE)
|
||||||
# static linked main, for sanitizing purpose
|
# static linked main, for sanitizing purpose
|
||||||
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
||||||
|
|||||||
@ -44,7 +44,6 @@ pkpy_Dict pkpy_Dict__copy(const pkpy_Dict* self);
|
|||||||
/**
|
/**
|
||||||
* @brief Set a key-value pair into the `pkpy_Dict`
|
* @brief Set a key-value pair into the `pkpy_Dict`
|
||||||
* @param self `pkpy_Dict` instance
|
* @param self `pkpy_Dict` instance
|
||||||
* @param vm __eq__ and __hash__ context
|
|
||||||
* @param key key to set
|
* @param key key to set
|
||||||
* @param val value to set
|
* @param val value to set
|
||||||
* @return `true` if the key is newly added, `false` if the key already exists
|
* @return `true` if the key is newly added, `false` if the key already exists
|
||||||
@ -54,7 +53,6 @@ bool pkpy_Dict__set(pkpy_Dict* self, py_TValue key, py_TValue val);
|
|||||||
/**
|
/**
|
||||||
* @brief Check if a key exists in the `pkpy_Dict`
|
* @brief Check if a key exists in the `pkpy_Dict`
|
||||||
* @param self `pkpy_Dict` instance
|
* @param self `pkpy_Dict` instance
|
||||||
* @param vm __eq__ and __hash__ context
|
|
||||||
* @param key key to check
|
* @param key key to check
|
||||||
* @return `true` if the key exists, `false` otherwise
|
* @return `true` if the key exists, `false` otherwise
|
||||||
*/
|
*/
|
||||||
@ -63,7 +61,6 @@ bool pkpy_Dict__contains(const pkpy_Dict* self, py_TValue key);
|
|||||||
/**
|
/**
|
||||||
* @brief Remove a key from the `pkpy_Dict`
|
* @brief Remove a key from the `pkpy_Dict`
|
||||||
* @param self `pkpy_Dict` instance
|
* @param self `pkpy_Dict` instance
|
||||||
* @param vm __eq__ and __hash__ context
|
|
||||||
* @param key key to remove
|
* @param key key to remove
|
||||||
* @return `true` if the key was found and removed, `false` if the key doesn't exist
|
* @return `true` if the key was found and removed, `false` if the key doesn't exist
|
||||||
*/
|
*/
|
||||||
@ -72,7 +69,6 @@ bool pkpy_Dict__del(pkpy_Dict* self, py_TValue key);
|
|||||||
/**
|
/**
|
||||||
* @brief Try to get a value from the `pkpy_Dict`
|
* @brief Try to get a value from the `pkpy_Dict`
|
||||||
* @param self `pkpy_Dict` instance
|
* @param self `pkpy_Dict` instance
|
||||||
* @param vm __eq__ and __hash__ context
|
|
||||||
* @param key key to get
|
* @param key key to get
|
||||||
* @return the value associated with the key, `NULL` if the key doesn't exist
|
* @return the value associated with the key, `NULL` if the key doesn't exist
|
||||||
*/
|
*/
|
||||||
@ -81,7 +77,6 @@ const py_TValue* pkpy_Dict__try_get(const pkpy_Dict* self, py_TValue key);
|
|||||||
/**
|
/**
|
||||||
* @brief Update the `pkpy_Dict` with another one
|
* @brief Update the `pkpy_Dict` with another one
|
||||||
* @param self `pkpy_Dict` instance
|
* @param self `pkpy_Dict` instance
|
||||||
* @param vm __eq__ and __hash__ context
|
|
||||||
* @param other `pkpy_Dict` instance to update with
|
* @param other `pkpy_Dict` instance to update with
|
||||||
*/
|
*/
|
||||||
void pkpy_Dict__update(pkpy_Dict* self, const pkpy_Dict* other);
|
void pkpy_Dict__update(pkpy_Dict* self, const pkpy_Dict* other);
|
||||||
@ -92,6 +87,15 @@ void pkpy_Dict__update(pkpy_Dict* self, const pkpy_Dict* other);
|
|||||||
*/
|
*/
|
||||||
void pkpy_Dict__clear(pkpy_Dict* self);
|
void pkpy_Dict__clear(pkpy_Dict* self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to pop the latest inserted key-value pair from the `pkpy_Dict`
|
||||||
|
* @param self `pkpy_Dict` instance
|
||||||
|
* @param key key will be filled with the current key, can be `NULL` if not needed
|
||||||
|
* @param value value will be filled with the current value, can be `NULL` if not needed
|
||||||
|
* @return `true` if the operation was successful, `false` if the `pkpy_Dict` is empty
|
||||||
|
*/
|
||||||
|
bool pkpy_Dict__try_pop(pkpy_Dict* self, py_TValue *key, py_TValue *val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Iterate over the `pkpy_Dict`
|
* @brief Iterate over the `pkpy_Dict`
|
||||||
* @param self `pkpy_Dict` instance
|
* @param self `pkpy_Dict` instance
|
||||||
|
|||||||
@ -118,6 +118,7 @@ bool py_issubclass(py_Type derived, py_Type base);
|
|||||||
#define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4))
|
#define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4))
|
||||||
|
|
||||||
#define TypeError(x) false
|
#define TypeError(x) false
|
||||||
|
#define KeyError(...) false
|
||||||
#define py_arg(i) py_offset(argv, i)
|
#define py_arg(i) py_offset(argv, i)
|
||||||
#define py_checkargc(n) \
|
#define py_checkargc(n) \
|
||||||
if(argc != n) return TypeError()
|
if(argc != n) return TypeError()
|
||||||
|
|||||||
@ -4,13 +4,17 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "dict.h"
|
||||||
|
|
||||||
#define DICT_MAX_LOAD 0.75
|
#define DICT_MAX_LOAD 0.75
|
||||||
#define DICT_HASH_NEXT(h) ((h) * 5 + 1)
|
#define DICT_HASH_NEXT(h) ((h) * 5 + 1)
|
||||||
#define DICT_HASH_TRANS(h) ((int)((h) & 0xffffffff)) // used for tansform value from __hash__
|
#define DICT_HASH_TRANS(h) ((int)((h) & 0xffffffff)) // used for tansform value from __hash__
|
||||||
#define PK_DICT_COMPACT_MODE 1
|
#define PK_DICT_COMPACT_MODE 1
|
||||||
#define pkpy_Var__is_null(self) ((self)->type == 0)
|
#define pkpy_Var__is_null(self) ((self)->type == 0)
|
||||||
#define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0)
|
#define pkpy_Var__set_null(self) \
|
||||||
|
do { \
|
||||||
|
(self)->type = 0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
struct pkpy_DictEntry {
|
struct pkpy_DictEntry {
|
||||||
py_TValue key;
|
py_TValue key;
|
||||||
@ -33,7 +37,9 @@ inline extern int pkpy_Dict__idx_null(const pkpy_Dict* self) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline extern int pkpy_Dict__ht_byte_size(const pkpy_Dict* self) { return self->_htcap * pkpy_Dict__idx_size(self); }
|
inline extern int pkpy_Dict__ht_byte_size(const pkpy_Dict* self) {
|
||||||
|
return self->_htcap * pkpy_Dict__idx_size(self);
|
||||||
|
}
|
||||||
|
|
||||||
void pkpy_Dict__ctor(pkpy_Dict* self) {
|
void pkpy_Dict__ctor(pkpy_Dict* self) {
|
||||||
self->count = 0;
|
self->count = 0;
|
||||||
@ -174,7 +180,8 @@ bool pkpy_Dict__contains(const pkpy_Dict* self, py_TValue key) {
|
|||||||
|
|
||||||
static bool pkpy_Dict__refactor(pkpy_Dict* self) {
|
static bool pkpy_Dict__refactor(pkpy_Dict* self) {
|
||||||
int deleted_slots = self->_entries.count - self->count;
|
int deleted_slots = self->_entries.count - self->count;
|
||||||
if(deleted_slots <= 8 || deleted_slots < self->_entries.count * (1 - DICT_MAX_LOAD)) return false;
|
if(deleted_slots <= 8 || deleted_slots < self->_entries.count * (1 - DICT_MAX_LOAD))
|
||||||
|
return false;
|
||||||
|
|
||||||
// shrink
|
// shrink
|
||||||
// free(self->_hashtable);
|
// free(self->_hashtable);
|
||||||
@ -256,6 +263,24 @@ static int pkpy_Dict__next_entry_idx(const pkpy_Dict* self, int idx) {
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pkpy_Dict__try_pop(pkpy_Dict* self, py_TValue* key, py_TValue* val) {
|
||||||
|
int idx = self->count - 1;
|
||||||
|
struct pkpy_DictEntry* entry;
|
||||||
|
do {
|
||||||
|
if (idx < 0)
|
||||||
|
return false;
|
||||||
|
entry = &c11__getitem(struct pkpy_DictEntry, &self->_entries, idx);
|
||||||
|
idx--;
|
||||||
|
} while (pkpy_Var__is_null(&entry->key));
|
||||||
|
|
||||||
|
if(key) *key = entry->key;
|
||||||
|
if(val) *val = entry->val;
|
||||||
|
pkpy_Var__set_null(&entry->key);
|
||||||
|
self->count -= 1;
|
||||||
|
pkpy_Dict__refactor(self);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict* self) {
|
pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict* self) {
|
||||||
return (pkpy_DictIter){
|
return (pkpy_DictIter){
|
||||||
._dict = self,
|
._dict = self,
|
||||||
@ -266,7 +291,8 @@ pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict *self) {
|
|||||||
bool pkpy_DictIter__next(pkpy_DictIter* self, py_TValue* key, py_TValue* val) {
|
bool pkpy_DictIter__next(pkpy_DictIter* self, py_TValue* key, py_TValue* val) {
|
||||||
if(self->_index >= self->_dict->_entries.count) return false;
|
if(self->_index >= self->_dict->_entries.count) return false;
|
||||||
|
|
||||||
struct pkpy_DictEntry* entry = &c11__getitem(struct pkpy_DictEntry, &self->_dict->_entries, self->_index);
|
struct pkpy_DictEntry* entry =
|
||||||
|
&c11__getitem(struct pkpy_DictEntry, &self->_dict->_entries, self->_index);
|
||||||
if(pkpy_Var__is_null(&entry->key)) return false;
|
if(pkpy_Var__is_null(&entry->key)) return false;
|
||||||
if(key) *key = entry->key;
|
if(key) *key = entry->key;
|
||||||
if(val) *val = entry->val;
|
if(val) *val = entry->val;
|
||||||
|
|||||||
@ -4,10 +4,224 @@
|
|||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
|
|
||||||
void py_newdict(py_Ref out){
|
#include "pocketpy/common/vector.h"
|
||||||
|
#include "pocketpy/objects/dict.h"
|
||||||
|
|
||||||
|
py_Type pk_dict__register() {
|
||||||
|
pk_VM* vm = pk_current_vm;
|
||||||
|
py_Type type = pk_VM__new_type(vm, "dict", tp_object, NULL, false);
|
||||||
|
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type);
|
||||||
|
ti->dtor = (void (*)(void*))pkpy_Dict__dtor;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void py_newdict(py_Ref out) {
|
||||||
|
pk_VM* vm = pk_current_vm;
|
||||||
|
PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_dict, 0, sizeof(pkpy_Dict));
|
||||||
|
pkpy_Dict* userdata = PyObject__userdata(obj);
|
||||||
|
pkpy_Dict__ctor(userdata);
|
||||||
|
out->type = tp_dict;
|
||||||
|
out->is_ptr = true;
|
||||||
|
out->_obj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dict medthods
|
||||||
|
// https://docs.python.org/3/library/stdtypes.html#dict
|
||||||
|
|
||||||
|
// TODO: list(d)
|
||||||
|
|
||||||
|
bool _py_dict__len__(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(1);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_newint(py_retval(), dict->count);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _py_dict__getitem__(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(2);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
py_TValue* val = pkpy_Dict__try_get(dict, *key);
|
||||||
|
if (val) {
|
||||||
|
*py_retval() = *val;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return KeyError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _py_dict__setitem__(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(3);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1), val = py_arg(2);
|
||||||
|
pkpy_Dict__set(dict, *key, *val);
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _py_dict__delitem__(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(2);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
pkpy_Dict__del(dict, *key);
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _py_dict__contains__(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(2);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
py_newbool(py_retval(), pkpy_Dict__contains(dict, *key));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: iter(d)
|
||||||
|
|
||||||
|
bool _py_dict__clear(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(1);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
pkpy_Dict__clear(dict);
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _py_dict__copy(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(1);
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref ret = py_retval();
|
||||||
|
py_newdict(ret);
|
||||||
|
pkpy_Dict__update(py_touserdata(ret), dict);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: classmethod fromkeys
|
||||||
|
|
||||||
|
bool _py_dict__get(int argc, py_Ref argv) {
|
||||||
|
if (argc < 2 || argc > 3)
|
||||||
|
return TypeError();
|
||||||
|
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
py_TValue* val = pkpy_Dict__try_get(dict, *key);
|
||||||
|
if (val) {
|
||||||
|
*py_retval() = *val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 3)
|
||||||
|
*py_retval() = *py_arg(2);
|
||||||
|
else
|
||||||
|
py_newnone(py_retval());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: method items
|
||||||
|
|
||||||
|
// TODO: method keys
|
||||||
|
|
||||||
|
bool _py_dict__pop(int argc, py_Ref argv) {
|
||||||
|
if (argc < 2 || argc > 3)
|
||||||
|
return TypeError();
|
||||||
|
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
py_TValue* val = pkpy_Dict__try_get(dict, *key);
|
||||||
|
if (val) {
|
||||||
|
pkpy_Dict__del(dict, *key);
|
||||||
|
*py_retval() = *val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 3) {
|
||||||
|
*py_retval() = *py_arg(2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyError();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _py_dict__popitem(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(1);
|
||||||
|
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_StackRef key = py_pushtmp(), val = py_pushtmp();
|
||||||
|
|
||||||
|
py_Ref ret = py_retval();
|
||||||
|
if (pkpy_Dict__try_pop(dict, key, val)) {
|
||||||
|
py_newtuple(ret, 2);
|
||||||
|
py_setslot(ret, 0, key);
|
||||||
|
py_setslot(ret, 1, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.python.org/3/library/stdtypes.html#dict-views
|
||||||
|
// TODO: dict_keys, dict_values, dict_items
|
||||||
|
// TODO: dict_iterator, dict_keyiterator, dict_valueiterator
|
||||||
|
|
||||||
|
// TODO: reversed(d)
|
||||||
|
|
||||||
|
bool _py_dict__setdefault(int argc, py_Ref argv) {
|
||||||
|
if (argc < 2 || argc > 3)
|
||||||
|
return TypeError();
|
||||||
|
|
||||||
|
pkpy_Dict* dict = py_touserdata(py_arg(0));
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
py_TValue* val = pkpy_Dict__try_get(dict, *key);
|
||||||
|
if (val) {
|
||||||
|
*py_retval() = *val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_Ref dft;
|
||||||
|
if (argc == 3) {
|
||||||
|
dft = py_arg(2);
|
||||||
|
} else {
|
||||||
|
dft = py_pushtmp();
|
||||||
|
py_newnone(dft);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkpy_Dict__set(dict, *key, *dft);
|
||||||
|
*py_retval() = *dft;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _py_dict__update(int argc, py_Ref argv) {
|
||||||
|
// TODO: accept kwargs
|
||||||
|
py_checkargc(2);
|
||||||
|
|
||||||
|
pkpy_Dict* me = py_touserdata(py_arg(0));
|
||||||
|
pkpy_Dict* other = py_touserdata(py_arg(1));
|
||||||
|
pkpy_Dict__update(me, other);
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: method values
|
||||||
|
|
||||||
|
bool _py_dict__or__(int argc, py_Ref argv) {
|
||||||
|
py_checkargc(2);
|
||||||
|
|
||||||
|
pkpy_Dict* me = py_touserdata(py_arg(0));
|
||||||
|
pkpy_Dict* other = py_touserdata(py_arg(1));
|
||||||
|
|
||||||
|
py_Ref ret = py_retval();
|
||||||
|
py_newdict(ret);
|
||||||
|
pkpy_Dict__update(py_touserdata(ret), me);
|
||||||
|
pkpy_Dict__update(py_touserdata(ret), other);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: method operator |=
|
||||||
|
|
||||||
|
py_Type pk_set__register() {
|
||||||
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_newset(py_Ref out){
|
void py_newset(py_Ref out){
|
||||||
|
// TODO: implement
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user