The design issue I'm currently solving is to iterate over some region of memory and on each such iteration retrieve from that memory some meta-data the client is interested in. I see 2 solutions currently:
I.
struct queue;
struct queue_element_view{
int id;
char *description;
};
//0 - if ok, -1 - if end of queue reached
int next(struct queue*);
//0 - if ok, -1 - if end of queue reached
int current_element_view(struct queue*, struct queue_element_view *);
So the queue opaque struct can be traversed via next
function and since the queue elements are platform dependent and I want to keep the library cross platform I provided a platform-independent struct queue_element_view
that is sensible on all platforms.
Drawback:
If client writes code like this:
struct queue *queue_ptr = //
struct queue_element_view current_out;
current_element_view(queue_ptr, ¤t_out);
//current_out now contains current's element meta data
next(queue_ptr);
//current_out now may contain unspecified data
//since queue's current element changed.
So calling to next
after calling to current_element_view
clobbers the current_out
.
II.
struct queue;
struct queue_element_view;
struct queue_element_view *allocate_view(void);
int * get_id(struct queue_element_view *);
char * get_description(struct queue_element_view *);
//0 - if ok, -1 - if end of queue reached
int next(struct queue*);
//0 - if ok, -1 - if end of queue reached
int current_element_view(struct queue*, struct queue_element_view *);
In this case we have allocated struct queue_element_view
and current_element_view
copies data to the object pointed to by struct queue_element_view *
so next does not clobber the data.
Drawbacks:
It involves a function additional call to simply retrieve
int
andchar *
fieldsIt makes testing public api more complicated.
So I'm kind of confused which one would be preferrable/readable? Probably there is another alternative?