Coder Social home page Coder Social logo

wolkykim / qlibc Goto Github PK

View Code? Open in Web Editor NEW
927.0 55.0 157.0 4.8 MB

qLibc is a simple and yet powerful C library providing generic data structures and algorithms.

Home Page: http://wolkykim.github.io/qlibc

License: Other

CMake 0.71% C 93.91% Shell 2.33% Makefile 1.97% M4 1.08%
qlibc c cplusplus library linkedlist hashtable tree-structure vector queue stack

qlibc's People

Contributors

bkuhls avatar charles0429 avatar colintd avatar darkdh avatar darmar-lt avatar demitsuri avatar ffontaine avatar fullaxx avatar havetrytwo avatar hojun-cho avatar levidurfee avatar lucch avatar niceliu avatar pzmarzly avatar refi64 avatar strohsnow avatar sunbeau avatar szsam avatar wolkykim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qlibc's Issues

make error on Darwin, -soname flag is uknown option to linker

Firstly, I apologize if this is something on my own side (it probably is) - I am not super familiar with CMake, as I normally utilize plain old make.

When attempting to run make on Mac OSX/Darwin, I receive an error about -soname flag. I do have gcc installed, and it appears that the generated Makefiles are properly instructed to use gcc (not clang) - however, this error does appear to be clang related (see below). My system info:

➜  qlibc git:(master) ✗ uname -a
Darwin MacBook-Air.local 12.5.0 Darwin Kernel Version 12.5.0: Sun Sep 29 13:33:47 PDT 2013; root:xnu-2050.48.12~1/RELEASE_X86_64 x86_64

➜  qlibc git:(master) ✗ cmake --version
cmake version 3.1.1

➜  qlibc git:(master) ✗ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix

./configure was run succesfully, but here is the config.log if it's any help.

The specific output of make is below, with the error at the very bottom:

➜  qlibc git:(master) ✗ make
===> src
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qlist.o containers/qlist.c
containers/qlist.c:873:5: warning: if statement has empty body [-Wempty-body]
    Q_MUTEX_DESTROY(list->qmutex);
    ^
./internal/qinternal.h:121:68: note: expanded from macro 'Q_MUTEX_DESTROY'
        if(x->count != 0) DEBUG("Q_MUTEX: mutex counter is not 0.");    \
                                                                   ^
containers/qlist.c:873:5: note: put the semicolon on a separate line to silence this warning
./internal/qinternal.h:121:68: note: expanded from macro 'Q_MUTEX_DESTROY'
        if(x->count != 0) DEBUG("Q_MUTEX: mutex counter is not 0.");    \
                                                                   ^
1 warning generated.
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qlisttbl.o containers/qlisttbl.c
containers/qlisttbl.c:1072:5: warning: if statement has empty body [-Wempty-body]
    Q_MUTEX_DESTROY(tbl->qmutex);
    ^
./internal/qinternal.h:121:68: note: expanded from macro 'Q_MUTEX_DESTROY'
        if(x->count != 0) DEBUG("Q_MUTEX: mutex counter is not 0.");    \
                                                                   ^
containers/qlisttbl.c:1072:5: note: put the semicolon on a separate line to silence this warning
./internal/qinternal.h:121:68: note: expanded from macro 'Q_MUTEX_DESTROY'
        if(x->count != 0) DEBUG("Q_MUTEX: mutex counter is not 0.");    \
                                                                   ^
1 warning generated.
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qhashtbl.o containers/qhashtbl.c
containers/qhashtbl.c:757:5: warning: if statement has empty body [-Wempty-body]
    Q_MUTEX_DESTROY(tbl->qmutex);
    ^
./internal/qinternal.h:121:68: note: expanded from macro 'Q_MUTEX_DESTROY'
        if(x->count != 0) DEBUG("Q_MUTEX: mutex counter is not 0.");    \
                                                                   ^
containers/qhashtbl.c:757:5: note: put the semicolon on a separate line to silence this warning
./internal/qinternal.h:121:68: note: expanded from macro 'Q_MUTEX_DESTROY'
        if(x->count != 0) DEBUG("Q_MUTEX: mutex counter is not 0.");    \
                                                                   ^
1 warning generated.
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qhasharr.o containers/qhasharr.c
containers/qhasharr.c:758:22: warning: unused variable 'data' [-Wunused-variable]
    qhasharr_data_t *data = tbl->data;
                     ^
