* @brief Shuffles the parts of a `Strs` object. * * This accepts a `Strs` object and potentially produces a new `Strs` object of a different layout: * - `STRS_U32_TAPE_VIEW` becomes `STRS_FRAGMENTED`, and keeps a link to the old as a parent. * - `STRS_U64_TAPE_VIEW` becomes `STRS_FRAGMENTED`, and keeps a link to the old as a parent. * - `STRS_U32_TAPE` becomes `STRS_FRAGMENTED`, and keep
| 6088 | * - `STRS_FRAGMENTED` returns a copy of itself, with the parts shuffled. |
| 6089 | */ |
| 6090 | static PyObject *Strs_shuffled(Strs *self, PyObject *const *args, Py_ssize_t positional_args_count, |
| 6091 | PyObject *args_names_tuple) { |
| 6092 | |
| 6093 | // Check for positional arguments |
| 6094 | PyObject *seed_obj = positional_args_count == 1 ? args[0] : NULL; |
| 6095 | if (positional_args_count > 1) { |
| 6096 | PyErr_SetString(PyExc_TypeError, "shuffle() takes at most 1 positional argument"); |
| 6097 | return NULL; |
| 6098 | } |
| 6099 | |
| 6100 | // Check for keyword arguments |
| 6101 | if (args_names_tuple) { |
| 6102 | Py_ssize_t args_names_count = PyTuple_GET_SIZE(args_names_tuple); |
| 6103 | for (Py_ssize_t i = 0; i < args_names_count; ++i) { |
| 6104 | PyObject *key = PyTuple_GET_ITEM(args_names_tuple, i); |
| 6105 | PyObject *value = args[positional_args_count + i]; |
| 6106 | if (PyUnicode_CompareWithASCIIString(key, "seed") == 0 && !seed_obj) { seed_obj = value; } |
| 6107 | else if (PyErr_Format(PyExc_TypeError, "Got an unexpected keyword argument '%U'", key)) { return NULL; } |
| 6108 | } |
| 6109 | } |
| 6110 | |
| 6111 | // Fisher-Yates Shuffle Algorithm |
| 6112 | unsigned int seed = (unsigned int)time(NULL); |
| 6113 | if (seed_obj) { |
| 6114 | if (!PyLong_Check(seed_obj)) { |
| 6115 | PyErr_SetString(PyExc_TypeError, "The seed must be an integer"); |
| 6116 | return NULL; |
| 6117 | } |
| 6118 | seed = PyLong_AsUnsignedLong(seed_obj); |
| 6119 | } |
| 6120 | |
| 6121 | // Determine the amount of memory needed |
| 6122 | sz_size_t substrings_count = 0; |
| 6123 | get_string_at_offset_t substring_getter = NULL; |
| 6124 | PyObject *parent_to_increment = NULL; |
| 6125 | sz_memory_allocator_t allocator; |
| 6126 | |
| 6127 | switch (self->layout) { |
| 6128 | case STRS_U32_TAPE: |
| 6129 | substring_getter = str_at_offset_u32_tape; |
| 6130 | substrings_count = self->data.u32_tape.count; |
| 6131 | parent_to_increment = (PyObject *)self; |
| 6132 | allocator = self->data.u32_tape.allocator; |
| 6133 | break; |
| 6134 | case STRS_U32_TAPE_VIEW: |
| 6135 | substring_getter = str_at_offset_u32_tape_view; |
| 6136 | substrings_count = self->data.u32_tape_view.count; |
| 6137 | parent_to_increment = self->data.u32_tape_view.parent; |
| 6138 | sz_memory_allocator_init_default(&allocator); |
| 6139 | break; |
| 6140 | case STRS_U64_TAPE: |
| 6141 | substring_getter = str_at_offset_u64_tape; |
| 6142 | substrings_count = self->data.u64_tape.count; |
| 6143 | parent_to_increment = (PyObject *)self; |
| 6144 | allocator = self->data.u64_tape.allocator; |
| 6145 | break; |
| 6146 | case STRS_U64_TAPE_VIEW: |
| 6147 | substring_getter = str_at_offset_u64_tape_view; |
nothing calls this directly
no test coverage detected
searching dependent graphs…