GithubHelp home page GithubHelp logo

bkthomps / containers Goto Github PK

View Code? Open in Web Editor NEW
166.0 5.0 14.0 712 KB

This library provides various containers. Each container has utility functions to manipulate the data it holds. This is an abstraction as to not have to manually manage and reallocate memory.

License: MIT License

C 99.46% Makefile 0.23% Python 0.31%
datastructures data-structures containers container collections collection array deque list map

containers's Introduction

GitHubBuild Documentation Codecov Language License

Containers

This library provides various containers. Each container has utility functions to manipulate the data it holds. This is an abstraction as to not have to manually manage and reallocate memory.

Inspired by the C++ standard library; however, implemented using C with different function interfaces as the C++ standard library but with the same container names.

Setup

It is possible to compile this library as either static .a or dynamic .so:

  1. A static library is slightly faster than a dynamic one, however, if the library is modified, the entire project codebase which uses it will need to be relinked.
  2. A dynamic library can be changed without relinking the codebase, assuming no function definitions have changed.

The installation process is as follows:

  1. Clone this repository and navigate to it.
  2. Run make static_clang/make static_gcc or make dynamic_clang/make dynamic_gcc for either a static or dynamic library.
  3. Then, you can copy-paste containers.h and containers.a/containers.so into your project to include the containers.
  4. Finally, you remember to link the library by including containers.a -ldl/containers.so -ldl as an argument.

Documentation

For high-level documentation and usage, visit the documentation page. For in-depth documentation, visit the code docs page.

Container Types

The container types that this library contains are described below.

Sequence containers

Data structures which can be accessed sequentially.

  • array - static contiguous array
  • vector - dynamic contiguous array
  • deque - double-ended queue
  • forward_list - singly-linked list
  • list - doubly-linked list

Associative containers

Data structures that can be quickly searched which use comparators.

  • set - collection of unique keys, sorted by keys
  • map - collection of key-value pairs, sorted by keys, keys are unique
  • multiset - collection of keys, sorted by keys
  • multimap - collection of key-value pairs, sorted by keys

Unordered associative containers

Data structures that can be quickly searched which use hashing.

  • unordered_set - collection of unique keys, hashed by keys
  • unordered_map - collection of key-value pairs, hashed by keys, keys are unique
  • unordered_multiset - collection of keys, hashed by keys
  • unordered_multimap - collection of key-value pairs, hashed by keys

Container adaptors

Data structures which adapt other containers to enhance functionality.

  • stack - adapts a container to provide stack (last-in first-out)
  • queue - adapts a container to provide queue (first-in first-out)
  • priority_queue - adapts a container to provide priority queue

containers's People

Contributors

bkthomps avatar pseudopooja 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

containers's Issues

Negative integer division and modulo is implementation-defined in C89

In C89, negative integer division and modulo is implementation defined.

Case 1: division rounds to 0 (C89/90, C99, C11, C18)

  • -9 / 7 -> -1
  • -9 % 7 -> -2

Case 2: division rounds to negative infinity (C89/90)

  • -9 / 7 -> -2
  • -9 % 7 -> 5

Make it so that negative integer division and modulo does not occur. For example, deque.c uses negative integer modulo to determine if the block spacing needs to be expanded backwards. This can be changed to not rely on modulo.

Make sizeof use variable not the type

When using the sizeof operator, use *variable rather than the type. This is so that if the variable type changes, the sizeof does not need to change.

deque_to_array silently fails

If deque_to_array fails to allocate memory, it simply returns without an error code, and without setting the array. To fix this, re-write deque_to_array without allocating memory.

Add Windows support to testing

The test_multimap.c fails on line 645 on Windows.

Overview:

gcc             No warnings or errors
Tiny C          No warnings or errors
bcc             No errors (2)
DMC             Errors (1)
Pelles C        Warnings (1); test program crashed (3)
lccwin          Warnings (1); compiler error (4)

(1) These all reported the same problems; the one above, and similar ones such as on lines 184 and 315 of test_unordered_map.c.