containers/qhasharr.c:911:22: warning: unused variable 'data' [-Wunused-variable]
    qhasharr_data_t *data = tbl->data;
                     ^
2 warnings generated.
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qvector.o containers/qvector.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qqueue.o containers/qqueue.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o containers/qstack.o containers/qstack.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qcount.o utilities/qcount.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qencode.o utilities/qencode.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qfile.o utilities/qfile.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qhash.o utilities/qhash.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qio.o utilities/qio.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qsocket.o utilities/qsocket.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qstring.o utilities/qstring.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qsystem.o utilities/qsystem.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o utilities/qtime.o utilities/qtime.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o ipc/qsem.o ipc/qsem.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o ipc/qshm.o ipc/qshm.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o internal/qinternal.o internal/qinternal.c
gcc -Wall -Wstrict-prototypes -fPIC -g -O2 -I/usr/include -I/usr/local/include -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include/qlibc -I./internal -c -o internal/md5/md5c.o internal/md5/md5c.c
/usr/bin/ar -rc ../lib/libqlibc.a containers/qlist.o containers/qlisttbl.o containers/qhashtbl.o containers/qhasharr.o containers/qvector.o containers/qqueue.o containers/qstack.o utilities/qcount.o utilities/qencode.o utilities/qfile.o utilities/qhash.o utilities/qio.o utilities/qsocket.o utilities/qstring.o utilities/qsystem.o utilities/qtime.o ipc/qsem.o ipc/qshm.o internal/qinternal.o internal/md5/md5c.o
ranlib ../lib/libqlibc.a
gcc -shared -Wl,-soname,libqlibc.so.2 -o ../lib/libqlibc.so.2 containers/qlist.o containers/qlisttbl.o containers/qhashtbl.o containers/qhasharr.o containers/qvector.o containers/qqueue.o containers/qstack.o utilities/qcount.o utilities/qencode.o utilities/qfile.o utilities/qhash.o utilities/qio.o utilities/qsocket.o utilities/qstring.o utilities/qsystem.o utilities/qtime.o ipc/qsem.o ipc/qshm.o internal/qinternal.o internal/md5/md5c.o
ld: unknown option: -soname
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [qlibc] Error 1
<=== src

An issue reported on StackOverflow suggests that Mac OSX should use -install_name instead of -soname, but I am not sure how to instruct CMake of this.

Any ideas about this one? Thanks!

This library is not portable!

It doesn't use standard C headers but relying on platform specific headers too much. This would work on posix systems but on Windows it's problematic. For example, on mingw64 there is no such header as <sys/sem.h>. It also uses <sys/types.h> that causes problem on mingw64 because on mingw64 there is no such thing as u_int32_t defined. There are ifdefs on source code to check for _WIN32 but I don't think it could build out of the box with MSVC either. This library shouldn't be used if you want something truly portable. There are much better solutions: https://github.com/oz123/awesome-c#frameworks

CMake build guilde

Is there anyone interested in updating INSTALL.md with information about using CMake on Windows/Mac/Linux for those who are not familiar with it?

Documentation on installing/setting up

Hi

How would I go about using this library in my c99 code?
I didn't see any section in then docs on installing it, so could use the help.

I tried make, but make didn't have any target.
So then I created a build dir in the project root and the did cd build and cmake ..
This errored out however, as I apparantly do not have pthreads.

It will be good to have a section on installing qlibc and its dependencies on each platform.

Confusions on qvector

  • qvector does not provide get method to access a single element
  • qvector is based on qlist, which does not provide O(1) time to access elements

In my opinion, I think qvector needs to be implemented based on array, and provide get methods to access element by index.

hostname or destname

hostname or destname?????

