/* By: agilliar <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/12/11 12:45:16 by agilliar #+# #+# */
-/* Updated: 2025/12/12 00:07:33 by agilliar ### ########.fr */
+/* Updated: 2025/12/14 03:07:01 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
size_t blocks;
} t_splitsort;
-// MODE_NORMAL: sort current elements in ascending order
-// top < bottom
-// top ascending
-// bottom descending
-// MODE_REV: sort current elements in descending order
-// top > bottom
-// top descending
-// bottom ascending
-// MODE_WRAP: sort current elements in descending order, without unwind
-// top < bottom
-// top descending
-// bottom ascending
-typedef enum e_mode
-{
- MODE_NORMAL,
- MODE_REV,
- MODE_WRAP,
-} t_mode;
-
typedef struct s_iter
{
- t_list top;
- t_list bottom;
- size_t top_blocks;
- size_t bottom_blocks;
- bool top_rev;
- bool bottom_rev;
+ t_list range;
+ size_t blocks;
+ bool rev;
} t_iter;
-static t_iter splitsort_iter_new(t_splitsort sort, t_mode mode, t_list range)
+static t_iter iter_new(t_list range, size_t blocks, bool rev)
{
t_iter res;
- size_t top_len;
- size_t bottom_len;
-
- if (sort.blocks == 0)
- cheatexit(1);
- res.top_blocks = sort.blocks / 2;
- res.bottom_blocks = sort.blocks - res.top_blocks;
- top_len = range.len * res.top_blocks / sort.blocks;
- bottom_len = range.len - top_len;
- if (mode == MODE_REV)
- res.bottom = list_split(&range, bottom_len);
- else
- res.top = list_split(&range, top_len);
- if (mode == MODE_REV)
- res.top = range;
- else
- res.bottom = range;
- res.top_rev = mode != MODE_NORMAL;
- res.bottom_rev = mode == MODE_NORMAL;
+
+ res.range = range;
+ res.blocks = blocks;
+ res.rev = rev;
return (res);
}
-static t_list splitsort_split_start(t_list *range, size_t blocks)
+static t_list iter_next(t_iter *self)
{
+ t_list res;
size_t count;
- count = 0;
- if (blocks)
- count = range->len / blocks + ((range->len % blocks) != 0);
- return (list_split(range, count));
+ if (!self->blocks)
+ return (list_split(&self->range, 0));
+ count = self->range.len / self->blocks;
+ if (self->rev)
+ {
+ res = self->range;
+ self->range = list_split(&res, res.len - count);
+ }
+ else
+ {
+ if (self->range.len % self->blocks)
+ count++;
+ res = list_split(&self->range, count);
+ }
+ self->blocks--;
+ return (res);
}
-static t_list splitsort_split_end(t_list *range, size_t blocks)
+static bool iter_nexti(t_iter *self, t_list *dst)
{
- size_t count;
- t_list res;
-
- count = 0;
- if (blocks)
- count = range->len / blocks + ((range->len % blocks) != 0);
- res = *range;
- *range = list_split(&res, res.len - count);
- return (res);
+ *dst = iter_next(self);
+ return (dst->len != 0);
}
-static void splitsort_iter_next(t_iter *self, t_list *top, t_list *bottom)
+// Takes the self iterator, skip n elements, and return an iterator which only
+// yields said elements
+static t_iter iter_splitoff(t_iter *self, size_t n)
{
- if (self->top_rev)
- *top = splitsort_split_end(&self->top, self->top_blocks);
- else
- *top = splitsort_split_start(&self->top, self->top_blocks);
- if (self->bottom_rev)
- *bottom = splitsort_split_end(&self->bottom, self->bottom_blocks);
- else
- *bottom = splitsort_split_start(&self->bottom, self->bottom_blocks);
- if (self->top_blocks)
- self->top_blocks--;
- if (self->bottom_blocks)
- self->bottom_blocks--;
+ t_iter res;
+
+ res = *self;
+ while (n--)
+ iter_next(self);
+ res.range.len -= self->range.len;
+ res.blocks -= self->blocks;
+ if (res.rev)
+ res.range.ptr += self->range.len;
+ return (res);
}
typedef struct s_part
{
- t_mode mode;
t_list top;
t_list bottom;
bool rev;
+ bool mirror;
} t_part;
static void splitsort_part_once(t_part self, t_splitsort sort, size_t count)
{
const t_stack *src;
- bool mirror;
t_psval val;
- mirror = self.mode == MODE_NORMAL;
- src = stacks_geta(sort.stacks, mirror);
+ src = stacks_geta(sort.stacks, self.mirror);
while (count--)
{
if (self.rev)
- closure_callm(sort.cb, OP_RRA, mirror);
+ closure_callm(sort.cb, OP_RRA, self.mirror);
val = clist_get_at(src->list, 0);
if (list_get_sorted(self.top, val) != -1)
{
- closure_callm(sort.cb, OP_PB, mirror);
- closure_callm(sort.cb, OP_RB, mirror);
+ closure_callm(sort.cb, OP_PB, self.mirror);
+ closure_callm(sort.cb, OP_RB, self.mirror);
}
else if (list_get_sorted(self.bottom, val) != -1)
- closure_callm(sort.cb, OP_PB, mirror);
+ closure_callm(sort.cb, OP_PB, self.mirror);
else if (!self.rev)
- closure_callm(sort.cb, OP_RA, mirror);
+ closure_callm(sort.cb, OP_RA, self.mirror);
}
}
-static void splitsort_part(t_splitsort *sort, t_mode mode, t_list range)
+// Parts range elements from stack a (which is in ascending order) onto stack b
+// in descending order
+static void splitsort_part_a(t_splitsort sort, t_list range)
{
+ t_iter topi;
+ t_iter bottomi;
t_part part;
- t_iter iter;
size_t top_count;
size_t bottom_count;
- part.mode = mode;
+ bottomi = iter_new(range, sort.blocks, true);
+ topi = iter_splitoff(&bottomi, sort.blocks / 2);
+ bottomi.rev = false;
+ top_count = 0;
+ bottom_count = 0;
part.rev = false;
- iter = splitsort_iter_new(*sort, mode, range);
+ part.mirror = false;
+ while (iter_nexti(&topi, &part.top) | iter_nexti(&bottomi, &part.bottom))
+ {
+ splitsort_part_once(part, sort, range.len - top_count - bottom_count);
+ part.rev = !part.rev;
+ top_count += part.top.len;
+ bottom_count += part.bottom.len;
+ }
+ while (top_count--)
+ closure_call(sort.cb, OP_RRB);
+}
+
+// Parts range elements from stack a (which is in ascending order) onto stack b
+// in descending order, assuming that stack b is initially empty
+static void splitsort_part_a_wrap(t_splitsort sort, t_list range)
+{
+ t_iter topi;
+ t_iter bottomi;
+ t_part part;
+ size_t top_count;
+ size_t bottom_count;
+
+ bottomi = iter_new(range, sort.blocks, false);
+ topi = iter_splitoff(&bottomi, sort.blocks / 2);
+ topi.rev = true;
top_count = 0;
bottom_count = 0;
- while (splitsort_iter_next(&iter, &part.top, &part.bottom),
- part.top.len || part.bottom.len)
+ part.rev = false;
+ part.mirror = false;
+ while (iter_nexti(&topi, &part.top) | iter_nexti(&bottomi, &part.bottom))
{
- splitsort_part_once(part, *sort, range.len - top_count - bottom_count);
- part.rev = !part.rev && mode != MODE_WRAP;
+ splitsort_part_once(part, sort, range.len - top_count - bottom_count);
+ part.rev = !part.rev;
top_count += part.top.len;
bottom_count += part.bottom.len;
}
- while (mode != MODE_WRAP && top_count--)
- closure_callm(sort->cb, OP_RRB, mode == MODE_NORMAL);
}
-static void splitsort_fortop(t_splitsort sort, t_mode mode,
- t_list range, t_closure func)
+
+// Parts range elements from stack b (which is in descending order) onto stack
+// a in ascending order
+static void splitsort_part_b(t_splitsort sort, t_list range)
{
- t_iter iter;
- t_list top;
- t_list bottom;
+ t_iter topi;
+ t_iter bottomi;
+ t_part part;
+ size_t top_count;
+ size_t bottom_count;
- iter = splitsort_iter_new(sort, mode, range);
- while (splitsort_iter_next(&iter, &top, &bottom), top.len)
- (func.func)(func.data, top);
+ bottomi = iter_new(range, sort.blocks, false);
+ topi = iter_splitoff(&bottomi, sort.blocks / 2);
+ bottomi.rev = true;
+ top_count = 0;
+ bottom_count = 0;
+ part.rev = false;
+ part.mirror = true;
+ while (iter_nexti(&topi, &part.top) | iter_nexti(&bottomi, &part.bottom))
+ {
+ splitsort_part_once(part, sort, range.len - top_count - bottom_count);
+ part.rev = !part.rev;
+ top_count += part.top.len;
+ bottom_count += part.bottom.len;
+ }
+ while (top_count--)
+ closure_call(sort.cb, OP_RRA);
}
-static void splitsort_forbottom_rev(t_splitsort sort, t_mode mode,
- t_list range, t_closure func)
+typedef void (t_layer_func) (t_splitsort, t_list);
+
+void splitsort_leaf_a(t_splitsort sort, t_list range)
{
- t_iter iter;
- t_list top;
- t_list bottom;
+ leaf_sort_local(sort.stacks, sort.cb, false, range.len);
+}
- iter = splitsort_iter_new(sort, mode, range);
- iter.bottom_rev ^= true;
- while (splitsort_iter_next(&iter, &top, &bottom), bottom.len)
- (func.func)(func.data, bottom);
+static void splitsort_leaf_b(t_splitsort sort, t_list range)
+{
+ leaf_sort_other(sort.stacks, sort.cb, true, range.len);
+}
+
+static t_layer_func *layer_from_info(size_t depth, size_t blocks, size_t len)
+{
+ size_t i;
+ size_t state;
+
+ i = 0;
+ state = 4;
+ while (i++ < depth)
+ state *= blocks;
+ if (len <= state)
+ {
+ if (depth % 2 == 0)
+ return (&splitsort_leaf_a);
+ return (&splitsort_leaf_b);
+ }
+ if (depth == 0)
+ return (&splitsort_part_a_wrap);
+ if (depth % 2 == 0)
+ return (&splitsort_part_a);
+ return (&splitsort_part_b);
}
typedef struct s_visit
{
- t_splitsort sort;
- t_closure callback;
- size_t depth;
- t_mode mode;
+ t_list range;
+ size_t depth;
+ t_layer_func *cb;
+ bool rev;
} t_visit;
-static void splitsort_visit_inner(t_visit *self, t_list range)
+static void splitsort_visit_layer(t_visit self, t_splitsort sort)
{
- t_visit subdata;
- t_closure subvisit;
-
- if (self->depth == 0)
- return ((self->callback.func)(self->callback.data, self->mode, range));
- subdata = *self;
- subdata.depth--;
- if (subdata.mode == MODE_NORMAL)
- subdata.mode = MODE_REV;
- else
- subdata.mode = MODE_NORMAL;
- subvisit.data = &subdata;
- subvisit.func = &splitsort_visit_inner;
- if (self->mode != MODE_WRAP)
- splitsort_fortop(self->sort, self->mode, range, subvisit);
- splitsort_forbottom_rev(self->sort, self->mode, range, subvisit);
- if (self->mode == MODE_WRAP)
- splitsort_fortop(self->sort, self->mode, range, subvisit);
+ t_iter iter;
+
+ if (self.depth == 0)
+ {
+ return (self.cb(sort, self.range));
+ }
+ self.depth--;
+ iter = iter_new(self.range, sort.blocks, self.rev);
+ while (iter_nexti(&iter, &self.range))
+ splitsort_visit_layer(self, sort);
}
-void splitsort_visit(t_splitsort sort, t_list range,
- size_t depth, t_closure callback)
+void splitsort_part_layer(t_splitsort sort, t_list range, size_t depth)
{
t_visit visit;
- visit.sort = sort;
- visit.callback = callback;
+ visit.range = range;
visit.depth = depth;
- visit.mode = MODE_WRAP;
- splitsort_visit_inner(&visit, range);
+ visit.cb = layer_from_info(depth, sort.blocks, range.len);
+ visit.rev = depth % 2 == 1;
+ splitsort_visit_layer(visit, sort);
}
-typedef struct s_layer
-{
- t_splitsort sort;
-} t_layer;
-
void test_splitsort(const t_stacks *stacks, t_closure cb)
{
t_splitsort sort;
t_list range;
- t_closure part;
sort.stacks = stacks;
sort.cb = cb;
sort.blocks = 5;
range = list_new(stacks->a);
list_sort(range);
- part.func = &splitsort_part;
- part.data = &sort;
- for (size_t depth = 0; depth < 2; depth++)
- splitsort_visit(sort, range, depth, part);
+ for (size_t i = 0; i < 4; i++)
+ splitsort_part_layer(sort, range, i);
}