Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pq closures #28

Merged
merged 6 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 11 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ main(void)
capacity for swap space, min priority queue, no allocation, no aux. */
flat_priority_queue pq = fpq_heapify_init(
heap, (sizeof(heap) / sizeof(int)), 19, CCC_LES, NULL, int_cmp, NULL);
int *elem = &heap[5];
fpq_update_w(&pq, elem, { elem -= 4; });
int prev = *((int *)front(&pq));
(void)pop(&pq);
while (!is_empty(&pq))
Expand Down Expand Up @@ -561,13 +563,6 @@ val_cmp(ccc_cmp const cmp)
return (lhs->val > rhs->val) - (lhs->val < rhs->val);
}

static void
decrease_val(ccc_user_type const t)
{
struct val *const v = t.user_type;
v->val = *(int *)t.aux;
}

int
main(void)
{
Expand All @@ -579,8 +574,8 @@ main(void)
struct val const *const v = push(&pq, &elems[i].elem);
assert(v && v->val == elems[i].val);
}
int new_v = -99;
bool const decreased = decrease(&pq, &elems[4].elem, decrease_val, &new_v);
bool const decreased = pq_decrease_w(&pq, &elems[4].elem,
{ elems[4].val = -99; });
assert(decreased);
struct val const *const v = front(&pq);
assert(v->val == -99);
Expand Down Expand Up @@ -889,19 +884,17 @@ Composing multiple containers with this approach is also possible. Consider the
```c
struct dijkstra_vertex
{
ccc_romap_elem path_elem;
ccc_pq_elem pq_elem;
romap_elem path_elem;
pq_elem pq_elem;
int dist;
char cur_name;
char prev_name;
};
/* ... Later Initialization After Memory is Prepared ... */
ccc_realtime_ordered_map path_map = ccc_rom_init(
path_map, struct dijkstra_vertex, path_elem, cur_name, arena_alloc,
cmp_prev_vertices, &bump_arena);
ccc_priority_queue costs_pq
= ccc_pq_init(struct dijkstra_vertex, pq_elem, CCC_LES, NULL,
cmp_pq_costs, NULL);
realtime_ordered_map path_map = rom_init(path_map, struct dijkstra_vertex,
path_elem, cur_name, arena_alloc, cmp_prev_vertices, &bump_arena);
priority_queue costs_pq
= pq_init(struct dijkstra_vertex, pq_elem, LES, NULL, cmp_pq_costs, NULL);
/*... Steps to Prepare to Run the Algorithm ...*/
while (!is_empty(&costs_pq))
{
Expand All @@ -917,7 +910,7 @@ while (!is_empty(&costs_pq))
if (alt < next->dist)
{
next->prev_name = cur->cur_name;
decrease(&costs_pq, &next->pq_elem, pq_update_dist, &alt);
pq_decrease_w(&costs_pq, &next->pq_elem, { next->dist = alt; });
}
}
}
Expand Down
66 changes: 66 additions & 0 deletions ccc/flat_priority_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,27 @@ ccc_result ccc_fpq_erase(ccc_flat_priority_queue *fpq, void *e);
bool ccc_fpq_update(ccc_flat_priority_queue *fpq, void *e, ccc_update_fn *fn,
void *aux);

/** @brief Update the user type stored in the priority queue directly. O(lgN).
@param [in] fpq_ptr a pointer to the flat priority queue.
@param [in] T_ptr a pointer to the user type being updated.
@param [in] update_closure_over_T the semicolon separated statements to execute
on the user type at T_ptr (optionally wrapping {code here} in braces may help
with formatting). This closure may safely modify the key used to track the user
element's priority in the priority queue.
@return true on success, false if parameters are invalid or fpq is empty.
@warning the user must ensure T_ptr is in the fpq.

```
#define FLAT_PRIORITY_QUEUE_USING_NAMESPACE_CCC
flat_priority_queue fpq = build_rand_int_fpq();
int *i = get_rand_fpq_elem(&fpq);
fpq_update_w(&fpq, i, { *i = rand_key(); });
```

Note that whether the key increases or decreases does not affect runtime. */
#define ccc_fpq_update_w(fpq_ptr, T_ptr, update_closure_over_T) \
ccc_impl_fpq_update_w(fpq_ptr, T_ptr, update_closure_over_T)

/** @brief Increase e that is a handle to the stored fpq element. O(lgN).
@param [in] fpq a pointer to the flat priority queue.
@param [in] e a handle to the stored fpq element. Must be in the fpq.
Expand All @@ -146,6 +167,27 @@ bool ccc_fpq_update(ccc_flat_priority_queue *fpq, void *e, ccc_update_fn *fn,
bool ccc_fpq_increase(ccc_flat_priority_queue *fpq, void *e, ccc_update_fn *fn,
void *aux);

/** @brief Increase the user type stored in the priority queue directly. O(lgN).
@param [in] fpq_ptr a pointer to the flat priority queue.
@param [in] T_ptr a pointer to the user type being updated.
@param [in] increase_closure_over_T the semicolon separated statements to
execute on the user type at T_ptr (optionally wrapping {code here} in braces may
help with formatting). This closure may safely modify the key used to track the
user element's priority in the priority queue.
@return true on success, false if parameters are invalid or fpq is empty.
@warning the user must ensure T_ptr is in the fpq.

```
#define FLAT_PRIORITY_QUEUE_USING_NAMESPACE_CCC
flat_priority_queue fpq = build_rand_int_fpq();
int *i = get_rand_fpq_elem(&fpq);
fpq_update_w(&fpq, i, { (*i)++; });
```

Note that if this priority queue is min or max, the runtime is the same. */
#define ccc_fpq_increase_w(fpq_ptr, T_ptr, increase_closure_over_T) \
ccc_impl_fpq_increase_w(fpq_ptr, T_ptr, increase_closure_over_T)

/** @brief Decrease e that is a handle to the stored fpq element. O(lgN).
@param [in] fpq a pointer to the flat priority queue.
@param [in] e a handle to the stored fpq element. Must be in the fpq.
Expand All @@ -156,6 +198,27 @@ bool ccc_fpq_increase(ccc_flat_priority_queue *fpq, void *e, ccc_update_fn *fn,
bool ccc_fpq_decrease(ccc_flat_priority_queue *fpq, void *e, ccc_update_fn *fn,
void *aux);

/** @brief Increase the user type stored in the priority queue directly. O(lgN).
@param [in] fpq_ptr a pointer to the flat priority queue.
@param [in] T_ptr a pointer to the user type being updated.
@param [in] decrease_closure_over_T the semicolon separated statements to
execute on the user type at T_ptr (optionally wrapping {code here} in braces may
help with formatting). This closure may safely modify the key used to track the
user element's priority in the priority queue.
@return true on success, false if parameters are invalid or fpq is empty.
@warning the user must ensure T_ptr is in the fpq.

```
#define FLAT_PRIORITY_QUEUE_USING_NAMESPACE_CCC
flat_priority_queue fpq = build_rand_int_fpq();
int *i = get_rand_fpq_elem(&fpq);
fpq_update_w(&fpq, i, { (*i)--; });
```

Note that if this priority queue is min or max, the runtime is the same. */
#define ccc_fpq_decrease_w(fpq_ptr, T_ptr, decrease_closure_over_T) \
ccc_impl_fpq_decrease_w(fpq_ptr, T_ptr, decrease_closure_over_T)

/**@}*/

/** @name Deallocation Interface
Expand Down Expand Up @@ -241,6 +304,9 @@ typedef ccc_flat_priority_queue flat_priority_queue;
# define fpq_update(args...) ccc_fpq_update(args)
# define fpq_increase(args...) ccc_fpq_increase(args)
# define fpq_decrease(args...) ccc_fpq_decrease(args)
# define fpq_update_w(args...) ccc_fpq_update_w(args)
# define fpq_increase_w(args...) ccc_fpq_increase_w(args)
# define fpq_decrease_w(args...) ccc_fpq_decrease_w(args)
# define fpq_clear(args...) ccc_fpq_clear(args)
# define fpq_clear_and_free(args...) ccc_fpq_clear_and_free(args)
# define fpq_is_empty(args...) ccc_fpq_is_empty(args)
Expand Down
23 changes: 23 additions & 0 deletions ccc/impl/impl_flat_priority_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct ccc_fpq_

size_t ccc_impl_fpq_bubble_up(struct ccc_fpq_ *, char[], size_t);
void ccc_impl_fpq_in_place_heapify(struct ccc_fpq_ *, size_t n);
void ccc_impl_fpq_update_fixup(struct ccc_fpq_ *, void *);

/* NOLINTBEGIN(readability-identifier-naming) */

Expand Down Expand Up @@ -86,6 +87,28 @@ void ccc_impl_fpq_in_place_heapify(struct ccc_fpq_ *, size_t n);
fpq_res_; \
}))

/* Only one update fn is needed because there is no advantage to updates if
it is known they are min/max increase/decrease etc. */
#define ccc_impl_fpq_update_w(fpq_ptr, T_ptr, update_closure_over_T) \
(__extension__({ \
struct ccc_fpq_ *const fpq_ = (fpq_ptr); \
bool fpq_update_res_ = false; \
void *const fpq_t_ptr_ = (T_ptr); \
if (fpq_ && fpq_t_ptr_ && !ccc_buf_is_empty(&fpq_->buf_)) \
{ \
fpq_update_res_ = true; \
{update_closure_over_T} ccc_impl_fpq_update_fixup(fpq_, \
fpq_t_ptr_); \
} \
fpq_update_res_; \
}))

#define ccc_impl_fpq_increase_w(fpq_ptr, T_ptr, increase_closure_over_T) \
ccc_impl_fpq_update_w(fpq_ptr, T_ptr, increase_closure_over_T)

#define ccc_impl_fpq_decrease_w(fpq_ptr, T_ptr, decrease_closure_over_T) \
ccc_impl_fpq_update_w(fpq_ptr, T_ptr, decrease_closure_over_T)

/* NOLINTEND(readability-identifier-naming) */

#endif /* CCC_IMPL_FLAT_PRIORITY_QUEUE_H */
52 changes: 52 additions & 0 deletions ccc/impl/impl_priority_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct ccc_pq_
void *aux_;
};

/* NOLINTBEGIN(readability-identifier-naming) */

#define ccc_impl_pq_init(struct_name, pq_elem_field, pq_order, alloc_fn, \
cmp_fn, aux_data) \
{ \
Expand All @@ -44,6 +46,9 @@ struct ccc_pq_

void ccc_impl_pq_push(struct ccc_pq_ *, struct ccc_pq_elem_ *);
struct ccc_pq_elem_ *ccc_impl_pq_elem_in(struct ccc_pq_ const *, void const *);
void ccc_impl_pq_update_fixup(struct ccc_pq_ *, struct ccc_pq_elem_ *);
void ccc_impl_pq_increase_fixup(struct ccc_pq_ *, struct ccc_pq_elem_ *);
void ccc_impl_pq_decrease_fixup(struct ccc_pq_ *, struct ccc_pq_elem_ *);

#define ccc_impl_pq_emplace(pq_ptr, lazy_value...) \
(__extension__({ \
Expand All @@ -69,4 +74,51 @@ struct ccc_pq_elem_ *ccc_impl_pq_elem_in(struct ccc_pq_ const *, void const *);
pq_res_; \
}))

#define ccc_impl_pq_update_w(pq_ptr, pq_elem_ptr, update_closure_over_T) \
(__extension__({ \
struct ccc_pq_ *const pq_ = (pq_ptr); \
bool pq_update_res_ = false; \
struct ccc_pq_elem_ *const pq_elem_ptr_ = (pq_elem_ptr); \
if (pq_ && pq_elem_ptr_ && pq_elem_ptr_->next_sibling_ \
&& pq_elem_ptr_->prev_sibling_) \
{ \
pq_update_res_ = true; \
{update_closure_over_T} ccc_impl_pq_update_fixup(pq_, \
pq_elem_ptr_); \
} \
pq_update_res_; \
}))

#define ccc_impl_pq_increase_w(pq_ptr, pq_elem_ptr, increase_closure_over_T) \
(__extension__({ \
struct ccc_pq_ *const pq_ = (pq_ptr); \
bool pq_increase_res_ = false; \
struct ccc_pq_elem_ *const pq_elem_ptr_ = (pq_elem_ptr); \
if (pq_ && pq_elem_ptr_ && pq_elem_ptr_->next_sibling_ \
&& pq_elem_ptr_->prev_sibling_) \
{ \
pq_increase_res_ = true; \
{increase_closure_over_T} ccc_impl_pq_increase_fixup( \
pq_, pq_elem_ptr_); \
} \
pq_increase_res_; \
}))

#define ccc_impl_pq_decrease_w(pq_ptr, pq_elem_ptr, decrease_closure_over_T) \
(__extension__({ \
struct ccc_pq_ *const pq_ = (pq_ptr); \
bool pq_decrease_res_ = false; \
struct ccc_pq_elem_ *const pq_elem_ptr_ = (pq_elem_ptr); \
if (pq_ && pq_elem_ptr_ && pq_elem_ptr_->next_sibling_ \
&& pq_elem_ptr_->prev_sibling_) \
{ \
pq_decrease_res_ = true; \
{decrease_closure_over_T} ccc_impl_pq_decrease_fixup( \
pq_, pq_elem_ptr_); \
} \
pq_decrease_res_; \
}))

/* NOLINTEND(readability-identifier-naming) */

#endif /* CCC_IMPL_PRIORITY_QUEUE_H */
Loading