qhttpclient_t *qhttpclient(const char *destname, int port) {
    bool ishttps = false;
    char hostname[256];
    if (port == 0 || strstr(hostname, "://") != NULL) { // hostname or destname?????
        if (_parse_uri(destname, &ishttps, hostname, sizeof(hostname), &port)
                == false) {
            DEBUG("Can't parse URI %s", destname);
            return NULL;
        }

        DEBUG("https: %d, hostname: %s, port:%d\n", ishttps, hostname, port);
    } else {
        qstrcpy(hostname, sizeof(hostname), destname);
    }

qhashmd5_file() reads zero bytes when the entire file is requested

Calling qhashmd5_file(myfile, 0, 0, buf) will result in an initialized MD5 context and an incorrect hash returned to the caller.
When nbytes is set to zero, the for loop never executes skipping all read() and MD5Update() calls.

Qlibc is a fantastic C library, thanks for creating this project!

A potential bug about lock

Hello, I encounter a segmentation fault in qhashtbl_lock (which is called by qhashtbl_getnext) where I have multiple threads call this function.
I suspect the problem is due to the following code in qinternal.h:

#define Q_MUTEX_ENTER(m) do {                                           \
        if(m == NULL) break;                                            \
        while(true) {                                                   \
            int _ret, i;                                                \
            for(i = 0; (_ret = pthread_mutex_trylock(&(((qmutex_t *)m)->mutex))) != 0 \
                        && i < MAX_MUTEX_LOCK_WAIT; i++) {              \
                if(i == 0) {                                            \
                    DEBUG("Q_MUTEX: mutex is already locked - retrying"); \
                }                                                       \
                usleep(1);                                              \
            }                                                           \
            if(_ret == 0) break;                                        \
            DEBUG("Q_MUTEX: can't get lock - force to unlock. [%d]",    \
                  _ret);                                                \
            Q_MUTEX_LEAVE(m);                                           \
        }                                                               \
        ((qmutex_t *)m)->count++;                                       \
        ((qmutex_t *)m)->owner = pthread_self();                        \
    } while(0)

In this code, the mutex that is locked by another thread is unlocked after trying MAX_MUTEX_LOCK_WAIT times.
However, is it safe to unlock a mutex lock that is locked by another thread ?

About next release

When can we publish next release? I want to integrate the official release to my project.
Because I need the remove_by_idx() API of the changes since 2.2.0.

qvector_t: calling addlast after calling clear causes double free and SIGABRT

I think there may be an issue in the clear function in qvector_t (using C11) starting with the line:

free(vector->data);

I ran into this when using the library (which has been super valuable and useful, thank you!) and I tested it in isolation with this program (lines packed for brevity):

#include <stdio.h>
#include <qlibc/qlibc.h>

void succeeds() {
    printf("\nsucceeds:\n");
    qvector_t *vec = qvector(10, sizeof(uint64_t), QVECTOR_RESIZE_DOUBLE);
    uint64_t a = 1, b = 2, c = 3, d = 4, e = 5;
    printf("addlast: &a"); vec->addlast(vec, &a);
    printf(", &b"); vec->addlast(vec, &b);
    printf(", &c"); vec->addlast(vec, &c);
    printf(", &d"); vec->addlast(vec, &d);
    printf(", &e"); vec->addlast(vec, &e);
    printf(", size=%zu\n", vec->size(vec));
    printf("remove all"); while (vec->size(vec) != 0) { vec->removelast(vec); }
    printf(", size=%zu\n", vec->size(vec));
    printf("addlast: &a"); vec->addlast(vec, &a);
    printf(", &b"); vec->addlast(vec, &b);
    printf(", &c"); vec->addlast(vec, &c);
    printf(", &d"); vec->addlast(vec, &d);
    printf(", &e"); vec->addlast(vec, &e);
    printf(", size=%zu\n", vec->size(vec));
    vec->free(vec);
}

void fails_with_double_free() {
    printf("\nfails_with_double_free:\n");
    qvector_t *vec = qvector(10, sizeof(uint64_t), QVECTOR_RESIZE_DOUBLE);
    uint64_t a = 1, b = 2, c = 3, d = 4, e = 5;
    printf("addlast: &a"); vec->addlast(vec, &a);
    printf(", &b"); vec->addlast(vec, &b);
    printf(", &c"); vec->addlast(vec, &c);
    printf(", &d"); vec->addlast(vec, &d);
    printf(", &e"); vec->addlast(vec, &e);
    printf(", size=%zu\n", vec->size(vec));
    printf("clear"); vec->clear(vec);
    printf(", size=%zu\n", vec->size(vec));
    printf("addlast: &a"); vec->addlast(vec, &a);
    printf(", &b"); vec->addlast(vec, &b);
    printf(", &c"); vec->addlast(vec, &c);
    printf(", &d"); vec->addlast(vec, &d);
    printf(", &e"); vec->addlast(vec, &e);
    printf(", size=%zu\n", vec->size(vec));
    vec->free(vec);
}

