/prog/, I've been working on a C library with basic data structures and useful functions, and have implemented things like doubly-linked lists and vectors and so on. Now I'm working on Unicode-based string support. Here's my issue.
I've implemented type agnosticism on the vector type using void pointers (not preprocessor macros), so I want to use the vector type to represent a string. Each Unicode codepoint is an int32_t. Of course, I don't want to have to allocate four bytes on the heap for each codepoint, then point to that from each vector element; that's utterly stupid. On the other hand, doing typecasts to shove an integer in the void * type is kludgy and works very poorly, often requiring double explicit casts; once to expand/shrink the type's size, then once more to explicitly cast to a pointer or back.
How can I solve my issues and use my vector type for strings?
/* The implementation is left as an exercise to the reader. */
typedef struct {
size_t element_size;
size_t allocated_space;
size_t n;
void* data;
} vector;
>>7
Wouldn't that require a function call just to fetch/store values?
Name:
Anonymous2011-09-16 6:39
>>7
Also, that'd make using a vector for actual pointers a pain in the ass, and need casts all over the fucking place.
Name:
Anonymous2011-09-16 6:38
>>8
No. The reader knowns the real type of what is pointed by data and use it directly with casting.
Name:
Anonymous2011-09-16 6:40
>>10
My whole question revolves around finding a way to avoid excessive casting. Could you provide me with a relevant solution?
Name:
Anonymous2011-09-16 6:44
>>11
My solution is VALID ANSI C89 and one of the best. If the typecast really annoys you, you can #define VEC(x, type, i) (((type*) (x)->data)[i]).
Name:
Anonymous2011-09-16 6:46
>>12
Calling yourself the best doesn't provide credibility. Also, my entire library is valid ANSI C89, save for the requirement of C99's stdint.h, so your 'achievement' isn't all that extraordinary. Also, preprocessor macros are for faggots.
Also, preprocessor macros are for faggots. No, they aren't. That's what Bjarne Stroustrup wants you to believe.
If you absolutely want to avoid reader typecasting, the only solutions I see are:
- Switch to C++ and use templates;
- Implement dynamic typing, which will be slow as fuck;
- Use kludges such as the one you described in >>1.
Perhaps a better programmer will find others.
Name:
Anonymous2011-09-16 6:52
Also: what should be the default type for my generic data structures' payload?
>>16 Nope. This is a C library.
Then enjoy your AIDS.
I mean, it is fucking ridiculous, isn't it? You have found one of the cases that perfectly illustrate why C++ is hands down better than C. Or, rather, the case found you. Yet through a miracle of cognitive alchemy you manage to warp your vision of the situation to completely turn it inside-out, so that you can respond to the only possible sane advice with a quietly smug "this is a C library". Mind boggles.
/**
* The pointer to the memory used for the vector. Integer values of the
* same size and signedness as a void pointer can also be stored here,
* but the void pointer data type varies between platforms, so this is not
* good practice except under controlled, memory-tight conditions.
*/
void **d;
/**
* The number of elements memory has been allocated for.
*/
intmax_t a;
/**
* The number of elements currently stored.
*/
intmax_t l;
};
/**
* A vector should be passed around by a pointer to its structure.
*/
typedef struct gvector_struct *gvector;
/**
* Allocate a new vector on the heap.
* \return the new vector
*/
gvector gvector_alloc();
/**
* Double the memory allocated to a vector.
* \param v the vector
* \return the vector
*/
void gvector_expand(gvector v);
/**
* Add a new value to the end of a vector, with the data pointer provided.
* \param v the vector
* \param d the data pointer value
*/
void gvector_append(gvector v, void *d);
/**
* Add a new value to the beginning of a vector, with the data pointer
* provided.
* \param v the vector
* \param d the data pointer value
*/
void gvector_prepend(gvector v, void *d);
/**
* Remove the first value of a vector, returning the removed value. If there
* are no elements, return NULL.
* \param v the vector
* \return the data pointer, or NULL if there are no elements
*/
void *gvector_remove_first(gvector v);
/**
* Remove the last value of a vector, returning the removed value. If there are
* no elements, return NULL.
* \param v the vector
* \return the data pointer, or NULL if there are no elements
*/
void *gvector_remove_last(gvector v);
/**
* Call a given function for each value, passing the value as the only argument
* to the child function each time.
* \param v the vector
* \param f the function to be called for each value
*/
void gvector_each(gvector v, void (*f)(void *));
/**
* Return the position index of the first element containing the given data
* pointer as it is placed in the vector. If a value can not be found, return
* -1.
* \param v the vector
* \param d the data pointer value
* \return a non-negative position index if the value is found; -1 otherwise
*/
intmax_t gvector_index_value(gvector v, void *d);
/**
* Return the position index of the first element in the vector that, when a
* given comparator function is called with the value and the given data
* pointer value as arguments, returns zero. If a value can not be found,
* return -1.
* \param v the vector
* \param d the data pointer value
* \param f the comparator function
* \return a non-negative position index if the value is found; -1 otherwise
*/
intmax_t gvector_index_compare(gvector v, void *d, int (*f)(void *, void *));
/**
* Reverses a vector in place.
* \param v the vector
*/
void gvector_reverse(gvector v);
/**
* Append one vector's contents to another vector.
* \param v the vector to append to
* \param w the vector to copy from
*/
void gvector_concat(gvector v, gvector w);
/**
* Frees the memory used for a vector.
* \param v the vector
*/
void gvector_destroy(gvector v);
#endif
Name:
Anonymous2011-09-16 7:53
That's vector.h as it is right now. The basic data type for each element is a void *, which should be the same size as a uintptr_t, I think.
Name:
Anonymous2011-09-16 8:03
>>19 Generic data structures are a sign of bad design or Greenspunning. The STL is a cancer.
Good lord look at all the autism in this post!
But let's try to be serious for a moment, assuming that is even possible with complete numbnuts like you around: At the implementation level, std::vector and std::map behave just exactly like containers in the GLib - the STL, however, provides proper reflection, making shit like vec_push_back(&crusty_cum, all_the_autism_in_this_thread, sizeof(crusty_cum)); unnecessary, because C++ is able to detect the size properly. Now go back to your hugbox, you grossly deformed LITHPu GNU/Blob, you.
>>22 But let's try to be serious for a moment, assuming that is even possible with complete numbnuts like you around: At the implementation level, std::vector and std::map behave just exactly like containers in the GLib GLib is shit.
the STL, however, provides proper reflection, making shit like vec_push_back(&crusty_cum, all_the_autism_in_this_thread, sizeof(crusty_cum)); unnecessary, because C++ is able to detect the size properly. The C Preprocessor, however, provides an overly-simplistic altough useful macro system, making shit like vec_push_back(&crusty_cum, all_the_autism_in_this_thread, sizeof(crusty_cum)); unnecessary, because it is trivial to use a macro to add the size parameter automatically.
>>24
As I showed in >>23, reflection isn't necessary in this case. And RAII hasn't got anything to do with the topic.
Also, my ass isn't spongy and I'm not a ni/g/ga.
>>22
Oh, by the way, that example was terribly bad, because there's no reason to pass the size as a parameter if it's already present in the vector structure.
>>14
Or just use clang which supports overloadable functions in C.
Name:
Anonymous2011-09-16 10:12
Why hello there mister OP.
If you would like to reliably store items of various sizes directly into your data structures without using pointers that point out to them, then I think you will have to use macros and compile your code with various appropriate definitions for the macros. If the data types just happens to be the same size, or smaller than a pointer, then you could probably get away with casting, but this wont be portable to architectures where the size of a pointer is smaller than the int. That probably wont happen though. Anyways, here is one way to get template like features out of C. I'll be using the ## preprocesser operator, which concatenates strings. I haven't tested this though.
vector.c
#include <malloc.h>
#include <assert.h>
// VECTOR and ITEM are defined elsewhere
struct VECTOR {
ITEM* internal_array;
int array_length;
};
If you would like to reliably store items of various sizes directly into your data structures without using pointers that point out to them, then I think you will have to use macros
correcting myself here. You could use unions as well, but this would force you to use more space than necessary when storing smaller types.
Name:
FrozenVoid2011-09-16 11:00
Why you need Unicode support? Can't you just learn English?
LoseThos is supposed to be simple, though it's not extreme. It's not intended to grow into a primary operating system. It's for recreational programming. In theory, you could ban running any 3rd party applications, but that'd suck. Let the Chinese make their own -- it's only 130,000 LOC.
If you balloon it, it will become "yuck". It has fundamentals which are contrary to primary operating systems, but fine for what it is.
Who's to say what the right size is -- I imagien I'll keep working on it and it will become "yuck" and die.
Name:
Anonymous2011-09-16 11:45
Your library sucks. Slow as hell, you should allocate more from stack. One word, THE FORCED USAGE OF MALLOC THREAD OVER!!!
Name:
Anonymous2011-09-16 11:51
>>34
Why do you need to learn English? Can't you just learn Mandarin?
>>20 web design
No, I don't think you are experienced in web design. I think you know how to use html.
Name:
FrozenVoid2011-09-16 12:05
>>37
Mandarin requires more code support, more bytes for storage, and is far more restrictive in use of characters.
English can transcribe Mandarin perfectly, so there is no need to graphically represent it.
orbis terrarum delenda est
Name:
Anonymous2011-09-16 13:02
>>39
Why do you need to talk? Can't you just shut the fuck up?
//ArchVect.a = No of stored elements
//ArchVect.l = No allocated
//ArchVect->gVect[i].d = element i
Name:
root@eecs.berkeley.edu2011-09-16 22:27
>>45
No. That totally sucks. Leave the programming to the legit engineers you fucking wanna be nigger.
Name:
root@eecs.berkeley.edu2011-09-16 22:30
>>44 Will store number of elements allocated / stored in every element of the vector?
Nothing is getting stored yet because the program never completed the translation unit. Once it does, the whole thing becomes a declaration. I would say go read the ANSI/ISO C standard, but I don't think you have the mental capacity for such terse reading.
Name:
n3n7i2011-09-16 22:53
...Unless you're doing something tricky with the **void?
...you probably could've explained it by now if you weren't groaning so much..
Name:
n3n7i 2011-09-16 22:56
The only reason why I'm here on a friday night, instead of going out, is that I'm a total loser in real life. I'm also broke because I got fired from nambla.org