summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-10-22 17:37:18 +0000
committerDamien George <damien.p.george@gmail.com>2014-10-22 23:20:15 +0100
commitf5d69794a86f7647de3f3b3efd282ed288b1cba6 (patch)
treedd81cfcca993bad937830aa7e9cc37f8c74a753c
parente72be1b999a3337f74a8e5a8f61705666f834d2b (diff)
downloadmicropython-f5d69794a86f7647de3f3b3efd282ed288b1cba6.tar.gz
micropython-f5d69794a86f7647de3f3b3efd282ed288b1cba6.zip
extmod: Add uheapq module.
-rw-r--r--extmod/moduheapq.c138
-rw-r--r--py/builtin.h1
-rw-r--r--py/builtintables.c3
-rw-r--r--py/mpconfig.h4
-rw-r--r--py/py.mk1
-rw-r--r--py/qstrdefs.h7
-rw-r--r--stmhal/mpconfigport.h1
-rw-r--r--tests/extmod/uheapq1.py36
-rw-r--r--unix/mpconfigport.h1
9 files changed, 192 insertions, 0 deletions
diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c
new file mode 100644
index 0000000000..c2db3b6211
--- /dev/null
+++ b/extmod/moduheapq.c
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <unistd.h>
+
+#include "mpconfig.h"
+#include "misc.h"
+#include "nlr.h"
+#include "qstr.h"
+#include "obj.h"
+#include "objlist.h"
+#include "runtime0.h"
+#include "runtime.h"
+
+#if MICROPY_PY_UHEAPQ
+
+// the algorithm here is modelled on CPython's heapq.py
+
+STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
+ if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "heap must be a list"));
+ }
+ return heap_in;
+}
+
+STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
+ mp_obj_t item = heap->items[pos];
+ while (pos > start_pos) {
+ mp_uint_t parent_pos = (pos - 1) >> 1;
+ mp_obj_t parent = heap->items[parent_pos];
+ if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
+ heap->items[pos] = parent;
+ pos = parent_pos;
+ } else {
+ break;
+ }
+ }
+ heap->items[pos] = item;
+}
+
+STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
+ mp_uint_t start_pos = pos;
+ mp_uint_t end_pos = heap->len;
+ mp_obj_t item = heap->items[pos];
+ for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
+ // choose right child if it's <= left child
+ if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
+ child_pos += 1;
+ }
+ // bubble up the smaller child
+ heap->items[pos] = heap->items[child_pos];
+ pos = child_pos;
+ }
+ heap->items[pos] = item;
+ heap_siftdown(heap, start_pos, pos);
+}
+
+STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
+ mp_obj_list_t *heap = get_heap(heap_in);
+ mp_obj_list_append(heap, item);
+ heap_siftdown(heap, 0, heap->len - 1);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
+
+STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
+ mp_obj_list_t *heap = get_heap(heap_in);
+ if (heap->len == 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
+ }
+ mp_obj_t item = heap->items[0];
+ heap->len -= 1;
+ heap->items[0] = heap->items[heap->len];
+ heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
+ if (heap->len) {
+ heap_siftup(heap, 0);
+ }
+ return item;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
+
+STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
+ mp_obj_list_t *heap = get_heap(heap_in);
+ for (mp_uint_t i = heap->len / 2; i > 0;) {
+ heap_siftup(heap, --i);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
+
+STATIC const mp_map_elem_t mp_module_uheapq_globals_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uheapq) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_heappush), (mp_obj_t)&mod_uheapq_heappush_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_heappop), (mp_obj_t)&mod_uheapq_heappop_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_heapify), (mp_obj_t)&mod_uheapq_heapify_obj },
+};
+
+STATIC const mp_obj_dict_t mp_module_uheapq_globals = {
+ .base = {&mp_type_dict},
+ .map = {
+ .all_keys_are_qstrs = 1,
+ .table_is_fixed_array = 1,
+ .used = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
+ .alloc = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
+ .table = (mp_map_elem_t*)mp_module_uheapq_globals_table,
+ },
+};
+
+const mp_obj_module_t mp_module_uheapq = {
+ .base = { &mp_type_module },
+ .name = MP_QSTR_uheapq,
+ .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
+};
+
+#endif //MICROPY_PY_UHEAPQ
diff --git a/py/builtin.h b/py/builtin.h
index a69712bec7..58b821bf3c 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -91,3 +91,4 @@ extern const mp_obj_module_t mp_module_uctypes;
extern const mp_obj_module_t mp_module_uzlib;
extern const mp_obj_module_t mp_module_ujson;
extern const mp_obj_module_t mp_module_ure;
+extern const mp_obj_module_t mp_module_uheapq;
diff --git a/py/builtintables.c b/py/builtintables.c
index 0e5daf6d8d..238d78872b 100644
--- a/py/builtintables.c
+++ b/py/builtintables.c
@@ -211,6 +211,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
#if MICROPY_PY_URE
{ MP_OBJ_NEW_QSTR(MP_QSTR_ure), (mp_obj_t)&mp_module_ure },
#endif
+#if MICROPY_PY_UHEAPQ
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uheapq), (mp_obj_t)&mp_module_uheapq },
+#endif
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 4efe21d4b5..201621ea19 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -403,6 +403,10 @@ typedef double mp_float_t;
#define MICROPY_PY_URE (0)
#endif
+#ifndef MICROPY_PY_UHEAPQ
+#define MICROPY_PY_UHEAPQ (0)
+#endif
+
/*****************************************************************************/
/* Hooks for a port to add builtins */
diff --git a/py/py.mk b/py/py.mk
index f58a5d0558..a821b7c08b 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -114,6 +114,7 @@ PY_O_BASENAME = \
../extmod/modujson.o \
../extmod/modure.o \
../extmod/moduzlib.o \
+ ../extmod/moduheapq.o \
# prepend the build destination prefix to the py object files
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 0f520719f1..d1bb4dc246 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -485,3 +485,10 @@ Q(search)
Q(group)
Q(DEBUG)
#endif
+
+#if MICROPY_PY_UHEAPQ
+Q(uheapq)
+Q(heappush)
+Q(heappop)
+Q(heapify)
+#endif
diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h
index a632631321..a72ad9c4c0 100644
--- a/stmhal/mpconfigport.h
+++ b/stmhal/mpconfigport.h
@@ -60,6 +60,7 @@
#define MICROPY_PY_UZLIB (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_URE (1)
+#define MICROPY_PY_UHEAPQ (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
diff --git a/tests/extmod/uheapq1.py b/tests/extmod/uheapq1.py
new file mode 100644
index 0000000000..e71f817ef8
--- /dev/null
+++ b/tests/extmod/uheapq1.py
@@ -0,0 +1,36 @@
+try:
+ import uheapq as heapq
+except:
+ import heapq
+
+try:
+ heapq.heappop([])
+except IndexError:
+ print("IndexError")
+
+try:
+ heapq.heappush((), 1)
+except TypeError:
+ print("TypeError")
+
+def pop_and_print(h):
+ l = []
+ while h:
+ l.append(str(heapq.heappop(h)))
+ print(' '.join(l))
+
+h = []
+heapq.heappush(h, 3)
+heapq.heappush(h, 1)
+heapq.heappush(h, 2)
+print(h)
+pop_and_print(h)
+
+h = [4, 3, 8, 9, 10, 2, 7, 11, 5]
+heapq.heapify(h)
+print(h)
+heapq.heappush(h, 1)
+heapq.heappush(h, 6)
+heapq.heappush(h, 12)
+print(h)
+pop_and_print(h)
diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h
index f188d5feff..13c0c93cfd 100644
--- a/unix/mpconfigport.h
+++ b/unix/mpconfigport.h
@@ -58,6 +58,7 @@
#define MICROPY_PY_UZLIB (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_URE (1)
+#define MICROPY_PY_UHEAPQ (1)
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
// names in exception messages (may require more RAM).