void also_fails_with_double_free() {
    printf("\nalso_fails_with_double_free:\n");
    qvector_t *vec = qvector(10, sizeof(uint64_t), QVECTOR_RESIZE_DOUBLE);
    uint64_t a = 1, b = 2, c = 3, d = 4, e = 5;
    printf("clear"); vec->clear(vec);
    printf(", size=%zu\n", vec->size(vec));
    printf("addlast: &a"); vec->addlast(vec, &a);
    printf(", &b"); vec->addlast(vec, &b);
    printf(", &c"); vec->addlast(vec, &c);
    printf(", &d"); vec->addlast(vec, &d);
    printf(", &e"); vec->addlast(vec, &e);
    printf(", size=%zu\n", vec->size(vec));
    vec->free(vec);
}

int main(int argc, char *argv[]) {
    setbuf(stdout, NULL);
    succeeds();
    fails_with_double_free();
    //also_fails_with_double_free();
    return 0;
}

Output:

succeeds:
addlast: &a, &b, &c, &d, &e, size=5
remove all, size=0
addlast: &a, &b, &c, &d, &e, size=5

fails_with_double_free:
addlast: &a, &b, &c, &d, &e, size=5
clear, size=0
addlast: &a, &b, &c, &dfree(): double free detected in tcache 2

Process finished with exit code 134

Other output:

also_fails_with_double_free:
clear, size=0
addlast: &a, &b, &c, &dfree(): double free detected in tcache 2

I'm statically linking to qlibc and using gcc version:

gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)

Does this look like an issue or am I doing something wrong? My workaround for now is to wrap "remove all" into a function; this will work fine for me since my use case isn't speed-critical.

Error while loading shared libraries: ../lib/libqlibc.so.2: cannot open shared object file: No such file or directory

Hello, there. qlibc is awesome. I am sadly, currently in a pickle: I can't execute the object file created upon successful compilation of a C file containing qhttpclient code. The linker flags -lqlibc -lqlibcext -lssl -lcrypto -pthread work only during compilation, but attempting to run the object file created from the linkage produces the message:

./[file]: error while loading shared libraries: ../lib/libqlibc.so.2: cannot open shared object file: No such file or directory

Any help would be appreciated.

Problem with reinitialization of HTTPS client

I've been trying to use your excellent library for repeated HTTPS requests, and have found that if I free and reallocate a client object, then subsequent operations quietly fail.

Having dug through the code I think the issue is to do with the setssl method, where the second time round, the initialized flag stops a ssl object being allocated on the client object.

I've fixed as below in my code and it seems to work fine.

Given that to date I believe you're the only person that has touched the code I thought I'd raise this issue rather than fixing directly, but feel free to let me know otherwise.

Once again, thanks for the excellent library.

Cheers,

Colin.

static bool setssl(qhttpclient_t *client) {

ifdef ENABLE_OPENSSL

static bool initialized = false;

if (client->socket >= 0) {
    // must be set before making a connection.
    return false;
}
if (client->ssl != NULL) {
    // already initialized.
    return true;
}

// init openssl
if (initialized == false)
{
  initialized = true;
  SSL_load_error_strings();
  SSL_library_init();
}

// allocate ssl structure
client->ssl = malloc(sizeof(struct SslConn));
if (client->ssl == NULL) return false;
memset(client->ssl, 0, sizeof(struct SslConn));

return true;

else

return false;

endif

}

typo in qqueue.c file

line81-86 can be modified to:

 *  obj = queue->pop(queue, NULL);
 *  printf("pop(): %s\n", (char*)obj);
 *  free(obj);
 *  obj = queue->pop(queue, NULL);
 *  printf("pop(): %s\n", (char*)obj);
 *  free(obj);

possible bug in qvector_resize

Hi,
I think I found a small bug in qvector container in function qvector_resize().
If the argument 'newmax' is smaller than the current size of container 'num', then the 'num' should be changed to 'newmax' too. I think the code should be added after 768 line:

if (vector->num > newmax) {
    vector->num = newmax;
}

A problem (?) in qtreetbl

Hello
A few months ago I developed a wrapper for some of qlibc containers to be called from Fortran language (here). Thanks to the developers of qlibc!

Recently one of the user, frazar, performed tests with qtreetbl container. He found, that an invariant 4 "If a node is red, then both its children are black." (Wikipedia) is broken in his test case. Original message of frazar can be found here. I repeated the same test with qlibc in my fork.