(2) This compiler (mine) doesn't do warnings. I'll need to investigate why it doesn't pick up that pointer mismatch, even with the change below

(3) The crash may be due to those pointers, or it might be a compiler bug

(4) This gave an internal compiler error on test_deque.c (probably a compiler bug), but only when optimised. Unoptimised it built the program but it gave this runtime error:

Assertion failed:  array_set(me, 0, &get) == -EINVAL c:\cont\src\test_array.c 23

Add iterators

Add iterators to some containers. For example, in the tree-based containers.

Increase base container sizes

Increase base bucket count of unordered_* from 8 to 16. Increase resize ratio from 1.5 to 2.

Increase base block count of deque from 1 to 8. Increase block size from 8 to 1024. Maybe let the user specify the block size?

deque #72
queue #79
stack #78
unordered_map #96
unordered_multimap #97
unordered_multiset #93
unordered_set #92

Examine memory and time usage

The deque seems to use quite a bit of memory when used as a queue (even though queue should be used for this). This is likely due to the fact that it does not trim. Examine this to see if there is a problem.

Also examine the memory and time usage for all containers.

Update CI/CD

Right now, it builds with coverage, then sends to codecov for analysis. Additionally, there is another tool to check code quality. Valgrind has to be run manually.

Instead, replace this with: build without coverage, run clang-tidy and valgrind with -Werror. Then, build with coverage and send to codecov. This requires a container with valgrind and codecov installed. However, this means we don't need to code quality tool (only allowed 10 code quality checks per day with that tool).

Singly-linked list performance optimization

Have a pointer that is either NULL or points to the back of the list.

On an append to the back, if the pointer to the back exists, append to that, which is O(1). Otherwise, find the back and update the pointer, which is O(n).

On the removal from the back, set the pointer to NULL.

Improve set

Currently, a binary search tree is being used without any re-balancing. Using an AVL tree will result in better time complexity.

Test out of memory conditions

Right now, the code coverage is at ~94%. The other ~6% that is not covered is out-of-memory (OOM) cleanup and safe failure.

It would be good to be able to test OOM conditions to make sure that the safe failure is correct.

This could either be done by:

  1. using hooks to change malloc, calloc, and realloc; or
  2. disabling the OOM handler and filling up the memory

Failed allocation recovery

Whenever malloc, calloc, or realloc is called, the pointer is checked for NULL. However, for some of the data structures, an invalid state is produced. Thus, make it so that in the extremely unlikely event that the memory allocation fails, that the structure is still in a valid state.

When resizing check for overflow

When multiplying the size of a container by a factor of 1.5 or 2, check that no overflow occurs with the new size. This is unlikely to occur, but I should investigate the edge case, what might happen, and look at potential solutions.

Macro names not unique enough

Change macro names so they are more unique. There are two variations:

  • change multiple include guards from CONTAINERS_* to BKTHOMPS_CONTAINERS_*
  • change default values for containers to start with BKTHOMPS_CONTAINERS

Fix typo in readme

For a static library, it should say "need to relink" not "need to recompile".

Create example usage documentation

Create documentation for example usage of various containers. Documentation already exists, but it does not explain how to use the containers sufficiently.

Set should not recursively clear

When clearing all the elements from the tree, currently recursion is used.

However, if the tree is large enough, the stack may not be big enough.

Thus, use iteration with pruning.

Queue should trim by factors

Currently, queue trims every 64 pops. However, if the size of the queue is in the thousands this does not make sense. Thus, queue should trim whenever the trim count is greater than 1.5 the size of the queue, or another similar value.

queue_pop function doesn't work

I have used JAVA language for some years, now I am working on a project which must using C . I think your project is very useful. But when use queue_pop it doesn't change anything for me, my code was below:

