RayList is a C library that implements a dynamic linked list supporting multiple data types, with various functions for list manipulation. It allows you to manage lists, stacks, and queues efficiently with support for custom data types and asynchronous task execution. raylist also contains magic macros to solve list C problems like (RLSetObject , RLDefer , ...)
To use RayList in your project, include the raylist.h
header file and link against the compiled library. Ensure you have the required dependencies installed. and define macro LIST_C to act like C file because the library is like stb stile header only library
// should include stdarg.h
#include
// enable raylist implementation
#define LIST_C
#include "raylist.h"
Here is a basic example of how to use RayList:
#include
#include
#define LIST_C
#include "raylist.h"
int main() {
RLList my_list = List(0); // Initialize an empty list
my_list.List_Append(RL_INT, (void*)&(int){10});
my_list.List_Append(RL_STR, "Hello, World!");
my_list.List_Print();
return 0;
}
list contains methods like in python and it's own preffix Example :
// this macro enable list preffix
#define USING_LIST
#define LIST_C
#include "raylist.h"
int main() {
RLList my_list = List(0);
// after define USING_LIST macro
my_list.Filter(callback, RL_INT); // now you can use method like this
my_list.Print();
return 0;
}
types can used in list , stack , queue this type helps raylist for memory managment
// this macro enable list preffix
#define USING_LIST
#define LIST_C
#include "raylist.h"
int main() {
// RL_INT type int
// RL_STR type str (char*)
// RL_VOIDPTR type void ptr (void*)
// RL_FLT type float
// RL_BOOL type boolean
// RL_CHR type char
// RL_STRFUNC type function return string
// RL_CHARFUNC type function return char
// RL_INTFUNC type function return int
// RL_VOIDFUNC type function return void
return 0;
}
List return RLList interface which implements all list method
list also accept va_list arguments to add data dynamicly
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(3, // 3 is number of the data we add to the list
RL_STR , "Hello", // ,
RL_BOOL , true, // .
RL_STR , "world" // .
);
return 0;
}
RLAppend macro works like append method but use generics
macro can detecte type of the data , without casting to void*
work with int , float and char only
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(0);
RLAppend(RL_INT , 1);
RLAppend(RL_INT , 2);
RLAppend(RL_INT , 3);
RLAppend(RL_CHR , 'e');
RLAppend(RL_CHR , 'h');
RLAppend(RL_FLT , 3.14f);
RLAppend(RL_FLT , 2.73f);
return 0;
}
append method takes type and data
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(0);
// U can call method append like this if you defined USING_LIST macro
mylist.Append(RL_STR , "Hello");
mylist.Append(RL_STR , "World");
// if not
mylist.List_Append(RL_STR , "Hello");
mylist.List_Append(RL_STR , "World");
return 0;
}
insert method takes index poition to add data , type and data
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(4,
RL_STR , "Hello",
RL_STR , "World",
RL_STR , "rayden",
RL_STR , "foo"
);
mylist.List_Insert(2 , RL_STR , "bar"); // insert bar str in index 2
mylist.List_Insert(0 , RL_STR , "baz"); // insert baz str in index 0
return 0;
}
search method takes int pointer type to return index of the data we search for , type of data and the data
function return boolean true if function found the data else false
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(2,
RL_STR , "Hello",
RL_STR , "World"
);
int idx;
if(mylist.List_Search(&idx , RL_STR , "World")){
printf("data found at index : %d\n" , idx);
}else{
printf("data not found \n");
}
return 0;
}
delete method takes int index the position of the data we want to delete
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(2,
RL_STR , "Hello",
RL_STR , "World"
);
// Hello data will be delete it
mylist.Del_Index(0);
return 0;
}
get method takes int index the position of the data we want to get
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(3,
RL_STR , "World",
RL_STR , "foo",
RL_STR , "bar"
);
// function will return foo
puts((char*)mylist.List_Get(1));
return 0;
}
reverse method take no argument and return nothing
reverse will reverse the list
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(3,
RL_STR , "World",
RL_STR , "foo",
RL_STR , "bar"
);
mylist.List_Reverse(); // list reverse
return 0;
}
print method take no argument and return nothing
print method will print the data in list like python3 format
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(3,
RL_STR , "World",
RL_STR , "foo",
RL_STR , "bar"
);
mylist.List_Print();
return 0;
}
get_error method take no argument and return string error , and NULL if not
while you working with raylist , library detecte errors , so after any operation
check if method return NULL or not ,
if return value is not NULL log the error
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(3,
RL_STR , "World",
RL_STR , "foo",
RL_STR , "bar"
);
char* err = mylist.List_Get_Error();
if(err != NULL){
fprintf(stderr , "[ERROR] %s" , err);
}
return 0;
}
len method take no argument and return how many data in list
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(3,
RL_STR , "World",
RL_STR , "foo",
RL_STR , "bar"
);
int len = mylist.List_Len(); // len == 3
return 0;
}
exec_sync method take index of the function , and the data (data passed to calling function argument) , and the flag
if index is less than 0 or bigger than length of list will execute all functions
Exec_Flag :
OUTT the return value from called function will returned in Exec_Sync method
OUTT flag is not enabled if index parameter in Exec_Sync was out of range
INPLACE the return value will replaced function callback index
the void function is not replaced
ADDED the function return value will added to the list
#define LIST_C
#include "raylist.h"
void foo(void){
printf("foo");
}
char* myname(char* name) {
return name;
}
int main() {
// Example Append
RLList mylist = List(2,
RL_VOIDFUNC , foo,
RL_STRFUNC , myname
);
myname.List_Exec_Sync(0 , NULL , OUTT); // void return type function don't care about flag
myname.List_Exec_Sync(1 , "rayden" , ADDED);
return 0;
}
exec_async method take index of the function , and the data (data passed to calling function argument)
if index is less than 0 or bigger than length of list will execute all functions
this function will call functions Asynchronously , this method call function iin separite thread and return interface
interface :
thread_id -> thread handler of the calling function
Kill :
* Kill function
* for killing the thread
Wait :
* Wait function
* function waits for the thread specified by thread to terminate
- both of these method takes handle thread in parameter
this method work with specific macro called RLTestCancel this macro should be called inside target function Kill method can detecte the function and kill thread
#define LIST_C
#include "raylist.h"
void limitloop(void)
{
for(int i = 0 ; i < 20 ; i++){
puts("Test");
sleep(1);
RLTestCancel();
}
}
void limitloop2(void)
{
for(int i = 0 ; i < 20 ; i++){
puts("Hello");
sleep(1);
RLTestCancel();
}
}
int main() {
// Example Append
RLList mylist = List(2,
RL_VOIDFUNC , limitloop,
RL_VOIDFUNC , limitloop2
);
IfaceThread tr = my_list.Exec_Async(3 , NULL);
IfaceThread rt = my_list.Exec_Async(4 , NULL);
RLUNUSED(tr); // unused variable
// functions now works in the same time
rt.Kill(tr.thread); // killing functionof tr interface
return 0;
}
filter method used to filter the list According to condition in callback function except void* parameter and return boolean
filter accept function call back , type for filter , and Filter_Flag
Filter_Flag :
ALL // (filtring all list)
ONLY // (filtring only type)
#define LIST_C
#include "raylist.h"
LBOOL for_filter(void* data)
{
// filtring odd numbers
if(*(int*)data % 2 != 0) return true;
return false;
}
int main() {
// Example Append
RLList mylist = List(0);
for(int i = 0 ; i < 10 ; i++)
{
RLAppend(RL_INT , i);
}
mylist.List_Filter(for_filter , RL_INT , ONLY);
// now our list contains odd numbers
// if flag was ALL other types will be delete it
return 0;
}
map method used to apply changes to the elemetn's in the list According to condition ,in callback function except void* parameter and return void*
#define LIST_C
#include "raylist.h"
void* for_map(void* data)
{
if(*(int*)data % 2 != 0){
// if data number is odd , change it to 100
*(int*)data = 100;
}
return data;
}
int main() {
// Example Append
RLList mylist = List(0);
for(int i = 0 ; i < 10 ; i++)
{
RLAppend(RL_INT , i);
}
mylist.List_Map(for_map , RL_INT);
// now all odd numbers is equale to 100
return 0;
}
clear method will free's all allocated data in list
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(0);
for(int i = 0 ; i < 10 ; i++)
{
RLAppend(RL_INT , i);
}
mylist.List_Clear(); // len list == 0
return 0;
}
both of thoes functions implements RLCollections interface this functions accept buffer limiter (can fix the size) and also you can put Buf_Disable parameter to make it dynamic RLCollections has macro RLPush this macro is generic like RLappend macro magic macros also work for this interface
RLCollections Example :
#define LIST_C
#include "raylist.h"
int main() {
// RLCollections interface
/*
* Max_Buffer() return true if buffer equal to fixed buffer else false
* */
// LBOOL Max_Buffer(void);
/*
* return true if stack is empty else false
* */
// LBOOL Is_Empty(void);
/*
* return String if the error is set true (status > 0)
* */
// string Get_Error(void);
/*
* Push function will take the data and stored to the __list__ global variable
*
* Push(
* Type : the data type
* void*: data pointer point address of stored data
* )
*
* NOTE : the append method works like push in stack algorithm
*
* Example :
* my_list.Push(RL_STR , "Hello World");
*
* */
// void Push(Type type, void* data);
/*
* Peek function return last value of the Stack (Stack)
* Example :
* void* value = my_list.Stack_Peek();
* */
// void* Peek(void);
/*
* Stack_Pop function will pop the last value from the list
*
* Example :
* void* value = my_list.Stack_Pop();
* */
// void* Pop(void);
// clear Stack
// void Clear(void);
RLCollections stack = Stack(Buf_Disable);
RLDefer(stack.Clear); // clear will be called at the end of program
for(int i = 0 ; i < 10 ; i++)
{
RLPush(RL_INT , i);
}
RLSetObject(2);
RLCollections queue = Queue(10); // queue with 10 buffer
RLPush(RL_FLT , 10.23f);
return 0;
}
defer raylist macro registers the given function to be called at normal process termination , accept callback function return type void and accept no arguments
works like defer in go
macro is atexit function from standard library
function will not work when forced with CTRL-C
#define LIST_C
#include "raylist.h"
int main() {
// Example Append
RLList mylist = List(0);
RLDefer(mylist.Clear); // clear will be called at the end of program
for(int i = 0 ; i < 10 ; i++)
{
RLAppend(RL_INT , i);
}
return 0;
}
RLSetObject macro used for multiple list storage
you can create another allocated list (linked list) RLSetObject change method access direction to pointed list
#define LIST_C
#include "raylist.h"
int main() {
RLList mylist = List(0);
RLList mysecondlist = List(0);
// default direction of methods and macros work with mylist object
for(int i = 0 ; i < 10 ; i++)
{
RLAppend(RL_INT , i);
}
// start with 1
RLSetObject(2)
//
// now all methods will work with mysecondlist object
//
return 0;
}
RLAmbda macro allows you to implements anonymouse function directly in parameter function type,
Positives :
- Avoid mixing function names
- Best choice for small functions
- She looks beautiful
also make it easier for map and filter method call back functions
RLMap(body) : you can define this call back in map method and handle the body , the default parameter is rlmapdata
RLFilter(body) : you can define this call back in filter method and handle the body , the default parameter is rlfilterdata
#include <stdio.h >
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define USING_LIST
#define LIST_C
#include "../raylist.h"
int main(void)
{
RLList list = List(0);
RLDefer(list.Clear);
RLCopyObject(RLSIZEOF(int));
for(int i = 0 ; i < 10 ; i++){
list.Append(RL_INT , (void*)&i);
}
RLDisableCopyObject();
// callback function in Filter method
list.Filter(RLFilter({
if(*(int*)rlfilterdata % 2 != 0) return false;
return true;
}) , RL_INT , ONLY);
// callback function in Map method
list.Map(RLMap({
if(*(int*)rlmapdata == 0){
*(int*)rlmapdata = 10;
}
return rlmapdata;
}) , RL_INT);
list.Print();
return 0;
}
RLCopyObject allow raylist to copy the target object instead of pointing his memory
raylist by default point address variables and this creates problems if the target object can be NULL or data changes
in same object
#define LIST_C
#include "raylist.h"
int main() {
RLList mylist = List(0);
RLCopyObject(sizeof(int)) // macro accept size of the copy object
for(int i = 0 ; i < 10 ; i++)
{
mylist.List_Append(RL_INT , (void*)&i);
}
RLDisableCopyObject();
// the list result is not [9,9,9,9,9,9,9,9,9] , it's [0,1,2,3,4,5,6,7,8,9]
return 0;
}