Does the rule "If a node is red, then both its children are black" should be always enforced in the realized algorithm?

qvector_t should use an array as its data container

The expected behaviour of a vector is:
a) O(1) random element access and append.
b) O(n) iteration, element removal, and element insertion
c) Specify capacity
b) sequential layout in memory.

If qlibc is targeting C99, then it could use a flexible array member to keep the vector size info together with
the array.

error: too many arguments to function 'mkdir'

It's in qfile.c and I'm on MSYS2 with cmake and ninja. Compiler is mingw-w64-x86_64-gcc. POSIX mkdir takes two arguments but Windows' mkdir only take just one. It seems your library doesn't support Windows, isn't it?

Hashtable with non-string keys

From qhashtbl.c:

qhashtbl implements a hash table, which maps keys to values. Key is a unique string and ...

Does it mean for instance, that a hash table with int keys is not supported?

[Question] Windows supported? It seems that CMake doesn't work

  1. It seems that pthreads is required, so I use pthreads for Windows instead. It seems CMakeLists.txt does not work well with find.
  2. If I ignore MESSAGE(FATAL_ERROR "Couldn't find pthreads."), then build process will be fail. One of the error messages come with
E:\DemoProjects\qlibc\src\internal\qinternal.h(64): fatal error C1083: Cannot open include file: 'unist d.h': No such file or directory [E:\DemoProjects\qlibc\build\qlibcext-static.vcxproj]

It seems some POSIX interfaces are required. Does it mean Windows not supported? Thansk!

Move `#include <sys/types.h>` to header files

I'm getting some errors regarding the types ssize_t and off_t when including utilities/qhash.h in Ubuntu + gcc. Shouldn't the #include <sys/types.h> present in src/utilities/qhash.c be in the corresponding .h? It fixes the problem...

It also occurs in other files. Following is the output of running grep "sys/types.h" -R include/ src/:

src/extensions/qhttpclient.c:#include <sys/types.h>
src/utilities/qfile.c:#include <sys/types.h>
src/utilities/qcount.c:#include <sys/types.h>
src/utilities/qhash.c:#include <sys/types.h>
src/internal/md5/md5c.c:#include <sys/types.h>

A new container in Tree data structure is written and under your review.

I'm so excited to tell everyone that we're going to add a new container in tree data structure.
That has been wanted for long time. This implementation takes left-leaning red-black BST algorithm and fully written from ground up.

40402e8

The implementation adds some useful addition algorithm tune ups such as iteration over LLRB tree and find_nearest_key.

The code might be little rough but I'd like ask your review and feedback and I'll keep working on code polishing.

Thank you all.

Contradictory licence information

The .io site says:

All of the deliverable code in qLibc has been dedicated to the public domain by the authors

However, the readme lists a more restrictive two-clause licence, and refers to the LICENCE file which is a traditional BSD-style licence.
Since the source files themselves also contain the same copyright notice and BSD-style licence, I guess that's the one that was intended to apply. That would mean that the project is not in the public domain, and the .io description is inaccurate.

man page - what man page!

Um, I've just cloned and built this library and I can see there is a doc directory and that it contains html pages but that these are not installed outside of the source tree. I am intending to use this for a INI config file reader/writer provided by the Extension API on a Raspberry Pi (for a Home Automation Project) that I am SSHing into and I'm not using a GUI so I'd be looking to use man (or the GNU preferred documentation info system) to browse the reference documentation.

Is it intended to expand the documentation into other formats or to install the information into a known location? 😀

Comparing floats

I'm thinking about using qunit.h for floating-point calculations.

What do you think about assertion like this

#define ASSERT_EQUAL_FLOAT_TOL(p1, p2, tol) ASSERT( (p1<p2 ? p2-p1 : p1-p2) < tol )

that can be used in tests:

TEST("Compare floats") {
  float f1 = 1.000000;
  float f2 = 1.000001;
  ASSERT_EQUAL_FLOAT_TOL(f1, f2, 1.0e-7); // should fail
  ASSERT_EQUAL_FLOAT_TOL(f1, f2, 1.0e-6); // who knows???
  ASSERT_EQUAL_FLOAT_TOL(f1, f2, 1.0e-5); // should pass
}

A comment to the questions about qLibc.