void addSendTask(queue sendQueue, const int *startTime, const int *endTime) {
    int pathLen = sizeof(FILE_LOCATION);
    for (int i = *startTime; i <= *endTime; ++i) {
        char file[pathLen + 2];
        strcpy(file, FILE_LOCATION);
        char fileName[3];
        sprintf(fileName, "%d", i);
        strncpy(file + pathLen - 1, fileName, 2);
        clearBuf(fileName, 2);
        clearBuf(file, pathLen + 2);
    }
    
    printf("the length of queue is: %d\n", queue_size(sendQueue));
    
    while (!queue_is_empty(sendQueue)) {
        char file[22];
        // queue_front(file, sendQueue);
        bk_bool a = queue_pop(file, sendQueue);
        if (a == BK_TRUE) {
            printf("File name: %s\n", file);
        } else {
            puts("the queue doesn't contain elements");
        }
    }
}

The printf() in the medium could output the size of the queue, and the result of queue_pop is true, but it still couldn't print the file name. Is there anything wrong in my code? Thanks so much

The queue may have a small bug?

Hello:
I think the library is very useful and pretty good!But when I use the queue,I found a small bug,for example:
for(int i = 0;i<100;i++)
xxx;
{
queue_push();
queue_pop();
}
xxx;
In linux,the console is show Core Dump,the reason is "double free or corruption",the bug is place in the deque_trim() function.
Thank you very much!

Error codes implementations-specific

Most implementations support EINVAL and ENOMEM; however, it isn't required in C89.

Since return values can be -EINVAL and -ENOMEM, check if those are defined, if they are, use their value, otherwise return what would have been returned had they been defined. So:

#ifdef EINVAL
#define BK_EINVAL EINVAL
#else
#define BK_EINVAL 22
#endif

#ifdef ENOMEM
#define BK_ENOMEM ENOMEM
#else
#define BK_ENOMEM 22
#endif

Make headers into one file

Combining all the 16 headers into one file will make it easier for people to include the library. This way, this library will consist of containers.h, and one of containers.so or containers.a.

This could either be done manually or by using a script.

Custom memory functions

Allow custom malloc, calloc, realloc, and free. Add freeing functions too, if a user wants the container to free on removal.

forward_list

free(backup->data); free(backup); if (!backup->next) { me->tail = NULL; }

Do not you think that these lines(256-260) are a bit strange? For example, we refer to the pointer after the free function and set the tail to NULL
maybe it should look like this:
if (!backup->next) { me->tail = traverse; } free(backup->data); free(backup);

Simplify return values

Sometimes it's hard to tell if 0 is good because it indicates no error, or if 0 is bad because it means false.

Add automatic trimming to deque

If a user uses a queue, or uses a deque as a queue, it should automatically trim the memory area that will never be used again.

Similar duplicated files

set.c, map.c, multiset.c, and multimap.c are very similar
unordered_set.c, unordered_map.c, unordered_multiset.c, and unordered_multimap.c are very similar

See if there is a way to reduce the amount of semi-duplicated code.

Do not overuse memcpy

If it's possible to use simple assignment, use that instead of memcpy.

For example, use block = me->data[start_block_index]; rather than memcpy(&block, me->data + start_block_index, sizeof(char *)); when possible.

Create second hash function for hashing containers

Containers which use hashing (unordered_set, unordered_map, unordered_multiset, unordered_multimap), should hash the user-specified hash. This is because the user-specified hash could potentially result in uneven hash distributions if the user-specified hash is sub-optimal. This second hash would reduce clustering in the hashed containers.

Run tests on pull request

Tests should be run when a pull request is created from a forked repository.

However, there must be some security feature so somebody can't waste github action minutes, etc.

Refactor tests

Refactor each testing component into its own function to easily determine what's being tested.

Valgrind reports leak

InvalidRead -> vector.c
InvalidWrite -> vector.c
Leak -> deque.c
Leak -> forward_list.c
Leak -> list.c

Rename all.h header

The all.h header has a bad name. Rename it since it provides the types for the containers. Additionally, the stdlib.h need not be included in that header.

Add functionality to access raw array for array and vector

Currently, the only way to access an array or vector like a C array is to call the to_array function. However, it is possible that a copy is not wanted, and the actual array is wanted. Thus, create a function to let the user access the actual array.

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.