A faster version of SingleKey

This commit is contained in:
Kovid Goyal 2022-08-12 09:17:42 +05:30
parent 9bb2c1a27b
commit f228f8368a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 178 additions and 5 deletions

View File

@ -22,11 +22,6 @@
typedef enum HASH_ALGORITHM { SHA1_HASH, SHA224_HASH, SHA256_HASH, SHA384_HASH, SHA512_HASH } HASH_ALGORITHM;
static PyObject* Crypto_Exception = NULL;
#define ADD_TYPE(which) \
if (PyType_Ready(&which##_Type) < 0) return false; \
if (PyModule_AddObject(module, #which, (PyObject *)&which##_Type) != 0) return false; \
Py_INCREF(&which##_Type);
static PyObject*
set_error_from_openssl(const char *prefix) {
BIO *bio = BIO_new(BIO_s_mem());

View File

@ -133,6 +133,14 @@ typedef struct ImageAnchorPosition {
#endif
#define START_ALLOW_CASE_RANGE IGNORE_PEDANTIC_WARNINGS
#define END_ALLOW_CASE_RANGE END_IGNORE_PEDANTIC_WARNINGS
#define BIT_MASK(__TYPE__, __ONE_COUNT__) \
((__TYPE__) (-((__ONE_COUNT__) != 0))) \
& (((__TYPE__) -1) >> ((sizeof(__TYPE__) * CHAR_BIT) - (__ONE_COUNT__)))
#define ADD_TYPE(which) \
if (PyType_Ready(&which##_Type) < 0) return false; \
if (PyModule_AddObject(module, #which, (PyObject *)&which##_Type) != 0) return false; \
Py_INCREF(&which##_Type);
typedef enum UTF8State { UTF8_ACCEPT = 0, UTF8_REJECT = 1} UTF8State;

View File

@ -1466,3 +1466,17 @@ class AES256GCMDecrypt:
def add_data_to_be_authenticated_but_not_decrypted(self, data: bytes) -> None: ...
def add_data_to_be_decrypted(self, data: bytes, finished: bool = False) -> bytes: ...
class SingleKey:
def __init__(self, mods: int = 0, is_native: bool = False, key: int = -1): ...
def __hash__(self) -> int: ...
def __len__(self) -> int: ...
def __getitem__(self, x: int) -> int: ...
@property
def mods(self) -> int: ...
@property
def is_native(self) -> bool: ...
@property
def key(self) -> int: ...

View File

@ -283,11 +283,155 @@ static PyMethodDef module_methods[] = {
{0}
};
// SingleKey {{{
#define KEY_BITS 21
#define MOD_BITS 10
typedef union Key {
struct {
uint32_t key : KEY_BITS;
uint32_t mods : MOD_BITS;
uint32_t is_native: 1;
};
uint32_t val;
} Key;
static PyTypeObject SingleKey_Type;
typedef struct {
PyObject_HEAD
Key key;
} SingleKey;
static PyObject *
SingleKey_new(PyTypeObject *type, PyObject *args, PyObject *kw) {
static char *kwds[] = {"mods", "is_native", "key", NULL};
long key = -1; unsigned short mods = 0; int is_native = 0;
if (!PyArg_ParseTupleAndKeywords(args, kw, "|Hpl", kwds, &mods, &is_native, &key)) return NULL;
SingleKey *self = (SingleKey *)type->tp_alloc(type, 0);
if (self) {
if (key > 0 && key <= 0x10FFFF) {
uint32_t k = (uint32_t)key;
self->key.key = k & BIT_MASK(uint32_t, KEY_BITS);
}
self->key.mods = mods;
if (is_native) self->key.is_native = 1u;
}
return (PyObject*)self;
}
static void
SingleKey_dealloc(SingleKey* self) {
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject*
SingleKey_repr(PyObject *s) {
SingleKey *self = (SingleKey*)s;
char buf[128];
int pos = 0;
pos += PyOS_snprintf(buf + pos, sizeof(buf) - pos, "SingleKey(");
unsigned int mods = self->key.mods;
if (mods) pos += PyOS_snprintf(buf + pos, sizeof(buf) - pos, "mods=%u, ", mods);
if (self->key.is_native) pos += PyOS_snprintf(buf + pos, sizeof(buf) - pos, "is_native=True, ");
unsigned long key = self->key.key;
if (key) pos += PyOS_snprintf(buf + pos, sizeof(buf) - pos, "key=%lu, ", key);
if (buf[pos-1] == ' ') pos -= 2;
pos += PyOS_snprintf(buf + pos, sizeof(buf) - pos, ")");
return PyUnicode_FromString(buf);
}
static PyObject*
SingleKey_get_key(SingleKey *self, void UNUSED *closure) {
const unsigned long val = self->key.key;
if (val) return PyLong_FromUnsignedLong(val);
return PyLong_FromLong(-1);
}
static PyObject*
SingleKey_get_mods(SingleKey *self, void UNUSED *closure) {
const unsigned long mods = self->key.mods;
return PyLong_FromUnsignedLong(mods);
}
static PyObject*
SingleKey_get_is_native(SingleKey *self, void UNUSED *closure) {
if (self->key.is_native) Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
static PyGetSetDef SingleKey_getsetters[] = {
{"key", (getter)SingleKey_get_key, NULL, "The key as an integer", NULL},
{"mods", (getter)SingleKey_get_mods, NULL, "The modifiers as an integer", NULL},
{"is_native", (getter)SingleKey_get_is_native, NULL, "A bool", NULL},
{NULL} /* Sentinel */
};
static Py_hash_t
SingleKey_hash(PyObject *self) {
Py_hash_t ans = ((SingleKey*)self)->key.val;
if (ans == -1) ans = -2;
return ans;
}
static PyObject*
SingleKey_richcompare(PyObject *self, PyObject *other, int op) {
if (!PyObject_TypeCheck(other, &SingleKey_Type)) { PyErr_SetString(PyExc_TypeError, "Cannot compare SingleKey to other objects"); return NULL; }
SingleKey *a = (SingleKey*)self, *b = (SingleKey*)other;
Py_RETURN_RICHCOMPARE(a->key.val, b->key.val, op);
}
static Py_ssize_t
SingleKey___len__(PyObject *self UNUSED) {
return 3;
}
static PyObject *
SingleKey_item(PyObject *o, Py_ssize_t i) {
SingleKey *self = (SingleKey*)o;
switch(i) {
case 0:
return SingleKey_get_mods(self, NULL);
case 1:
return SingleKey_get_is_native(self, NULL);
case 2:
return SingleKey_get_key(self, NULL);
}
PyErr_SetString(PyExc_IndexError, "tuple index out of range");
return NULL;
}
static PySequenceMethods SingleKey_sequence_methods = {
.sq_length = SingleKey___len__,
.sq_item = SingleKey_item,
};
static PyTypeObject SingleKey_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "fast_data_types.SingleKey",
.tp_basicsize = sizeof(SingleKey),
.tp_dealloc = (destructor)SingleKey_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Compact and fast representation of a single key as defined in the config",
.tp_new = SingleKey_new,
.tp_hash = SingleKey_hash,
.tp_richcompare = SingleKey_richcompare,
.tp_as_sequence = &SingleKey_sequence_methods,
.tp_repr = SingleKey_repr,
/* .tp_methods = methods, */
.tp_getset = SingleKey_getsetters,
}; // }}}
bool
init_keys(PyObject *module) {
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
if (PyType_Ready(&PyKeyEvent_Type) < 0) return false;
if (PyModule_AddObject(module, "KeyEvent", (PyObject *)&PyKeyEvent_Type) != 0) return 0;
Py_INCREF(&PyKeyEvent_Type);
ADD_TYPE(SingleKey);
return true;
}

View File

@ -532,3 +532,15 @@ class TestDataTypes(BaseTest):
q('a\x1bbc', 'ac')
q('a\x1b[bc', 'ac')
q('a\x1b[12;34:43mbc', 'abc')
def test_SingleKey(self):
from kitty.fast_data_types import SingleKey, GLFW_MOD_NUM_LOCK, GLFW_MOD_SHIFT
for m in (GLFW_MOD_NUM_LOCK, GLFW_MOD_SHIFT):
s = SingleKey(mods=m)
self.ae(s.mods, m)
self.ae(tuple(SingleKey()), (0, False, -1))
self.ae(tuple(SingleKey(key=0x10ffff, mods=GLFW_MOD_SHIFT, is_native=True)), (GLFW_MOD_SHIFT, True, 0x10ffff))
self.ae(repr(SingleKey()), 'SingleKey()')
self.ae(repr(SingleKey(key=23, mods=2, is_native=True)), 'SingleKey(mods=2, is_native=True, key=23)')
self.ae(repr(SingleKey(key=23, mods=2)), 'SingleKey(mods=2, key=23)')
self.ae(repr(SingleKey(key=23)), 'SingleKey(key=23)')