There's an interesting conversation going on about qLibc. I left below comments at the forum. I'm copying it here for those who might have similar questions.

The full conversation can be seen at here

Hi,

I'm the author of qLibc. One of our contributors let me know this interesting conversation is going on here. I've read all thoroughly and I consider all the comments here are so helpful and valuable. Thank you for all the inputs. I will use your input for the future improvements. Just wanted to leave my takeouts and current plan on your suggestions and comments.

About pointer function approach to the container functions.

  • The intention of this approach is to easily switch containers from one to the other with minimizing the need of user code changes. qLibc try to keep the container API similar as much as possible. For an example, switching from hash table to linked-list table or tree table(in dev mode) could be done with one line change. qhashtbl_t *tbl = qhashtbl() => qlisttbl_t *tbl = qlisttbl() then rest of code will work since tbl->put() will work on both containers. (this is not always true but trying to practically make it easier enough for the common parts such as put, get, delete, clear, size, free)
  • I caught this approach from Berkeley DB implementation long time ago. But as you mention here, it carries small overhead. So it has good and bad depends on your perspective and use cases. Personally, I don't think this would be a deal breaker and compromising too much and quiet not sure if it does produce noticeable performance degradation in practice.
  • But, besides my personal preference, after all, this is your library, I'm considering to make qLibc provide both traditional APIs and current encapsulated APIs. For an example: qhashtbl_get(tbl, "score") tbl->get(tbl, "score")
  • Currently qLibc is adding Left-Leaning Red-Black BST algorithm and will be available soon with a name of qtreetbl. I think this qtreetbl will be the first container providing the both ways then we can expand it to other containers.

About the name qLibc.

In the history, the many parts of qLibc code has delivered from the successor project of qDecoder. qDecoder is a C library for Common Gateway Interface(CGI). Around 2010, one of qDecoder fan suggested to break the project into 2 parts and maintain the general codes in a separate project. I took the advice then qLibc was born like that. There's qHttpd project which was also departed from qDecoder project. So I gave qLibc a sibling mark of alphabet Q :) I was little concerning about the look similarity between qlibc and glibc in lower case writings. But it just went like that and I like the name. So alphabet Q happened to get a meaning to me. I guess now you all like the name like I do ? Still no? Oh man! I'm sad then...

qLibc VS. glib?

I think the principals are different. To me glib is like Home Depot. qLibc is like Ace Hardware Store or Radio Shark. qLibc takes practical needs. For an example,

  • all the containers and extensions are implemented in 2 files per each. 1 header file and 1 code file. If you need modification to take care of your special need or If you want to use only some part of library or whatever reason, you can merge it into user project by dropping those 2 files.
  • Containers takes string type keys in the default put/get API for practical reason and provide binary type key type which is less frequently used in general with little longer method names. It carries convenient wrapper methods by default like putstr which stores string type data and which is technically not necessary once it provides binary key/data pair functionality, all those can be handled in user space. But because it's C, not any other OO languages which is relative simpler to manage user wrappers, it takes more elbow grease, so qLibc carries them. glib's kind of spirit perspective or from standard perspective, it's too kind thing and wouldn't allow it. But qLibc is written to be practical, so it's absolutely ok with qLibc if that's a way we commonly use.
  • qLibc is unique and flexibility to adopt the boundary areas. For example, qhasharr which implements hash table in a fixed memory block for shared memory/disk operation has a unique algorithm. It implements Token Bucket, Configuration file parser for apache httpd style configuration, light weight HTTP client since we have great curl library, all the handy hash algorithms including Murmur Hash and FNV. So it's like that, it also provides MD5 hash as well but if your application seriously use MD5(like updating the digest on the fly before finalization), I recommend to use openssl's API since it comes with most of distributions. But if you just need to fingerprint some strings or files, I think using qLibc's API will greatly reduce your efforts on the code. So I think the values of qLibc are there.
  • More freedom? 2-clause BSD license vs LGPL license. qLibc, every single line has written from ground up. And as a copyright holder, I can tell all I want is giving back(if I can) what I got from the spirit of opensource.
  • And maybe compact, zero dependency, consistent APIs, supports of Windows are +1?

