libclc-developers Mailing List for libclc (Page 4)
Status: Planning
Brought to you by:
augestad
You can subscribe to this list here.
| 2003 |
Jan
|
Feb
(1) |
Mar
(170) |
Apr
(73) |
May
(3) |
Jun
(1) |
Jul
(1) |
Aug
|
Sep
(2) |
Oct
|
Nov
|
Dec
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
|
From: Hallvard B F. <h.b...@us...> - 2003-04-02 10:21:37
|
Bertrand Mollinier Toublet writes: > Hallvard, thanks for the proposal, but... > Thinking about the documentation issue, it appears that there is not > likely going to be any *development* platform that doesn't also have > HTML viewing support (e.g. the most hardcore command line Unix > environment likely has Lynx). Thus, I'd like to think that the most > practical format to publish our documentation is HTML. Of course there > is a difference between what we published and what we archive, the > former possibly being a processed version of the latter. Sigh. Just like me to suggest the format and forget to mention _why_ I suggested it. The idea was * to have one source format for documentation from which a script would produce the "real" documentation: at least HTML, text and Unix man format. Similar to doxygen, I take it. I'd like us to make the documentation available in at least these formats. After that, PostScript documentation can be generated with groff from the manpages for those who are interested. For that matter, I think the text format can too. * A simple enough source format that contributors can write it even if they have no special tools like doxygen, and which should be easy for the documentation manager(s) to edit to fix any problem in the contributed text. That way there will be no need to translate contributed documentation to doxygen. > So, while I agree that the current format is certainly not adapted to > our needs (and I should know, having "translated" all of the > documentation so far from the text source to adequate HTML tagging), I > don't think something slightly enhanced, but still close will be > satisfying either. I'm not quite sure what you mean here. My format can be translated to Unix-manpage-like HTML pages, with links to other the HTML pages documenting other CLC functions. Is that insufficient? > I would like to try and come up with a general design for HTML version > of our documentation. Once this is done, and approved, I could provide > templates for the developers to fill out. I think it's a very bad idea to request people to write HTML documentation. Experience shows that this will give us a lot of bad HTML, unless the documentation manager(s) takes on the job of cleaning it up and validating it. Even then, cleanup can be a lot of work. Besides, we can't generate Unix manpages from HTML. > In the long run, we would like to come up with a more powerful tagging > system (maybe somthing inspired from the DocBook format), I don't know that one. > maybe also an alternate version of the documentation targeted at > libclc developers rather than libclc users, etc. Hmm. I'm not sure what that part would say, at least not something which fit in the user documentation. If it's about the implementation of a module, it belongs in the source code, not in the user documentation. The latter should not change if the implementation changes. -- Hallvard |
|
From: regis <re...@in...> - 2003-04-02 08:22:42
|
Bertrand Mollinier Toublet wrote: > > > From: Hallvard B Furuseth <h.b...@us...> > > > > Here is a suggestion for a file format for documentation. > > Contributors should write this, though maybe the documentation > > manager(s) will clean the file up a little, and it will be used to > > generate the other formats. If accepted, I'll write a Perl program to > > process it. The overall documentation structure reflects Unix man > > pages, as in <http://libclc.sourceforge.net/documentation-policy.txt>. > > I've also added an initial NAME section. (Bertrand, are you there?:-) > > > Yes, I am there... er... from time to time ;-) > Sorry for the delay in replying... > > > Format description: > > > <snipped> > > > Hallvard, thanks for the proposal, but... > Thinking about the documentation issue, it appears that there is not > likely going to be any *development* platform that doesn't also have > HTML viewing support (e.g. the most hardcore command line Unix > environment likely has Lynx). Thus, I'd like to think that the most > practical format to publish our documentation is HTML. Of course there > is a difference between what we published and what we archive, the > former possibly being a processed version of the latter. > > So, while I agree that the current format is certainly not adapted to > our needs (and I should know, having "translated" all of the > documentation so far from the text source to adequate HTML tagging), I > don't think something slightly enhanced, but still close will be > satisfying either. > > I would like to try and come up with a general design for HTML version > of our documentation. Once this is done, and approved, I could provide > templates for the developers to fill out. > > In the long run, we would like to come up with a more powerful tagging > system (maybe somthing inspired from the DocBook format), from which we > could produce a satisfying HTML version, why not a text version to be > bundled with libclc releases, maybe also an alternate version of the > documentation targeted at libclc developers rather than libclc users, > etc. > > > Questions: > > > <snip troff stuff> > > > > - Should manpage references in text, html and PostScript formats use > > the Unix format 'strcmp(3)', or just 'strcmp'? > > > Since we are not really producing any man-pages, merely a mimic of it, I > think our references shall not include a man-section number. > Can somebody recall me why the option of doxygen has been dropped while it produces html, man pages, and latex outputs? -- Regis |
|
From: Bertrand M. T. <ber...@en...> - 2003-04-01 23:02:23
|
> From: Hallvard B Furuseth <h.b...@us...> > > Here is a suggestion for a file format for documentation. > Contributors should write this, though maybe the documentation > manager(s) will clean the file up a little, and it will be used to > generate the other formats. If accepted, I'll write a Perl program to > process it. The overall documentation structure reflects Unix man > pages, as in <http://libclc.sourceforge.net/documentation-policy.txt>. > I've also added an initial NAME section. (Bertrand, are you there?:-) > Yes, I am there... er... from time to time ;-) Sorry for the delay in replying... > Format description: > <snipped> > Hallvard, thanks for the proposal, but... Thinking about the documentation issue, it appears that there is not likely going to be any *development* platform that doesn't also have HTML viewing support (e.g. the most hardcore command line Unix environment likely has Lynx). Thus, I'd like to think that the most practical format to publish our documentation is HTML. Of course there is a difference between what we published and what we archive, the former possibly being a processed version of the latter. So, while I agree that the current format is certainly not adapted to our needs (and I should know, having "translated" all of the documentation so far from the text source to adequate HTML tagging), I don't think something slightly enhanced, but still close will be satisfying either. I would like to try and come up with a general design for HTML version of our documentation. Once this is done, and approved, I could provide templates for the developers to fill out. In the long run, we would like to come up with a more powerful tagging system (maybe somthing inspired from the DocBook format), from which we could produce a satisfying HTML version, why not a text version to be bundled with libclc releases, maybe also an alternate version of the documentation targeted at libclc developers rather than libclc users, etc. > Questions: > <snip troff stuff> > > - Should manpage references in text, html and PostScript formats use > the Unix format 'strcmp(3)', or just 'strcmp'? > Since we are not really producing any man-pages, merely a mimic of it, I think our references shall not include a man-section number. -- Bertrand |
|
From: Jan E. <je...@li...> - 2003-04-01 15:09:27
|
>>>What do we gain? What don't we gain? >> Sorry, that was a rather truncated message. >> What I meant to say was, there are filesystems with uncomfortable >> limits for filenames, like 8.3 characters or max 14 characters. >> So we should try to keep filenames short. > >Does anyone on the list even know of a C developer working on platform >with a 8.3 filesystem only? I don't... (Partially) me... TCPP/DOS is quite handy for Physics in school.. >We cannot make everyone happy, and I'm not going to have lousy filenames >for 99% of us to support 1% working on archaic or very special >platforms. They won't use libclc anyway. - Jan Engelhardt |
|
From: Jan E. <je...@li...> - 2003-04-01 15:08:16
|
>Sorry, that was a rather truncated message. (as 8.3 is) >What I meant to say was, there are filesystems with uncomfortable >limits for filenames, like 8.3 characters or max 14 characters. >So we should try to keep filenames short. > >> If a standalone function is named clc_foo, I hope to see >> clc_foo.c >> clc_foo.man >> clc_foo.html *grin* clc_foo.htm even! - Jan Engelhardt |
|
From: Jan E. <je...@li...> - 2003-04-01 15:07:36
|
>Here is a suggestion for a file format for documentation. >Contributors should write this, though maybe the documentation >manager(s) will clean the file up a little, and it will be used to >generate the other formats. If accepted, I'll write a Perl program to >process it. The overall documentation structure reflects Unix man >pages, as in <http://libclc.sourceforge.net/documentation-policy.txt>. >I've also added an initial NAME section. (Bertrand, are you there?:-) > >Comments welcome. > > >An example first, since that's shorter than the format description. >(CVS replaces $Id$ below with info about the file.) Hm if this is going to be in the C files itself, may using some sig like POD format does /* =pod =head1 NAME lolz... etc... =cut */ >@comment $Id$ >@comment Copyright 2003 Hallvard B. Furuseth <h.b...@us...> > >NAME > >clc_strblurg, clc_strglarp - fromp a string > >SYNOPSIS > >#include <clc_string.h> >char *clc_strblurg(char *src); >char *clc_strglarp(char *src); > >Link with: clc library > >DESCRIPTION > >These functions modify their arguments by fromping the string src. >@break >clc_strblurg() blurgifies the string first. >@break >clc_strglarp() glarps the string afterwards. > >RETURN VALUES > >The functions return src, or NULL at failure. > >ERROR CODES > >CLC_ENOFROMP >The string could not be fromped. >The resulting contents of src is undefined. > >CLC_ENOGLARP >The string could not be glarped. >src will contain the fromped but unglarped string. > >EXAMPLE > > /* Print a blurgified string using @manpage{printf} */ > void printfromp(const char *str) > { > char *tmp = clc_strdup(str); > if (tmp && clc_strblurg(tmp)) > printf("Glarp: %s\n", tmp); > free(tmp); > } > > >Format description: > >- A document consists of a series of paragraphs separated by blank > lines. Whitespace at the end of lines are ignored. > >- Normal paragraphs are plain text to be filled and justified. > >- Lines starting with '@' <word> <whitespace> are single-line commands: > @comment <text>... -- a comment-line, not written. > Retained as a comment in some output > filetypes, at the start of the paragraph. > A comment may not contain '--' (because > that mucks up HTML comments). > @section <name> -- start a section (NAME, SYNOPSIS, etc). > @subsection <name> -- start a subsection. > @break/@br -- force a line break. > @list ... @item <name> ... @end list -- list of items. Each item > can be followed by paragraphs describing it. > @fixed/@pre/@preformatted ... @end fixed/pre/preformatted > -- print fixed font, and don't fill. > @indent ... @end indent -- indent (but still fill/justify) contents. > @manpage <name> or <name>(section) -- explicit reference to manpage. > One may also write @manpage{...} or @fixed{...} in the middle of text. > @fixed{} text should be short: it will not be broken with line breaks. > Or should it be, at spaces? I'm not sure. > >- Various error checks are done: For example, all @items in the > ERRORS section are checked to be CLC_E*, ERANGE or EDOM. > >- The special cases below let us avoid most of the above commands. > Or are some of these too complex so it's simpler to always use > commands? > >- Indented paragraphs are not filled or justified, and they are printed > in a fixed-width font. 4 spaces of indentation are removed, or less > if the whole paragraph is not indented that much. > Thus, example code can be written just as it is by indenting it. > >- The paragraphs in the SYNOPSIS section are not filled or justified, > since they contain C code. > >- A paragraph which consists of one line of uppercase words is taken > to be a section header, e.g. NAME, DESCRIPTION, SEE ALSO and so on. > >- In the ERRORS section, if the first line of a paragraph is simply > one all-uppercase word (which may have digits and underscores), it > is considered to be an @item line. Also, if ERRORS has @items but > not @list, the whole ERRORS section from the first @item and onwards > is wrapped in @list ... @end list. > >- In the SEE ALSO section, single comma-separated words are translated > to manpage references if they either start with "clc_" or are ISO C > (1989) function names. If they are neither, they produce a warning. > >Other details: > >- Preformatted lines should be 58 or fewer characters long, or less > still if they are inside already-indented text (@indent or @list). > [Or should this be less still for the sake of HTML pages?] > >- Don't indent with TABs, use SPACEs. Some contributors will be using > tab-width 4, others will be using 8, so TABs for indentation would > cause havoc. > >- Please start each sentence on a new line. Troff notices this and > puts extra space after such sentences ending with '.', '!' or '?'. > I'll make a word starting with an uppercase letter except CLC_E* and > E*, which follows a letter, a ',', '!' or '?', and a space, to also > be taken to start a sentence. > >- Picky people can write opening single quotes as "`", not "'", like > troff and nroff want. We can't do that with quotes that should be > the C quoted char "'", so a program can't convert "'"s to "`"s. > >- 8-bit characters are taken to be latin-1 characters. > > >Questions: > >- Nroff and troff retain multiple spaces typed into a paragraph, > though troff's space is thinner than most other characters. Should > we retain this feature, or transform multiple spaces to single ones > in filled paragraphs like HTML does? > >- If a line in an otherwise unindented paragraph starts with > whitespace, nroff and troff retains that whitespace at the beginning > of a new line. However, they still break the line if it gets too > long or fill it from the next line if too short. I'm not sure what > to do about this feature. We could retain it, but my suggestion is > to report such paragraphs as an error -- probably there should be a > blank line between the indented and the unindented part. OK? > >- There are two basic dashes: minus and hyphen. Hyphen may be > shorter. I suggest all minuses are treated as minus, except that it > is a hyphen if there is a letter or digit on each side. Thus, one > should write 'size - strlen(foo)', not 'size-strlen(foo)'. OK? > >- Should manpage references in text, html and PostScript formats use > the Unix format 'strcmp(3)', or just 'strcmp'? (3) Hm, after wrting this short reply I realize that one could really USE pod, it's already written and can be embedded (I guess) into any language that supports multi-line comments (or POD directly). - Jan Engelhardt |
|
From: <bo...@me...> - 2003-03-31 15:40:38
|
Hi, everyone. Just wanted you to know that I just posted the source code for clc_string to comp.lang.c. I don't expect much flak, but who knows? ;-) Thanks to all. -- boa libclc home: http://libclc.sourceforge.net |
|
From: <pha...@al...> - 2003-03-31 02:28:44
|
I've been busy implementing many of the changes to the double linked list
module suggested by you all, and I include the latest draft of the interface
documentation here for your consideration. If I have not taken a suggestion
you feel is warrented, don't worry. I may still do so. I'm still trying to
figure out the best way to go about some things and just didn't get around
to other things yet.
I do have a question, though. There has been talk of including other
container types in libclc (single linked lists, trees, deques, etc.). Are we
going to have one module for each of these, or would it make more sense to
put these all in one module?
Now, what have I done to the double linked list interface? Well, I've
added functions that return a node's next and prev pointers. I've added a
function that iterates through the list and calls a user defined function
for each node. There's also a new search function that goes "backward", as
suggested by Bryan Donlan. I think it was Bryan who also suggested a
function to insert a new node at a given location, which was something I was
already thinking about. I have implemented that function. I've also changed
type names to lower case, as several people have suggested. I added a copy
node function a couple of people suggested. Other changes: well, you can see
for yourself.
This document explains how to use the functions and data types defined
by the clc_dl module. This module implements a generic double linked
list system that is easy to use but flexible.
Data types:
===========
These are the data types defined by this module. They are defined in
the clc_dl.h header file. These types should generally not be touched
directly by users. Leave it to the module to manipulate these types.
However, their definitions are provided to users by defining
CLC_DL_ADVANCED_FUNCS before including the header. This allows extra
flexibility and control.
typedef struct clc_dl_node
{
struct clc_dl_node *prev, *next;
int type; /* payload type */
size_t size; /* payload size */
void *payload; /* payload data */
void (*cleanup)(void *); /* cleanup function */
} clc_dl_node;
clc_dl_node is the basis of the system. It is the double linked list
node type. The members of this struct are as follows:
prev, next pointers to the previous and next nodes
type the payload type (in case of a linked list containing
more than one type of data
size size of the payload
payload pointer to the actual payload itself
cleanup pointer to a user supplied function to cleanup any extra
memory associated with a node's payload (but not the
node or payload itself - clc_dl_FreeNode() takes care of
that)
typedef struct clc_dl_list
{
clc_dl_node *head, *tail; /* first and last nodes */
size_t num; /* number of nodes */
} clc_dl_list;
clc_dl_list is a structure intended to store all data needed to access
and manipulate a linked list, currently comprising the following:
head, tail pointers to the first and last nodes in the list (NULL
if list is empty)
num number of nodes in the list
Most accesses to a linked list use this struct. An object of this type
is obtained (dynamically allocated) by using the clc_dl_NewList()
function.
struct clc_dl_search_data
{
clc_dl_list *list; /* list the search applys to */
clc_dl_node *lastnode; /* last node found by search */
int type; /* type of payload to search for */
size_t size; /* size of payload to search for */
void *find; /* payload data to search for */
int (*cmp)(int keytype, size_t keysize, const void *keydata,
int nodetype, size_t nodesize,
const void *nodedata); /* compare func */
int dir; /* direction of search:
>= 0 means forward,
< 0 means backward */
};
clc_dl_search_data is a structure used in linked list search
operations. Searching in the clc_dl module uses two functions;
clc_dl_FindFirst(), which takes (among other arguments) a pointer to
this type, and clc_dl_FindNext() which takes the same pointer. The
former fills in the object this pointer points to with values related to
the search. These values are as follows:
list pointer to the clc_dl_list the search pertains to
lastnode the last found node that matches the search criteria
(a null pointer if search failed)
type payload type of the node data to find
find pointer to data to find in the linked list
cmp pointer to a function that compares the key data, size
and type with a node's payload data, size and type,
returning 0 if they compare equal and non-zero
otherwise.
dir the direction of the search: use a value >= 0 to search
forward from the start of the list, or a value < 0 to
search backward from the end of the list
The clc_dl_FindNext() function uses this data to continue the search
using the same criteria, and updates the lastnode member each time it is
called. Users should obtain a pointer to a clc_dl_search_data object, by
using clc_dl_NewSearch(), and pass it to clc_dl_FindFirst() and
clc_dl_FindNext() to search for nodes.
The macros CLC_DL_FORWARD and CLC_DL_REVERSE are provided as a
convenience for the dir member. Use the former to search forward or the
latter to search backward.
typedef int clc_dl_cmpfunc(
int keytype, /* type of key data */
size_t keysize, /* size of key data */
const void *keydata, /* key data */
int nodetype, /* type of node payload data */
size_t nodesize, /* size of node payload data */
const void *nodedata); /* node payload data */
The clc_dl_cmpfunc type is defined merely to make clc_dl module code
easier to read. It is the type of user defined comparison functions
(see below).
Basic functions:
================
The following are the "basic" functions, the ones most commonly used,
in the clc_dl module. These are defined in the clc_dl.c file. "Advanced"
functions, which provide extra flexibility but are less commonly used,
are described below this section.
clc_dl_list *clc_dl_NewList(void)
The clc_dl_NewList() function is used to dynamically allocate and
initialise a clc_dl_list structure. All fields are initialised to
reflect an empty linked list (one with no nodes).
clc_dl_node *clc_dl_InsertData(clc_dl_list *list,
int dir,
int type,
size_t size,
void *payload,
void (*cleanup)(void *));
The clc_dl_InsertData() function is used to create a new node and
insert new data into a linked list. It returns a pointer to the new
node, or a null pointer if memory could not be allocated for the node.
The parameters are:
list a pointer indicating the linked to insert data into
dir direction of insertion: use value < 0 to insert at the
start of the list, ora value >= 0 to insert at the end of
the list
type type of the payload (in case of a list containing more
than one type of data)
size size of the payload
payload the data to be copied to the new node's payload
cleanup pointer to a user supplied function to cleanup any extra
memory associated with a node's payload (but not the
node or payload itself - clc_dl_FreeNode() takes care of
that)
The last argument may be a null pointer, in which case no cleanup
function will be called, but the node and its payload will still be
de-allocated normally by clc_dl_FreeNode().
The macros CLC_DL_FRONT, CLC_DL_START and CLC_DL_END are provided as a
convenience for the dir argument. Use either of the first two to insert
at the start of the list or the last to insert at the end.
clc_dl_node *clc_dl_InsertDataAt(clc_dl_list *list,
int dir,
clc_dl_node *location,
int type,
size_t size,
void *payload,
void (*cleanup)(void *));
clc_dl_InsertDataAt() is very similar to clc_dl_InsertData(). It
creates a new double linked list node and stored data in it the same was
as clc_dl_InsertData(). The difference is that this function allows the
user to specify where the node will be inserted. The new node is
inserted before or after (depending on the dir argument) a given node
(location). It returns a pointer to the new node, or a null pointer if
memory could not be allocated for the node. The parameters are:
list a pointer indicating the linked to insert data into
dir direction of insertion: use a value < 0 to insert before
the specified node, or a value >= 0 to insert after the
specified node
location the node to insert the new node before or after
type type of the payload (in case of a list containing more
than one type of data)
size size of the payload
payload the data to be copied to the new node's payload
cleanup pointer to a user supplied function to cleanup any extra
memory associated with a node's payload (but not the
node or payload itself - clc_dl_FreeNode() takes care of
that)
The macros CLC_DL_BEFORE and CLC_DL_END are provided as a convenience
for the dir argument. Use the former to insert before the given location
or the latter to insert after it.
clc_dl_search_data clc_dl_NewSearch(void);
void clc_dl_FreeSearch(clc_dl_search_data *sd);
clc_dl_NewSearch() dynamically allocates a clc_dl_search_data
structure that can be used by clc_dl_FindFirst() and clc_dl_FindNext().
clc_dl_FreeSearch() is used to de-allocate this structure.
clc_dl_node *clc_dl_FindFirst(clc_dl_list *list,
int type,
size_t size,
void *find,
clc_dl_cmpfunc *cmp,
int dir,
clc_dl_search_data *srch);
clc_dl_node *clc_dl_FindNext(clc_dl_search_data *srch);
The clc_dl_FindFirst() and clc_dl_FindNext() functions are used to
search linearly for a node or nodes of a specified type containing a
specified set of data. The parameters of the former are:
list pointer indicating the linked list to search
type type of payload to search for
size size of payload to search for
find data to search for in payloads
cmp pointer to compare function (compares key type, size and
data to node's payload type, size and data - returns 0
if match, non-zero otherwise)
dir direction of search: use CLC_DL_FORWARD to search
forward from the start of the list or CLC_DL_REVERSE to
search backward from the end of the list
srch pointer to a structure containing data used in the
search process
clc_dl_FindFirst() searches for the first node that matches (according
to the comparison function passed as the fifth argument) the key data
and its type and size. clc_dl_FindNext(), using a clc_dl_search_data *
previously passed to clc_dl_FindFirst(), searches for subsequent nodes
that match the search criteria specified in the clc_dl_FindFirst() call.
clc_dl_FindFirst() returns a pointer to the first node found that
matches the search criteria. clc_dl_FindNext() returns a pointer to the
next node in turn that matches the search criteria. Both functions
return a null pointer if a match is not found.
The macros CLC_DL_FORWARD and CLC_DL_REVERSE are provided as a
convenience for clc_dl_FindFirst()'s dir argument. Use the former to
search forward or the latter to search backward.
void clc_dl_FreeList(clc_dl_list *list);
clc_dl_FreeList() removes all nodes and de-allocates all memory
associated with a linked list, including the clc_dl_list structure. Its
single parameter, a pointer to clc_dl_list, indicates the linked list to
de-allocate. The function calls clc_dl_FreeNode() to de-allocate each
node.
If the user supplied a cleanup function (when the node was created),
then that function is called before the payload of each node is
de-allocated.
void clc_dl_FreeNode(clc_dl_list *list, clc_dl_node *node);
clc_dl_FreeNode() removes a node from a linked list and de-allocates
it. The first parameter is a pointer to clc_dl_list indicating the
linked list the node belongs to. If the node to be freed is not in a
linked list (not associated with a clc_dl_list structure), the argument
passed to this parameter must be a null pointer. The second parameter is
a pointer to the node to free. If the user supplied a cleanup function
(when the node was created), then that function is called before the
payload and node are de-allocated.
void *clc_dl_Payload(clc_dl_node *node, void *data);
clc_dl_Payload() stores a copy of a node's payload data in a user
supplied buffer, and returns a pointer to this copied data. The first
parameter is a pointer to the node whose payload data is to be copied.
The second parameter is a pointer to the buffer used to copy the data
to. The return value is the argument passed to the data parameter.
size_t clc_dl_NumNodes(clc_dl_list *list);
int clc_dl_Type(clc_dl_node *node);
size_t clc_dl_Size(clc_dl_node *node);
clc_dl_NumNodes() returns the number of nodes in the linked list
specified by its only parameter, a pointer to clc_dl_list.
clc_dl_Type() returns the payload type of the linked list node
specified by its only parameter, a pointer to clc_dl_node.
clc_dl_Size() returns the payload size of the linked list node
specified by its only parameter, a pointer to clc_dl_node.
clc_dl_node *clc_dl_NextNode(clc_dl_node *node);
clc_dl_node *clc_dl_PrevNode(clc_dl_node *node);
clc_dl_node *clc_dl_Link(clc_dl_node *node, int dir);
clc_dl_NextNode() returns the "next" pointer of the double linked list
node pointed to by its single argument.
clc_dl_PrevNode() returns the "prev" pointer of the double linked list
node pointed to by its single argument.
clc_dl_Link() returns the "next" (if dir >= 0) or "prev" (if dir < 0)
pointer of the node pointed to by its node argument. The macros
CLC_DL_NEXT and CLC_DL_PREV are provided for the dir argument as a
convenience.
int clc_dl_ForEach(clc_dl_list *list,
int (*func)(clc_dl_node *),
int dir);
clc_dl_ForEach() is a function that iterates over all the nodes in a
double linked list, passing (a pointer to) each node to a user supplied
function. The first parameter is a pointer to the linked list whose
nodes are to be iterated over. The (user supplied) function specified by
the second parameter is called and passed the address of each node in
the list in turn. The third parameter is the direction of iteration;
>= 0 means iterate forward, while < 0 means iterate backward. The macros
CLC_DL_FORWARD and CLC_DL_BACKWARD have been supplied for convenience.
Iteration can be stopped prematurely by returning non-zero from the
called function, in which case the value returned by that function will
also be returned by clc_dl_ForEach(). Otherwise clc_dl_ForEach() returns
0.
void clc_dl_Sort(clc_dl_list *list, clc_dl_cmpfunc *cmp);
The clc_dl_Sort() function sorts the nodes of a double linked list
according to a user supplied comarison function.
I came up with two versions of the following function. The first one
here is the original version. After writing it, I re-thought the
possible needs of users, and thought a slightly more versatile version
would be better. So I rewrote it (with an extra function for even more
versatility). But the new version uses variable argument lists, and may
be overkill. What do you all think? Should I keep the variable args
version or go back to the original? Or should I rename one of the
versions and keep both of them?
Original version:
clc_dl_list *clc_dl_MergeLists(clc_dl_list *list1, clc_dl_list *list2);
clc_dl_MergeLists() creates a new double linked list and copies the
nodes (and their payloads) of two source linked lists, as specified by
its two arguments, into it. The nodes are not sorted. On success, the
function returns a pointer to the new linked list. On failure, it
returns a null pointer. In either case the source lists are not
modified.
Variable args version:
clc_dl_list *clc_dl_vMergeLists(size_t num, va_list arg);
clc_dl_list *clc_dl_MergeLists(size_t num, ...);
The clc_dl_vMergeLists() and clc_dl_MergeLists() functions create a
new double linked list and copies the nodes from a number of existing
lists into it. The first parameter represents the number of lists to be
merged into the new list. The second parameter represents pointers to
the lists to merge. On success, these functions return a pointer to the
new list. On failure they return a null pointer. In either case the
source lists are not modified.
Advanced functions:
===================
The following functions are defined in the clc_dl_a.c source file.
Thier prototypes are available by defining a macro called
CLC_DL_ADVANCED_FUNCS before the clc_dl.h header is included.
clc_dl_node *clc_dl_NewNode(int type,
size_t size,
void *payload,
void (*cleanup)(void *));
clc_dl_NewNode() creates a new clc_dl_node structure and fills it with
data. The parameters are:
type type of the data to store in the node's payload
size size of data to store in the node's payload
payload pointer to data to store in the node's (dynamically
allocated) payload
cleanup pointer to a user supplied function to cleanup any extra
memory associated with a node's payload (but not the
node or payload itself - clc_dl_FreeNode() takes care of
that)
The last argument may be a null pointer, in which case no cleanup
function will be called, but the node and its payload will still be
de-allocated normally by clc_dl_FreeNode().
void clc_dl_InsertNodes(clc_dl_list *list,
clc_dl_node *location,
clc_dl_node *start,
int dir);
clc_dl_InsertNodes() inserts a "mini-list", a group of one or more
linked nodes that are not part of a linked list (ie., are not associated
with a clc_dl_list structure), into a linked list. The parameters are:
list pointer to the list to insert the mini-list into
location pointer to "target node" where the mini-list will be
inserted (the mini-list will be inserted either before
or after this node)
start pointer to the first node in the mini-list
dir direction of insertion: use CLC_DL_BEFORE to insert
before the target node or CLC_DL_AFTER to insert after
the target node
clc_dl_node *clc_dl_RemoveNode(clc_dl_list *list, clc_dl_node *node);
clc_dl_RemoveNode() removes a node from a linked list, but does not
de-allocate the it. The node is still available (via the returned
pointer) to manipulate as required. The first parameter is a pointer to
the linked list the node belongs to, while the second is a pointer to
the node to be removed.
clc_dl_node *clc_dl_RemoveMultiNodes(clc_dl_list *list,
clc_dl_node *start,
size_t num);
clc_dl_RemoveMultiNodes() removes one or more nodes from a linked
list, but does not de-allocate them. The nodes removed remain linked,
forming a "mini-list", a group of one or more linked nodes that are not
part of a linked list (ie., are not associated with a clc_dl_list
structure). The nodes are still available (via the returned pointer,
which points to the first node in the mini-list) to manipulate as
required. The function parameters are:
list pointer to the list to remove nodes from
start pointer to the first node to remove
num the number of nodes to remove
If the last argument is greater than the number of nodes from the node
indicated by the second argument to the end of the list, then all the
nodes from the start node to the end of the list are removed.
void *clc_dl_ModifyPayload(clc_dl_node *node,
int newtype,
size_t newsize,
void *newpayload,
void (*newcleanup)(void *));
clc_dl_ModifyPayload() is used to change a clc_dl_node's payload and
cleanup function. The original payload is de-allocated. If the user
supplied a cleanup function (when the node was created), then that
function is called before the payload is de-allocated. The parameters
are:
node pointer to the node to modify
newtype the new payload type
newsize new payload size
newpayload pointer to data to copy to new payload
newcleanup pointer to a user supplied function to cleanup any extra
memory associated with a node's payload (but not the
node or payload itself - clc_dl_FreeNode() takes care of
that)
The last argument may be a null pointer, in which case no cleanup
function will be called, but the node and its payload will still be
de-allocated normally by clc_dl_FreeNode().
clc_dl_ModifyPayload() returns a pointer to the new payload on
success. It returns a null pointer if memory could not be allocated for
the new payload, in which case the old payload remains intact.
clc_dl_node *clc_dl_GetHead(clc_dl_list *list);
clc_dl_node *clc_dl_GetTail(clc_dl_list *list);
The clc_dl_GetHead() and clc_dl_GetTail() functions return pointers to
the first and last nodes (respectively) in a linked list. The solitary
paramer to each of these functions is a pointer to clc_dl_list
representing the linked list whose head/tail node pointer will be
returned.
User supplied functions:
========================
This section explains the purpose and requirements of user supplied
functions used by the clc_dl module. The user must follow these rules
when writing these functions.
Cleanup functions:
------------------
A cleanup function, as used by clc_dl_FreeNode(), clc_dl_FreeList()
and clc_dl_ModifyPayload(), is used to de-allocate any extra memory
associated with a node's payload - but not the payload itself nor the
node. (clc_dl_FreeNode() or clc_dl_FreeList() takes care of that.) Its
prototype must take the form:
void cleanup(void *);
The single parameter is a pointer to a node's payload data.
For example, suppose a node's payload is a struct containing a member
called some_ptr which is a pointer to some dynamically allocated memory.
The node's cleanup function could free the memory pointed to by this
pointer like so:
void cleanup(void *payload)
{
struct foo *bar = payload;
free(bar->some_ptr);
}
IMPORTANT NOTE: users should not de-allocate the payload themselves.
This should be left to clc_dl_FreeNode().
Comparison functions:
---------------------
A comparison function, as used by clc_dl_FindFirst() and
clc_dl_FindNext(), compares one payload type and data with another. It
must have the following prototype:
int cmp(int, size_t, const void *, int, size_t, const void *);
The first three parameters represent the first node or key values used
to compare against the node payload represented by the last three
parameters. The int parameters represent the payload type. This is
useful in the case of a linked list that contains more than one type of
data. The comparison of data can be skipped if the types don't match.
The arguments passed to these parameters may simply be ignored if the
linked list only contains one type of data. The size_t parameters
represent the size of the data. The const void * parameters are pointers
to the data to be compared. The function must return 0 to indicate that
the two data items are equal, < 0 to indicate that the first data item
(or key) is less than the second or > 0 to indicate that the first data
item (or key) is greater than the second.
For example, suppose you have a linked list containing strings, and
you want to search for a particular string in the list. The comparison
function passed to clc_dl_FindFirst() might look something like this:
int cmp(int keytype, size_t keysize, const void *keydata,
int nodetype, size_t nodesize, const void *nodedata)
{
/* first, make sure the types match */
if(keytype != nodetype)
return 1;
/* no need to compare strings if sizes don't match
(makes this function more efficient) */
if(keysize != nodesize)
return 1;
/* compare the strings */
return strcmp(keydata, nodedata);
}
clc_dl_ForEach()'s second parameter:
------------------------------------
The second parameter of clc_dl_ForEach() is a pointer to a user
defined function that has the following format:
int func(clc_dl_node *node);
This function can be used for almost any purpose pertaining to a double
linked list node. Iteration can be stopped prematurely by returning
non-zero from this user supplied function, in which case the value
returned by this function will also be returned by clc_dl_ForEach().
Eample of use:
==============
Normal use of this module is easy. The following program demonstrates
how simple it is.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "clc_dl.h"
#define PAYLOAD_TYPE_STRING 0
int cmp(int keytype, size_t keysize, const void *keydata,
int nodetype, size_t nodesize, const void *nodedata)
{
/* first, make sure the types match */
if(keytype != nodetype)
return 1;
/* compare the strings */
return strcmp(keydata, nodedata);
}
/* a function to be passed to clc_dl_ForEach() to print the list */
int printnode(clc_dl_node *node)
{
char buf[10];
if(0 > printf("%s ", clc_dl_Payload(node, buf)))
return EOF;
else
return 0;
}
int main(void)
{
char *s[] = {"foo", "bar", "baz", "plonk", "baz", "bar", "foo",};
clc_dl_node *node;
clc_dl_list *list;
clc_dl_search_data *srch;
int i;
char buf[10];
/* first, create the linked list */
list = clc_dl_NewList();
if(!list)
{
fprintf(stderr, "Memory allocation error.\n");
return EXIT_FAILURE;
}
/* next, fill it with data */
for(i = 0; i < (sizeof s / sizeof *s); i++)
{
node = clc_dl_InsertData(list, CLC_DL_START, PAYLOAD_TYPE_STRING,
1 + strlen(s[i]), s[i], NULL);
if(!node)
{
clc_dl_FreeList(list);
fprintf(stderr, "Memory allocation error.\n");
return EXIT_FAILURE;
}
}
/* now that we have filled the list, we can traverse it using
clc_dl_ForEach() */
clc_dl_ForEach(list, printnode, CLC_DL_FORWARD);
putchar('\n');
/* searching for data is just as simple - say you want to search for
all nodes containing "baz" - first we need a search structure */
srch = clc_dl_NewSearch();
if(!srch)
{
clc_dl_FreeList(list);
fprintf(stderr, "Memory allocation error!\n");
return EXIT_FAILURE;
}
node = clc_dl_FindFirst(list, PAYLOAD_TYPE_STRING, 1 + strlen(s[2]),
s[2], cmp, CLC_DL_FORWARD, srch);
while(node)
{
/* we have the first matching node -
now we extract the payload data */
clc_dl_Payload(node, buf);
printf("%s ", buf);
/* find the next matching node */
node = clc_dl_FindNext(srch);
}
putchar('\n');
/* sorting the list is also easy - just use clc_dl_Sort() */
clc_dl_Sort(list, cmp);
clc_dl_ForEach(list, printnode, CLC_DL_FORWARD);
putchar('\n');
/* now we're done - we can clean up and quit */
clc_dl_FreeSearch(srch);
clc_dl_FreeList(list);
return 0;
}
Dig the sig!
_-/~~~~~~/\ |------ pha...@al... -------|
////| /^^\ |-----------------------------------------------|
||||||\ |()()|___ | name Peter Haywood | |
|||||||| | _---6|9- | alias Shaggy | Remove .NOSPAM to reply |
|||||||| |/ \_/| | alias Wolvaen | |
|||||||| | A | | alias HEY YOU! | |
|||||||| | (===/\\/ |-----------------------------------------------|
\||||/ /------\|/ | Dig my groovy web page! |
"""" " | http://alphalink.com.au.au/~phaywood/ |
- Aint I'm a Dawg! --|--------------- Shaggy was here! --------------|
(This sig best viewed with a fixed pitch font.)
|
|
From: Hallvard B F. <h.b...@us...> - 2003-03-28 18:32:16
|
Bj=F8rn Augestad writes:
>Hallvard B Furuseth wrote:
>> Anyway, shall I check it in? =20
> Yes.
Done.
I also made it handle size =3D=3D 1, since it took no extra object code.
Also, here are some fixes to the documentation.
NAME
clc_ultostr - convert an unsigned long integer to a string
SYNOPSIS
char *clc_ultostr(char *ptr, size_t size, unsigned long num
int base);
DESCRIPTION
The clc_ultostr() function converts the number NUM to a string, in
base BASE notation. BASE must be between 2 and 36 inclusive. SIZE
must be at least 1. To summarize it, this function does (nearly)
exactly the opposite of strtoul().
The output and a trailing '\0' is stored in a buffer pointed to by
PTR, whose total length is passed in SIZE. If SIZE is too small,
the result is truncated and only the least significant digits are
stored.
RETURN VALUE
clc_ultostr() returns 1 on success, or 0 if truncation happened.
EXAMPLE
unsigned char buf[12];
/* print 10101010 */
clc_ultostr_n(buf, sizeof(buf), 170, 2);
puts(buf);
/* print 1Y */
clc_ultostr_n(buf, sizeof(buf), 70, 36);
puts(buf);
--=20
Hallvard
|
|
From: <bo...@me...> - 2003-03-28 17:55:28
|
Hallvard B Furuseth wrote: > Bjørn Augestad writes: > Anyway, shall I check it in? Yes. We can always take CLC_FAST out later > if c.l.c doesn't like it. They'll love it. :-) -- boa libclc home: http://libclc.sourceforge.net |
|
From: <pha...@al...> - 2003-03-28 03:22:37
|
>On Sunday 23 March 2003 09:14 pm, Peter "Shaggy" Haywood wrote: >> From: Bryan Donlan <bd...@bd...> >> Subject: Re: [Libclc-developers] Introducing the double linked list >> interface > >> >How about FindPrev to walk the list backwards? >> >> That's what the dir member (of CLC_DL_SEARCH_DATA) is for. This indicates >> whether to search forward or backward, and is set by clc_dl_FIND_FIRST(). > >No, undoing FindNext. The lack of such a function defeats much of the purpose >of a doubly-linked list. You have to walk the entire list just to look at the >prior node. Oh, I see what you mean. Yes, I could write this. >> > What about removing arbitrar= >> >y=20 >> >nodes and replacing them during such a search? >> >> Huh? I don't understand. > >Walk through the list, and if some test is true, delete the current node and >continue to the next. I still don't understand. Why would one want to remove a node during a search? What good would that do? Or is that what you're asking, what happens when someone removes a node found with clc_dl_Find*() before calling clc_dl_FindNext()? Dig the sig! _-/~~~~~~/\ |------ pha...@al... -------| ////| /^^\ |-----------------------------------------------| ||||||\ |()()|___ | name Peter Haywood | | |||||||| | _---6|9- | alias Shaggy | Remove .NOSPAM to reply | |||||||| |/ \_/| | alias Wolvaen | | |||||||| | A | | alias HEY YOU! | | |||||||| | (===/\\/ |-----------------------------------------------| \||||/ /------\|/ | Dig my groovy web page! | """" " | http://alphalink.com.au.au/~phaywood/ | - Aint I'm a Dawg! --|--------------- Shaggy was here! --------------| (This sig best viewed with a fixed pitch font.) |
|
From: Hallvard B F. <h.b...@us...> - 2003-03-27 23:17:30
|
Bj=F8rn Augestad writes:
>Hallvard B Furuseth wrote:
>> Bj=F8rn Augestad writes:
>=20
>>>Speaking of optimizations, any opinions on code like this?
>>>
>>>int clc_ultostr(char *ptr, size_t size, unsigned long num, int base)
>>>{
>>> const char *sym =3D "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
>>> char* sp;
>>>
>>>#ifdef CLC_FAST
>>> if(base =3D=3D 2) { (...) return num =3D=3D 0; }
>>>#endif
>>> .... /* regular version goes here */
>>>}
>>=20
>>=20
>> Since the _whole_ base2 function is special-cased, I think it's better
>> to provide a separate base2 function. Then the library still gets
>> bigger like you say, but not the application using it.
>=20
> Hmm. A separate base2 function means that the user must call different
> functions depending on the speed/size tradeoff he's willing to make. We
> discussed the concept of CLC_FAST early in the project, where the
> intention of CLC_FAST was to allow for speedier implementations if the
> user/builder of libclc wanted that.
Sorry, I forgot about that. Yes, I think that may be a good idea if we
implement CLC_FAST. I'm not sure if CLC_FAST is a good idea though...
> I used base2 as an easy-to-implement example, pretty sure that if the
> idea catches on, others can provide optimizations for e.g. base 16.
Here is one which covers all power-of-2 bases.
In the case of base 2, it's 10-20% slower than hardcoded base 2 on
Solaris, I think that's acceptable.
BTW, your claim that CLC_FAST is 4 times as fast as without CLC_FAST
depends on how large NUM is. With NUM=3D0, this function is 15% faster,
with random NUM, 50% faster on Solaris.
Anyway, shall I check it in? We can always take CLC_FAST out later
if c.l.c doesn't like it.
int clc_ultostr(char *ptr, size_t size, unsigned long num, int base)
{
const char *sym =3D "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *sp;
clc_assert_not_null(clc_ultostr, ptr);
clc_assert_arg(clc_ultostr, size > 1);
clc_assert_arg(clc_ultostr, base >=3D 2 && base <=3D 36);
--size;
sp =3D ptr;
#ifdef CLC_FAST
if((base & (base-1)) =3D=3D 0) {
static const unsigned int log[] =3D { 1,2,3,0, 4,0,0,0, 5 };
unsigned int shift =3D log[base / 4];
unsigned int mask =3D base - 1U;
do {
*sp++ =3D sym[num & mask];
num >>=3D shift;
} while(num && --size);
}
else
#endif /* CLC_FAST */
{
do {
*sp++ =3D sym[num % base];
num /=3D base;
} while (num && --size);
}
*sp =3D '\0';
clc_memrev(ptr, sp-ptr);
return !num;
}
> What if we add clc_ltostr(), clc_lltostr(), clc_itostr() and
> clc_ulltostr() for other integer types?
Not clc_itostr() I hope. clc_ltostr() can handle that. As for
clc_{u}lltostr(), I guess that depends on whether or not we want to add
a bunch of long long functions when compiled with C99 compilers.
--=20
Hallvard
|
|
From: Hallvard B F. <h.b...@us...> - 2003-03-27 09:50:46
|
Here is a suggestion for a file format for documentation. Contributors should write this, though maybe the documentation manager(s) will clean the file up a little, and it will be used to generate the other formats. If accepted, I'll write a Perl program to process it. The overall documentation structure reflects Unix man pages, as in <http://libclc.sourceforge.net/documentation-policy.txt>. I've also added an initial NAME section. (Bertrand, are you there?:-) Comments welcome. An example first, since that's shorter than the format description. (CVS replaces $Id$ below with info about the file.) @comment $Id$ @comment Copyright 2003 Hallvard B. Furuseth <h.b...@us...> NAME clc_strblurg, clc_strglarp - fromp a string SYNOPSIS #include <clc_string.h> char *clc_strblurg(char *src); char *clc_strglarp(char *src); Link with: clc library DESCRIPTION These functions modify their arguments by fromping the string src. @break clc_strblurg() blurgifies the string first. @break clc_strglarp() glarps the string afterwards. RETURN VALUES The functions return src, or NULL at failure. ERROR CODES CLC_ENOFROMP The string could not be fromped. The resulting contents of src is undefined. CLC_ENOGLARP The string could not be glarped. src will contain the fromped but unglarped string. EXAMPLE /* Print a blurgified string using @manpage{printf} */ void printfromp(const char *str) { char *tmp = clc_strdup(str); if (tmp && clc_strblurg(tmp)) printf("Glarp: %s\n", tmp); free(tmp); } Format description: - A document consists of a series of paragraphs separated by blank lines. Whitespace at the end of lines are ignored. - Normal paragraphs are plain text to be filled and justified. - Lines starting with '@' <word> <whitespace> are single-line commands: @comment <text>... -- a comment-line, not written. Retained as a comment in some output filetypes, at the start of the paragraph. A comment may not contain '--' (because that mucks up HTML comments). @section <name> -- start a section (NAME, SYNOPSIS, etc). @subsection <name> -- start a subsection. @break/@br -- force a line break. @list ... @item <name> ... @end list -- list of items. Each item can be followed by paragraphs describing it. @fixed/@pre/@preformatted ... @end fixed/pre/preformatted -- print fixed font, and don't fill. @indent ... @end indent -- indent (but still fill/justify) contents. @manpage <name> or <name>(section) -- explicit reference to manpage. One may also write @manpage{...} or @fixed{...} in the middle of text. @fixed{} text should be short: it will not be broken with line breaks. Or should it be, at spaces? I'm not sure. - Various error checks are done: For example, all @items in the ERRORS section are checked to be CLC_E*, ERANGE or EDOM. - The special cases below let us avoid most of the above commands. Or are some of these too complex so it's simpler to always use commands? - Indented paragraphs are not filled or justified, and they are printed in a fixed-width font. 4 spaces of indentation are removed, or less if the whole paragraph is not indented that much. Thus, example code can be written just as it is by indenting it. - The paragraphs in the SYNOPSIS section are not filled or justified, since they contain C code. - A paragraph which consists of one line of uppercase words is taken to be a section header, e.g. NAME, DESCRIPTION, SEE ALSO and so on. - In the ERRORS section, if the first line of a paragraph is simply one all-uppercase word (which may have digits and underscores), it is considered to be an @item line. Also, if ERRORS has @items but not @list, the whole ERRORS section from the first @item and onwards is wrapped in @list ... @end list. - In the SEE ALSO section, single comma-separated words are translated to manpage references if they either start with "clc_" or are ISO C (1989) function names. If they are neither, they produce a warning. Other details: - Preformatted lines should be 58 or fewer characters long, or less still if they are inside already-indented text (@indent or @list). [Or should this be less still for the sake of HTML pages?] - Don't indent with TABs, use SPACEs. Some contributors will be using tab-width 4, others will be using 8, so TABs for indentation would cause havoc. - Please start each sentence on a new line. Troff notices this and puts extra space after such sentences ending with '.', '!' or '?'. I'll make a word starting with an uppercase letter except CLC_E* and E*, which follows a letter, a ',', '!' or '?', and a space, to also be taken to start a sentence. - Picky people can write opening single quotes as "`", not "'", like troff and nroff want. We can't do that with quotes that should be the C quoted char "'", so a program can't convert "'"s to "`"s. - 8-bit characters are taken to be latin-1 characters. Questions: - Nroff and troff retain multiple spaces typed into a paragraph, though troff's space is thinner than most other characters. Should we retain this feature, or transform multiple spaces to single ones in filled paragraphs like HTML does? - If a line in an otherwise unindented paragraph starts with whitespace, nroff and troff retains that whitespace at the beginning of a new line. However, they still break the line if it gets too long or fill it from the next line if too short. I'm not sure what to do about this feature. We could retain it, but my suggestion is to report such paragraphs as an error -- probably there should be a blank line between the indented and the unindented part. OK? - There are two basic dashes: minus and hyphen. Hyphen may be shorter. I suggest all minuses are treated as minus, except that it is a hyphen if there is a letter or digit on each side. Thus, one should write 'size - strlen(foo)', not 'size-strlen(foo)'. OK? - Should manpage references in text, html and PostScript formats use the Unix format 'strcmp(3)', or just 'strcmp'? -- Hallvard |
|
From: <bo...@me...> - 2003-03-26 16:58:09
|
Hallvard B Furuseth wrote: > Bjørn Augestad writes: > >>Hallvard B Furuseth wrote: >> >>>I think we should drop the 'clc_' prefix from the .c filenames and maybe >>>the internal .h files (the ones that are not installed) in the future. >> >>What do we gain? > > > Sorry, that was a rather truncated message. > What I meant to say was, there are filesystems with uncomfortable > limits for filenames, like 8.3 characters or max 14 characters. > So we should try to keep filenames short. Does anyone on the list even know of a C developer working on platform with a 8.3 filesystem only? I don't... We cannot make everyone happy, and I'm not going to have lousy filenames for 99% of us to support 1% working on archaic or very special platforms. They won't use libclc anyway. -- boa libclc home: http://libclc.sourceforge.net |
|
From: Hallvard B F. <h.b...@us...> - 2003-03-26 16:20:22
|
Bj=F8rn Augestad writes: > [typedefs to pointers] > Let's continue to disagree for a while, shall we? ;-) OK. Until the news discussion... >>> Does the design [of iterators] easily create mem leaks? >>=20 >>=20 >> Maybe. It would be safer with >> struct clc_iterator iter; >> clc_iterator_init(&iter, ...); >> because then many iterators would not need to be freed at all. >=20 > Can't do that with an ADT. It has to be allocated since it is an=20 > incomplete type. It doesn't have to be an incomplete type just because users shouldn't access it. Look at various FILE implementations, for example. We could just document that the struct implementation is subject to change and should not be accessed directly. --=20 Hallvard |
|
From: <bo...@me...> - 2003-03-26 16:11:57
|
Hallvard B Furuseth wrote: > Bjørn Augestad writes: > >>Hallvard B Furuseth wrote: >> >>>clc_stl.h says: >>> >>> typedef struct clc_list_tag* clc_list; >>> typedef struct clc_iterator_tag* clc_iterator; >>> >>>I think typedefs to pointers like this is a bad idea. >>>(...) I'd rather see >>> >>> typedef struct clc_list_tag clc_list; >>> typedef struct clc_iterator_tag clc_iterator; >>> >>>(...) >> >>Thanks for the feedback. The general concensus on c.l.c seems to be that >>it's OK to typedef the pointer if no struct members are available >>outside the implementation. > > > That's not what c.l.c said last time. They said one should normally not > typedef a struct at all, but it's OK if no struct members are available > outside the implementation. While typedefs to pointers are evil. See: > > http://groups.google.com/groups?selm=newscache%2405mrbh%24jt1%241%40tomato.pcug.org.au > http://groups.google.com/groups?selm=b553pt%245f8%241%40sunnews.cern.ch I must have misread those the last time, possibly mixing in memories from the clc_bitset discussion where this issue was discussed as well. Memory can be quite selective... Let's continue to disagree for a while, shall we? ;-) >>We can compromise by dropping the _tag suffix, >> typedef struct foo* foo; > > > Absolutely not! If we have a struct tag and a typedef with the same > name, they should be the same type. That was a joke. :-) >>Does the design easily create mem leaks? > > > Maybe. It would be safer with > struct clc_iterator iter; > clc_iterator_init(&iter, ...); > because then many iterators would not need to be freed at all. Can't do that with an ADT. It has to be allocated since it is an incomplete type. -- boa libclc home: http://libclc.sourceforge.net |
|
From: Hallvard B F. <h.b...@us...> - 2003-03-26 15:56:06
|
Bj=F8rn Augestad writes: >Hallvard B Furuseth wrote: >> I think we should drop the 'clc_' prefix from the .c filenames and maybe >> the internal .h files (the ones that are not installed) in the future. >=20 > What do we gain? Sorry, that was a rather truncated message. What I meant to say was, there are filesystems with uncomfortable limits for filenames, like 8.3 characters or max 14 characters. So we should try to keep filenames short. > If a standalone function is named clc_foo, I hope to see > clc_foo.c > clc_foo.man > clc_foo.html Yes, the manpages must have full names. However, for unfortunate systems that don't support man or html there might be a single clc.txt file which contains the documentation from all the clc*.man pages. > We can of course have clc_strdup.man even if we have strdup.c, but that=20 > makes it harder to script things. Not if it's consistently done. --=20 Hallvard |
|
From: <bo...@me...> - 2003-03-26 15:50:28
|
Hallvard B Furuseth wrote: > I think we should drop the 'clc_' prefix from the .c filenames and maybe > the internal .h files (the ones that are not installed) in the future. > What do we gain? If a standalone function is named clc_foo, I hope to see clc_foo.c clc_foo.man clc_foo.html clc_foo.o ... For e.g. clc_strdup, we may get problems since we implement a function which frequently already exists. So a man page must be named clc_strdup.man (or whatever extension is proper). We can of course have clc_strdup.man even if we have strdup.c, but that makes it harder to script things. Just my 0.02 NOK. -- boa libclc home: http://libclc.sourceforge.net |
|
From: Jan E. <je...@li...> - 2003-03-26 12:00:39
|
>How about an saprintf? > >size_t saprintf(char *buf, const char *formatstr, void **args); >size_t sanprintf(char *buf, size_t size, const char *formatstr, void **args); Such functions already exist (in some other project,package,et al), as "asnprintf" (not sanprintf): http://www.ijs.si/software/snprintf/ - Jan Engelhardt |
|
From: Jan E. <je...@li...> - 2003-03-26 11:58:50
|
>A lot of libclc files will contain small functions, so I if we put a >huge copyright notice at the top of each, more than half of the released >libclc source text may be copyright notices... > >Can we get away with just this notice at the top of files? That's what >OpenLDAP does. > > Copyright <year> <Author> > COPYING RESTRICTIONS APPLY, see COPYRIGHT.txt file Why not? I do so in all my files. - Jan Engelhardt |
|
From: Hallvard B F. <h.b...@us...> - 2003-03-26 10:46:43
|
I think we should drop the 'clc_' prefix from the .c filenames and maybe the internal .h files (the ones that are not installed) in the future. -- Hallvard |
|
From: Hallvard B F. <h.b...@us...> - 2003-03-26 10:28:48
|
Bj=F8rn Augestad writes: >Hallvard B Furuseth wrote: >>=20 >> clc_stl.h says: >>=20 >> typedef struct clc_list_tag* clc_list; >> typedef struct clc_iterator_tag* clc_iterator; >>=20 >> I think typedefs to pointers like this is a bad idea. >> (...) I'd rather see >>=20 >> typedef struct clc_list_tag clc_list; >> typedef struct clc_iterator_tag clc_iterator; >>=20 >> (...) >=20 > Thanks for the feedback. The general concensus on c.l.c seems to be that= =20 > it's OK to typedef the pointer if no struct members are available=20 > outside the implementation. That's not what c.l.c said last time. They said one should normally not typedef a struct at all, but it's OK if no struct members are available outside the implementation. While typedefs to pointers are evil. See: http://groups.google.com/groups?selm=3Dnewscache%2405mrbh%24jt1%241%40tomat= o.pcug.org.au http://groups.google.com/groups?selm=3Db553pt%245f8%241%40sunnews.cern.ch > That's my opinion as well. >=20 > We can compromise by dropping the _tag suffix, > typedef struct foo* foo; Absolutely not! If we have a struct tag and a typedef with the same name, they should be the same type. > How about the iterator concept? Do you think it can be applied to all > the containers we want to add? Personally I expect I'll think it's overkill, but let me look at the actual containers and their built-in ways to iterate first... > Performance issues? That's another thing, yes. A built-in list walker need only take the previous object as an argument and return the next, or vice versa. > Will it be too complex to use for beginners? Don't think so. > Does the design easily create mem leaks? Maybe. It would be safer with struct clc_iterator iter; clc_iterator_init(&iter, ...); because then many iterators would not need to be freed at all. --=20 Hallvard |
|
From: <bo...@me...> - 2003-03-25 20:10:08
|
Regis has been working hard and has come up with a new clc_bitset.
Regis' version is much more complete than the current, so this may be a
winner. :-)
The excellent documentation Regis provided has been moved to a separate
file, libclc/src/bitset/clc_bitset.dox. That file is available in CVS
for review.
Here is the implementation, please comment.
----------------------------------------------------------
#include "clc_assert.h"
#include "clc_bitset.h"
/** \brief The chosen word size for the buffer of bits.
*
* I would choose unsigned integer instead of unsigned char
* if I knew how to get the number of value bits in an unsigned
* at compile time.
*/
typedef unsigned char clc_bitset_word;
static const size_t nbytes_per_word = sizeof(clc_bitset_word);
static const size_t nbits_per_word = CHAR_BIT;
static const clc_bitset_word mask_all = ~0;
static const clc_bitset_word comask_all = 0;
/** \brief The internal struct that implements the ADT clc_bitset.
*
* The bitset holds 'nbits' bits (nbits > 0).
* The bits are packed in unsigned values of type clc_bitset_word.
* There are 'nwords' such words that hold the 'nbits' bits.
* The 'nwords' words are stored in an array pointed by 'words'.
* Since only some of the bits of the last are generally used,
* 'nlast_bits' is the number of used bits in words[nword-1].
* The unused bits should remain zero.
*/
struct clc_bitset_tag {
/** number of words in the array 'words[]'. */
size_t nwords;
/** number of bits in the bitset. */
size_t nbits;
/** number of used bits in the last word. */
size_t nlast_bits;
/** pointer to the array of words. */
clc_bitset_word *words;
};
static size_t bit_index(size_t i)
{
return i / nbits_per_word;
}
static size_t bit_offset(size_t i)
{
return i % nbits_per_word;
}
static void bit_pos(size_t * idx, size_t * off, size_t i)
{
clc_assert_not_null(bit_pos, idx);
clc_assert_not_null(bit_pos, off);
*idx = i / nbits_per_word;
*off = i % nbits_per_word;
}
static clc_bitset_word mask_one(size_t i)
{
clc_assert_arg(mask_one, i < nbits_per_word);
return (1 << i);
}
static clc_bitset_word comask_one(size_t i)
{
clc_assert_arg(comask_one, i < nbits_per_word);
return ~(1 << i);
}
static clc_bitset_word mask_first(size_t n)
{
clc_assert_arg(mask_first, n <= nbits_per_word);
return ((1 << n) - 1);
}
static clc_bitset_word comask_first(size_t n)
{
clc_assert_arg(comask_first, n <= nbits_per_word);
return ~((1 << n) - 1);
}
static clc_bitset_word mask_range(size_t i, size_t j)
{
clc_assert_arg(mask_range, i <= j);
clc_assert_arg(mask_range, i < nbits_per_word);
clc_assert_arg(mask_range, i <= nbits_per_word);
return (((1 << j) - 1) ^ ((1 << i) - 1));
}
static clc_bitset_word comask_range(size_t i, size_t j)
{
clc_assert_arg(comask_range, i <= j);
clc_assert_arg(comask_range, i < nbits_per_word);
clc_assert_arg(comask_range, i <= nbits_per_word);
return ~(((1 << j) - 1) ^ ((1 << i) - 1));
}
static size_t first_one(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(first_one, w != 0);
for (off = 0; (w & 1) != 1; off++)
w >>= 1;
return off;
}
static size_t first_zero(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(first_zero, w != mask_all);
for (off = 0; (w & 1) != 0; off++)
w >>= 1;
return off;
}
static size_t last_one(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(last_one, w != 0);
for (off = 0; w != 0; off++)
w >>= 1;
return off - 1;
}
static size_t last_zero(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(last_zero, w != mask_all);
w = ~w;
for (off = 0; w != 0; off++)
w >>= 1;
return off - 1;
}
static clc_bitset unary_result(clc_bitset r, clc_bitset b1,
int init_zero)
{
clc_assert_not_null(unary_result, b1);
clc_assert_arg(unary_result, r == NULL || r->nbits == b1->nbits);
if(r == NULL)
return clc_bitset_new(b1->nbits, init_zero);
return r;
}
static clc_bitset binary_result(clc_bitset r, clc_bitset b1,
clc_bitset b2, int init_zero)
{
clc_assert_not_null(binary_result, b1 != NULL);
clc_assert_not_null(binary_result, b2 != NULL);
clc_assert_arg(binary_result, b1->nbits == b2->nbits);
clc_assert_arg(binary_result, r == NULL || r->nbits == b1->nbits);
if(r == NULL)
return clc_bitset_new(b1->nbits, init_zero);
return r;
}
clc_bitset clc_bitset_new(size_t nbits, int init_to_zero)
{
clc_bitset b = malloc(sizeof *b);
if(!b)
return NULL;
b->nbits = nbits;
bit_pos(&b->nwords, &b->nlast_bits, nbits);
if(b->nlast_bits != 0)
b->nwords++;
else
b->nlast_bits = nbits_per_word;
b->words = malloc(b->nwords * nbytes_per_word);
if(!b->words) {
clc_bitset_delete(b);
return NULL;
}
if(init_to_zero)
clc_bitset_clear_all(b);
return b;
}
void clc_bitset_delete(clc_bitset b)
{
if(b) {
free(b->words);
free(b);
}
}
clc_bitset clc_bitset_copy(clc_bitset copy, clc_bitset b)
{
size_t idx;
if(!(copy = unary_result(copy, b, 0)))
return NULL;
for (idx = 0; idx < b->nwords; idx++)
copy->words[idx] = b->words[idx];
return copy;
}
size_t clc_bitset_size(clc_bitset b)
{
clc_assert_not_null(clc_bitet_size, b);
return b->nbits;
}
size_t clc_bitset_count_ones(clc_bitset b)
{
size_t idx, nbits = 0;
clc_bitset_word word;
clc_assert_not_null(clc_bitset_count_ones, b);
/* the last word does not need any special treatment
*/
for (idx = 0; idx < b->nwords; idx++) {
word = b->words[idx];
while (word) {
nbits += word & 1;
word >>= 1;
}
}
return nbits;
}
size_t clc_bitset_first_one(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_first_one, b);
/* the last word does not need any special treatment
*/
for (idx = 0; idx < b->nwords; idx++)
if(b->words[idx])
return idx * nbits_per_word + first_one(b->words[idx]);
return b->nbits;
}
size_t clc_bitset_last_one(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_last_one, b);
/* the last word does not need any special treatment
* the first word is a specil case since the loop is
* downward to zero and size_t is of unsigned type
*/
for (idx = b->nwords - 1; idx != 0; idx--)
if(b->words[idx])
return idx * nbits_per_word + last_one(b->words[idx]);
return b->words[0] == 0 ? b->nbits : last_one(b->words[0]);
}
size_t clc_bitset_first_zero(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_first_zero, b);
/* though the last word does not need any special treatment
* with the convention to return nbits, we treat it separately
* to emphazise that a special treatment would be required if this
* convention changed.
*/
for (idx = 0; idx < b->nwords - 1; idx++)
if(b->words[idx] != mask_all)
return idx * nbits_per_word + first_zero(b->words[idx]);
return b->words[idx] == mask_first(b->nlast_bits) ?
b->nbits : first_zero(b->words[idx]);
}
size_t clc_bitset_last_zero(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_last_zero, b);
/* the unused zeroes of the last word should be ignored
*/
if(b->words[b->nwords - 1] != mask_first(b->nlast_bits))
return (b->nwords - 1) * nbits_per_word
+ last_zero(b->words[b->nwords - 1] |
comask_first(b->nlast_bits));
if(b->nwords == 1)
return b->nbits;
for (idx = b->nwords - 2; idx != 0; idx--)
if(b->words[idx] != mask_all)
return idx * nbits_per_word + last_zero(b->words[idx]);
return b->words[0] == mask_all ? b->nbits : last_zero(b->words[0]);
}
void clc_bitset_set(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_set, b);
clc_assert_arg(clc_bitset_set, i < b->nbits);
b->words[bit_index(i)] |= mask_one(bit_offset(i));
}
void clc_bitset_clear(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_set, b);
clc_assert_arg(clc_bitset_set, i < b->nbits);
b->words[bit_index(i)] &= comask_one(bit_offset(i));
}
void clc_bitset_toggle(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_toggle, b);
clc_assert_arg(clc_bitset_toggle, i < b->nbits);
b->words[bit_index(i)] ^= mask_one(bit_offset(i));
}
void clc_bitset_assign(clc_bitset b, size_t i, int value)
{
clc_assert_not_null(clc_bitset_assign, b);
clc_assert_arg(clc_bitset_assign, i < b->nbits);
if(value)
clc_bitset_set(b, i);
else
clc_bitset_clear(b, i);
}
int clc_bitset_is_set(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_is_set, b);
clc_assert_arg(clc_bitset_is_set, i < b->nbits);
return b->words[bit_index(i)] & mask_one(bit_offset(i));
}
int clc_bitset_and(clc_bitset b1, clc_bitset b2, size_t i)
{
size_t off_i, idx_i;
clc_assert_not_null(clc_bitset_and, b1 != NULL);
clc_assert_not_null(clc_bitset_and, b2 != NULL);
clc_assert_arg(clc_bitset_and, b1->nbits == b2->nbits);
clc_assert_arg(clc_bitset_and, i < b1->nbits);
bit_pos(&off_i, &idx_i, i);
return ((b1->words[idx_i] & b2->words[idx_i]) >> off_i) & 1;
}
int clc_bitset_or(clc_bitset b1, clc_bitset b2, size_t i)
{
size_t off_i, idx_i;
clc_assert_not_null(clc_bitset_or, b1 != NULL);
clc_assert_not_null(clc_bitset_or, b2 != NULL);
clc_assert_arg(clc_bitset_or, b1->nbits == b2->nbits);
clc_assert_arg(clc_bitset_or, i < b1->nbits);
bit_pos(&off_i, &idx_i, i);
return ((b1->words[idx_i] | b2->words[idx_i]) >> off_i) & 1;
}
int clc_bitset_xor(clc_bitset b1, clc_bitset b2, size_t i)
{
size_t off_i, idx_i;
clc_assert_not_null(clc_bitset_xor, b1 != NULL);
clc_assert_not_null(clc_bitset_xor, b2 != NULL);
clc_assert_arg(clc_bitset_xor, b1->nbits == b2->nbits);
clc_assert_arg(clc_bitset_xor, i < b1->nbits);
bit_pos(&off_i, &idx_i, i);
return ((b1->words[idx_i] ^ b2->words[idx_i]) >> off_i) & 1;
}
void clc_bitset_clear_all(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_clear_all, b);
/* the last word does not require any special treatment
*/
for (idx = 0; idx < b->nwords; idx++)
b->words[idx] = comask_all;
}
void clc_bitset_set_all(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_set_all, b);
/* the unused bits of the last word should be left zero
*/
for (idx = 0; idx < b->nwords - 1; idx++)
b->words[idx] = mask_all;
b->words[idx] = mask_first(b->nlast_bits);
}
void clc_bitset_toggle_all(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_toggle_all, b);
/* the unused bits of the last word should be left zero
*/
for (idx = 0; idx < b->nwords - 1; idx++)
b->words[idx] = ~b->words[idx];
b->words[idx] ^= mask_first(b->nlast_bits);
}
void clc_bitset_assign_all(clc_bitset b, int value)
{
clc_assert_not_null(clc_bitset_assign_all, b);
if(value)
clc_bitset_set_all(b);
else
clc_bitset_clear_all(b);
}
int clc_bitset_is_all_set(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_is_all_set, b);
/* the unused bits of the last word should be ignored
*/
for (idx = 0; idx < b->nwords - 1; idx++)
if(b->words[idx] != mask_all)
return 0;
return (mask_first(b->nlast_bits) & b->words[idx])
== mask_first(b->nlast_bits);
}
int clc_bitset_is_all_clear(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_is_all_clear, b);
/* the last word does not require any special treatment
*/
for (idx = 0; idx < b->nwords; idx++)
if(b->words[idx] != comask_all)
return 0;
return 1;
}
clc_bitset clc_bitset_or_all(clc_bitset r, clc_bitset b1, clc_bitset b2)
{
size_t idx;
if(!(r = binary_result(r, b1, b2, 0)))
return NULL;
/* the last word does not require any special treatment
*/
for (idx = 0; idx < r->nwords; idx++)
r->words[idx] = b1->words[idx] | b2->words[idx];
return r;
}
clc_bitset clc_bitset_and_all(clc_bitset r,
clc_bitset b1, clc_bitset b2)
{
size_t idx;
if(!(r = binary_result(r, b1, b2, 0)))
return NULL;
/* the last word does not require any special treatment
*/
for (idx = 0; idx < r->nwords; idx++)
r->words[idx] = b1->words[idx] & b2->words[idx];
return r;
}
clc_bitset clc_bitset_xor_all(clc_bitset r,
clc_bitset b1, clc_bitset b2)
{
size_t idx;
if(!(r = binary_result(r, b1, b2, 0)))
return NULL;
/* the last word does not require any special treatment
*/
for (idx = 0; idx < r->nwords; idx++)
r->words[idx] = b1->words[idx] ^ b2->words[idx];
return r;
}
clc_bitset clc_bitset_range(clc_bitset r,
clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_range, b);
clc_assert_arg(clc_bitset_range, i <= j);
clc_assert_arg(clc_bitset_range, i < b->nbits);
clc_assert_arg(clc_bitset_range, j <= b->nbits);
if(!(r = unary_result(r, b, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] =
(r->words[idx_i] & comask_range(off_i, off_j)) |
(b->words[idx_i] & mask_range(off_i, off_j));
return r;
}
r->words[idx_i] =
(r->words[idx_i] & mask_first(off_i)) |
(b->words[idx_i] & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b->words[idx];
if(idx_j < b->nwords)
r->words[idx_j] =
(r->words[idx_j] & comask_first(off_j)) |
(b->words[idx_j] & mask_first(off_j));
return r;
}
void clc_bitset_set_range(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_set_range, b);
clc_assert_arg(clc_bitset_set_range, i <= j);
clc_assert_arg(clc_bitset_set_range, i < b->nbits);
clc_assert_arg(clc_bitset_set_range, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
b->words[idx_i] |= mask_range(off_i, off_j);
return;
}
b->words[idx_i] |= comask_first(off_i);
for (idx = idx_i + 1; idx < idx_j; idx++)
b->words[idx] = mask_all;
if(idx_j < b->nwords)
b->words[idx_j] |= mask_first(off_j);
}
void clc_bitset_clear_range(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_clear_range, b);
clc_assert_arg(clc_bitset_clear_range, i <= j);
clc_assert_arg(clc_bitset_clear_range, i < b->nbits);
clc_assert_arg(clc_bitset_clear_range, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
b->words[idx_i] &= comask_range(off_i, off_j);
return;
}
b->words[idx_i] &= mask_first(off_i);
for (idx = idx_i + 1; idx < idx_j; idx++)
b->words[idx] = comask_all;
if(idx_j < b->nwords)
b->words[idx_j] &= comask_first(off_j);
}
void clc_bitset_toggle_range(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_toggle_range, b);
clc_assert_arg(clc_bitset_toggle_range, i <= j);
clc_assert_arg(clc_bitset_toggle_range, i < b->nbits);
clc_assert_arg(clc_bitset_toggle_range, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
b->words[idx_i] ^= mask_range(off_i, off_j);
return;
}
b->words[idx_i] ^= comask_first(off_i);
for (idx = idx_i + 1; idx < idx_j; idx++)
b->words[idx] ^= mask_all;
if(idx_j < b->nwords)
b->words[idx_j] ^= mask_first(off_j);
}
void clc_bitset_assign_range(clc_bitset b, size_t i, size_t j,
int value)
{
if(value)
clc_bitset_set_range(b, i, j);
else
clc_bitset_clear_range(b, i, j);
}
int clc_bitset_range_is_set(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_range_is_set, b);
clc_assert_arg(clc_bitset_range_is_set, i <= j);
clc_assert_arg(clc_bitset_range_is_set, i < b->nbits);
clc_assert_arg(clc_bitset_range_is_set, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j)
return (mask_range(off_i, off_j) & b->words[idx_i])
== mask_range(off_i, off_j);
if((comask_first(off_i) & b->words[idx_i])
!= comask_first(off_i))
return 0;
for (idx = idx_i + 1; idx < idx_j; idx++)
if(b->words[idx] != mask_all)
return 0;
return idx_j == b->nwords ||
(mask_first(idx_j) & b->words[idx_j]) == mask_first(idx_j);
}
int clc_bitset_range_is_clear(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_range_is_clear, b);
clc_assert_arg(clc_bitset_range_is_clear, i <= j);
clc_assert_arg(clc_bitset_range_is_clear, i < b->nbits);
clc_assert_arg(clc_bitset_range_is_clear, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j)
return (b->words[idx_i] & mask_range(off_i, off_j))
== comask_all;
if((b->words[idx_i] & comask_first(off_i)) != comask_all)
return 0;
for (idx = idx_i + 1; idx < idx_j; idx++)
if(b->words[idx] != comask_all)
return 0;
return idx_j == b->nwords ||
(b->words[idx_j] & mask_first(idx_j)) == comask_all;
}
clc_bitset clc_bitset_or_range(clc_bitset r,
clc_bitset b1,
clc_bitset b2, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
if(!(r = binary_result(r, b1, b2, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] = (r->words[idx_i] &
comask_range(off_i, off_j)) |
((b1->words[idx_i] | b2->words[idx_i]) &
mask_range(off_i, off_j));
return r;
}
r->words[idx_i] = (r->words[idx_i] & mask_first(off_i)) |
((b1->words[idx_i] | b2->words[idx_i]) & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b1->words[idx_i] | b2->words[idx_i];
if(idx_j < r->nwords)
r->words[idx_j] = (r->words[idx_j] & comask_first(off_j)) |
((b1->words[idx_j] | b2->words[idx_j]) & mask_first(off_j));
return r;
}
clc_bitset clc_bitset_and_range(clc_bitset r,
clc_bitset b1,
clc_bitset b2, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
if(!(r = binary_result(r, b1, b2, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] = (r->words[idx_i] &
comask_range(off_i, off_j)) |
((b1->words[idx_i] & b2->words[idx_i]) &
mask_range(off_i, off_j));
return r;
}
r->words[idx_i] = (r->words[idx_i] & mask_first(off_i)) |
((b1->words[idx_i] & b2->words[idx_i]) & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b1->words[idx_i] & b2->words[idx_i];
if(idx_j < r->nwords)
r->words[idx_j] = (r->words[idx_j] & comask_first(off_j)) |
((b1->words[idx_j] & b2->words[idx_j]) & mask_first(off_j));
return r;
}
clc_bitset clc_bitset_xor_range(clc_bitset r,
clc_bitset b1,
clc_bitset b2, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
if(!(r = binary_result(r, b1, b2, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] = (r->words[idx_i] &
comask_range(off_i, off_j)) |
((b1->words[idx_i] ^ b2->words[idx_i]) &
mask_range(off_i, off_j));
return r;
}
r->words[idx_i] = (r->words[idx_i] & mask_first(off_i)) |
((b1->words[idx_i] ^ b2->words[idx_i]) & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b1->words[idx_i] ^ b2->words[idx_i];
if(idx_j < r->nwords)
r->words[idx_j] = (r->words[idx_j] & comask_first(off_j)) |
((b1->words[idx_j] ^ b2->words[idx_j]) & mask_first(off_j));
return r;
}
void clc_bitset_print(clc_bitset b, size_t block_length, char sep,
FILE * file)
{
size_t idx, off, n, count = 0;
clc_bitset_word word;
for (idx = n = 0; idx < b->nwords; idx++) {
size_t nused_bits = (idx != b->nwords - 1) ?
nbits_per_word : b->nlast_bits;
word = b->words[idx];
for (off = 0; off < nused_bits; off++, n++) {
fprintf(file, "%c", (word & 1) ? '1' : '0');
if(++count == block_length && n != b->nbits) {
fprintf(file, "%c", sep);
count = 0;
}
word >>= 1;
}
}
printf("\n");
}
--
boa
libclc home: http://libclc.sourceforge.net
|
|
From: <bo...@me...> - 2003-03-25 19:13:34
|
Hallvard B Furuseth wrote: > Bjørn Augestad writes: > >>Attached is a file containing a list adt as well as an iterator adt. > > > clc_stl.h says: > > typedef struct clc_list_tag* clc_list; > typedef struct clc_iterator_tag* clc_iterator; > > I think typedefs to pointers like this is a bad idea. It makes > calls to functions like these: > > int clc_list_push_back(clc_list lst, void* data); > > look like they are sending a list argument which is only read by the > function, while the function is actually updating through the 'hidden' > pointer. > > I'd rather see > > typedef struct clc_list_tag clc_list; > typedef struct clc_iterator_tag clc_iterator; > > and > > int clc_list_push_back(clc_list *lst, void* data); Thanks for the feedback. The general concensus on c.l.c seems to be that it's OK to typedef the pointer if no struct members are available outside the implementation. That's my opinion as well. We can compromise by dropping the _tag suffix, typedef struct foo* foo; but then C++ gets *really* confused. ;-) How about the iterator concept? Do you think it can be applied to all the containers we want to add? Performance issues? Will it be too complex to use for beginners? Does the design easily create mem leaks? -- boa libclc home: http://libclc.sourceforge.net |
|
From: Hallvard B F. <h.b...@us...> - 2003-03-25 17:29:50
|
Bj=F8rn Augestad writes: > Attached is a file containing a list adt as well as an iterator adt. clc_stl.h says: typedef struct clc_list_tag* clc_list; typedef struct clc_iterator_tag* clc_iterator; I think typedefs to pointers like this is a bad idea. It makes calls to functions like these: int clc_list_push_back(clc_list lst, void* data); look like they are sending a list argument which is only read by the function, while the function is actually updating through the 'hidden' pointer. I'd rather see typedef struct clc_list_tag clc_list; typedef struct clc_iterator_tag clc_iterator; and int clc_list_push_back(clc_list *lst, void* data); --=20 Hallvard |