About using _t suffix that's reserved.

  • This is basically because of my ignorance. I knew that recently. The reason I put _t for the object is to help users to identify and treat the returned data structure as an object. It's like saying that accessing the object's internal directly is not intended by the implementation.
  • POSIX standard reserves _t to prevent possible name conflicts with user codes. After I knew that fact, I was considering alternatives like _o, _obj, _x, _q or no sufixes but I ended up using qXXX_t notation thinking that using _t sufix would deliver the intended meaning clearly to people's common sense.
  • If this is a serious deal breaker then I think it should change but quiet not sure for now. There's some of code standard compliant requests from users and it's going on now but _t suffix is not considered yet and open to hearing.

Using boolean type, C99

Personally, I say personally, sticking on traditional C coding standard gives pros and cons. With traditional style, your code can be more widely ported with minimum efforts. If I were working on glib, I'd stick to it. For qLibc? I've choose to take the advantages. Using pointer member concept is one of them. Integer type could replace boolean type, or char type could be used for it, but to me it is not obvious not to use boolean type since most of recent dev environments can handle them. C99 makes code more readable, less buggy and I think it helps making the code easier to maintain.

It's open to all

The project is open to suggestions and looking for better ways all the times. Your interests feeds the project and drives the projects. So drop it a line at the project home if you have any ideas or suggestions. The spirit of open source.

Thank you again for all your interests and valuable comments/suggestions.

Seungyoung “Steve” Kim

Performance benchmark: encapsulation call VS. direct call.

For those, who's interested in to see the performance diff between encapsulation call VS direct call.

Test qtreetbl.c
======================================================================
* TEST : Test growth of tree 
                                E 
              C `````````````````````````````````` R 
     B ```````````````` D                 N ```````````````` X 
   [A]````````           ````````       [I]````````        [S]````````   
   ````       ````      ````   

       Tree Info : #nodes=10, #red=3, #black=-7, root=E
.................... OK (20 assertions, 80us)
* TEST : Test basic but complete .............................. OK (33 assertions, 9us)
* TEST : Test encapsulated call perf - 1,000,000,000 times  OK (0 assertions, 1592006us)
* TEST : Test direct call perf - 1,000,000,000 times  OK (0 assertions, 1557411us)

Here the test code:

TEST("Test encapsulated call perf - 1,000,000,000 times") {
    qtreetbl_t *tbl = qtreetbl(0);
    long i;
    for (i = 0; i < 1000000000; i++) {
    tbl->size(tbl);
    }
    tbl->free(tbl);
}

TEST("Test direct call perf - 1,000,000,000 times") {
    qtreetbl_t *tbl = qtreetbl(0);
    long i;
    for (i = 0; i < 1000000000; i++) {
    qtreetbl_size(tbl);
    }
    tbl->free(tbl);
}

My dev box has Intel(R) Core(TM) i5-4430 CPU @ 3.00GHz

Memory allocation fail then return NULL?

I am looking at your code with great interest. It's quite interesting!
The code below does not check to see if it returns NULL. There are a few more such codes.
I'll create a PR if you need to.

char *buf = (char *) malloc(sizeof(char) * (len + 1));

newstr = (char *) malloc(maxstrlen + 1);

newstr = (char *) malloc(maxstrlen + 1);

char *buf = (char *) malloc(sizeof(char) * (len + 1));

Should qlibc support meson and ninja build?

Hi there! I've been contributing to the project. Seeing that this project is using CMake.
I think this could be better if qlibc implements Meson and Ninja for better project configuration and build.

about gitignore?

When I compile and install qlibc, the following files are not ignored to be tracked.

# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   ../lib/libqlibc.so
#   ../lib/libqlibc.so.2
#   ../lib/libqlibcext.so
#   ../lib/libqlibcext.so.2
#   test_qhasharr
#   test_qhasharr_darkdh
#   test_qhashtbl
#   test_qstring
#   test_qtreetbl
nothing added to commit but untracked files present (use "git add" to track)

qurl_decode segfault

#include "qlibc.h"

int main(int argc, char *argv[]) {
  char* str = "JW";

  qurl_decode(str);

  return(0);
}

This produces a segfault when run. The function definition says it will return NULL if there is any problem but only a check for str == NULL is being performed. I have not taken the time to fully understand the problem happening here, in the hopes someone more familiar with this could take a look and do a proper fix.

Valgrind shows this:

==6515== Memcheck, a memory error detector
==6515== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6515== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==6515== Command: ./ex
==6515==
==6515==
==6515== Process terminating with default action of signal 11 (SIGSEGV)
==6515==  Bad permissions for mapped region at address 0x111004
==6515==    at 0x10A7EF: qurl_decode (qencode.c:210)
==6515==    by 0x10A7EF: qurl_decode (qencode.c:192)
==6515==    by 0x10A43F: main (ex.c:7)
==6515==
==6515== HEAP SUMMARY:
==6515==     in use at exit: 0 bytes in 0 blocks
==6515==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==6515==
==6515== All heap blocks were freed -- no leaks are possible
==6515==
==6515== For counts of detected and suppressed errors, rerun with: -v
==6515== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Problem with qstrreplace()

I use it to replace space in a exec string and it fails. The string was something like "/home/user/test/project/progs/cprogs/this is.sh" and the function destroys the string. If I use the function for "this is.sh" everything is right. I try to replace the " " with "\ " to escape the space for exec.

After ./configure, should these files be ignored or committed back?

After running configure, some files appear in the repo to be modified but without any actual difference in a git diff. It is strange because these files appear as "Untracked", but they existed in the repo right after pulling - for example, Makefile. Additionally, even after running make clean these files are still modified.

What is the suggested method of keeping the repo clean for committing changes upstream for a pull request?

➜  qlibc git:(master) ✗ git st
On branch master
Your branch is up-to-date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Makefile
    config.h
    config.log
    config.status
    examples/Makefile
    src/Makefile
    tests/Makefile

typo in qlist.c

In function qlist_getnext, the following lines:

    if (obj == NULL)
        return NULL;

The return type of qlist_getnext is bool, so the return line needs to be changed to:

    if (obj == NULL)
        return false;

qtreetbl has right lean child. Is qtreetbl not a llrb?

ut_qrbtree(134)-> "put: 40\n"
(BLK:40)
| |---L(BLK, null)
| |---R(BLK, null)
ut_qrbtree(134)-> "put: 30\n"
(BLK:40)
| |---L(RED:30)
| | |---L(BLK, null)
| | |---R(BLK, null)
| |---R(BLK, null)
ut_qrbtree(134)-> "put: 20\n"
(BLK:30)
| |---L(RED:20)
| | |---L(BLK, null)
| | |---R(BLK, null)
| |---R(RED:40) -- right lean red node.
| | |---L(BLK, null)
| | |---R(BLK, null)

test code:
`TESTCASE(rbtree, ut_qrbtree)
{
int i;
int data[] = {
40, 30, 20, 50, 60, 55, 4, 24, 80, 33, 44, 11
};
int size = ARRAY_CNT(data);
qtreetbl_t *qtree = qtreetbl(0);

qtree->set_compare(qtree, qtree_cmp);

for (i = 0; i < ARRAY_CNT(data); i++) {
    LOG_DEBUG("put: %d\n", data[i]);
    qtree->put_by_obj(qtree, &data[i], sizeof(int), &data[i], sizeof(int));
    print_qrbtree(qtree->root, 0, 0);
}

{
    for (i = 0; i < size; i++) {
        LOG_DEBUG("delete-inorder:%d", data[i]);
        qtree->remove_by_obj(qtree, &data[i], sizeof(int));
        print_qrbtree(qtree->root, 0, 0);
    }
}
qtree->free(qtree);
return 0;

}
`

qhex_decode segfault

#include "qlibc.h"

int main(int argc, char *argv[]) {
  char* str = "JW";

  qhex_decode(str);

  return(0);
}

This program segfaults when run. The function definition says it will return NULL if there is any problem but I do not see any checks being done. Would it be enough to check if the characters are in the valid set of characters for this function? [0-9][a-f][A-F] or something similar.

Valgrind shows this:

==6475== Memcheck, a memory error detector
==6475== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6475== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==6475== Command: ./ex
==6475==
==6475==
==6475== Process terminating with default action of signal 11 (SIGSEGV)
==6475==  Bad permissions for mapped region at address 0x111004
==6475==    at 0x10AE58: qhex_decode (qencode.c:448)
==6475==    by 0x10A43F: main (ex.c:6)
==6475==
==6475== HEAP SUMMARY:
==6475==     in use at exit: 0 bytes in 0 blocks
==6475==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==6475==
==6475== All heap blocks were freed -- no leaks are possible
==6475==
==6475== For counts of detected and suppressed errors, rerun with: -v
==6475== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.