Skip to content

Commit 8b66739

Browse files
committed
Added traditional linear search algorithm for unsorted vectors
1 parent 3a68e9e commit 8b66739

File tree

3 files changed

+164
-64
lines changed

3 files changed

+164
-64
lines changed

.vscode/c_cpp_properties.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"/Library/Developer/CommandLineTools/usr/include/",
3030
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include",
3131
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
32-
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks"
32+
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks",
33+
"/Library/Developer/CommandLineTools/usr/lib/clang/14.0.3/include"
3334
],
3435
"defines": [],
3536
"macFrameworkPath": [

src/zvector.c

+139-63
Original file line numberDiff line numberDiff line change
@@ -1671,10 +1671,14 @@ zvect_retval vect_sem_post(ivector v) {
16711671
}
16721672

16731673
/*
1674+
TODO: Implement this function:
1675+
16741676
static inline zvect_retval p_vect_wait_for_signal(const vector v) {
16751677
return (locking_disabled || (v->flags & ZV_NOLOCKING)) ? 1 : wait_for_signal(v, 3);
16761678
}
16771679
1680+
and also:
1681+
16781682
inline zvect_retval vect_wait_for_signal(const vector v) {
16791683
return p_vect_wait_for_signal(v);
16801684
}
@@ -2468,6 +2472,90 @@ void vect_qsort(ivector v, int (*compare_func)(const void *, const void *)) {
24682472
p_throw_error(rval, NULL);
24692473
}
24702474

2475+
#ifdef TRADITIONAL_BINARY_SEARCH
2476+
static bool p_standard_binary_search(vector v, const void *key,
2477+
zvect_index *item_index,
2478+
int (*f1)(const void *, const void *));
2479+
#else
2480+
static bool p_adaptive_binary_search(ivector v, const void *key,
2481+
zvect_index *item_index,
2482+
int (*f1)(const void *, const void *));
2483+
#endif
2484+
2485+
/*
2486+
* Although if the vect_add_* doesn't belong to this group of
2487+
* functions, the vect_add_ordered is an exception because it
2488+
* requires vect_bserach and vect_qsort to be available.
2489+
*/
2490+
void vect_add_ordered(ivector v, const void *value,
2491+
int (*f1)(const void *, const void *)) {
2492+
// Check parameters:
2493+
if (value == NULL)
2494+
return;
2495+
2496+
// check if the vector exists:
2497+
zvect_retval rval = p_vect_check(v);
2498+
if (rval)
2499+
goto VECT_ADD_ORD_JOB_DONE;
2500+
2501+
#if (ZVECT_THREAD_SAFE == 1)
2502+
zvect_retval lock_owner = (locking_disabled || (v->flags & ZV_NOLOCKING)) ? 0 : get_mutex_lock(v, 2);
2503+
#endif
2504+
2505+
// Few tricks to make it faster:
2506+
zvect_index vsize = p_vect_size(v);
2507+
if (vsize == 0) {
2508+
// If the vector is empty clearly we can just
2509+
// use vect_add and add the value normally!
2510+
vect_add(v, value);
2511+
goto VECT_ADD_ORD_DONE_PROCESSING;
2512+
}
2513+
2514+
if ((*f1)(value, v->data[v->begin + (vsize - 1)]) > 0) {
2515+
// If the compare function returns that
2516+
// the value passed should go after the
2517+
// last value in the vector, just do so!
2518+
vect_add(v, value);
2519+
goto VECT_ADD_ORD_DONE_PROCESSING;
2520+
}
2521+
2522+
// Ok previous checks didn't help us, so we need
2523+
// to get "heavy weapons" out and find where in
2524+
// the vector we should add "value":
2525+
zvect_index item_index = 0;
2526+
2527+
// Here is another trick:
2528+
// I improved adaptive binary search to ALWAYS
2529+
// return an index (even when it doesn't find a
2530+
// searched item), this works for both: regular
2531+
// searches which will also use the bool to
2532+
// know if we actually found the item in that
2533+
// item_index or not and the vect_add_ordered
2534+
// which will use item_index (which will be the
2535+
// place where value should have been) to insert
2536+
// value as an ordered item :)
2537+
#ifdef TRADITIONAL_BINARY_SEARCH
2538+
p_standard_binary_search(v, value, &item_index, f1);
2539+
#else
2540+
p_adaptive_binary_search(v, value, &item_index, f1);
2541+
#endif
2542+
2543+
vect_add_at(v, value, item_index);
2544+
2545+
VECT_ADD_ORD_DONE_PROCESSING:
2546+
#if (ZVECT_THREAD_SAFE == 1)
2547+
if (lock_owner)
2548+
get_mutex_unlock(v, 2);
2549+
#endif
2550+
2551+
VECT_ADD_ORD_JOB_DONE:
2552+
if(rval)
2553+
p_throw_error(rval, NULL);
2554+
}
2555+
2556+
2557+
// Searching Algorithms:
2558+
24712559
#ifdef TRADITIONAL_BINARY_SEARCH
24722560
static bool p_standard_binary_search(vector v, const void *key,
24732561
zvect_index *item_index,
@@ -2521,7 +2609,7 @@ static bool p_adaptive_binary_search(ivector v, const void *key,
25212609
bot = v->bottom;
25222610
top = 32;
25232611

2524-
// key >= array[bot]
2612+
// the following evaluation correspond to: key >= array[bot]
25252613
if ((*f1)(key, v->data[v->begin + bot]) >= 0) {
25262614
while (1) {
25272615
if ((bot + top) >= p_vect_size(v)) {
@@ -2530,7 +2618,7 @@ static bool p_adaptive_binary_search(ivector v, const void *key,
25302618
}
25312619
bot += top;
25322620

2533-
// the meaning of the line below is key < array[bot]
2621+
// the meaning of the line below is: key < array[bot]
25342622
if ((*f1)(key, v->data[v->begin + bot]) < 0) {
25352623
bot -= top;
25362624
break;
@@ -2546,7 +2634,7 @@ static bool p_adaptive_binary_search(ivector v, const void *key,
25462634
}
25472635
bot -= top;
25482636

2549-
// the meaning of the line below is key >= array[bot]
2637+
// the meaning of the line below is: key >= array[bot]
25502638
if ((*f1)(key, v->data[v->begin + bot]) >= 0)
25512639
break;
25522640
top *= 2;
@@ -2556,7 +2644,7 @@ static bool p_adaptive_binary_search(ivector v, const void *key,
25562644
P_ADP_BSEARCH_MONOBOUND:
25572645
while (top > 3) {
25582646
mid = top / 2;
2559-
// key >= array[bot + mid]
2647+
// the meaning of the following statement is: key >= array[bot + mid]
25602648
if ((*f1)(key, v->data[v->begin + (bot + mid)]) >= 0)
25612649
bot += mid;
25622650
top -= mid;
@@ -2566,7 +2654,7 @@ static bool p_adaptive_binary_search(ivector v, const void *key,
25662654
v->bottom = bot;
25672655

25682656
while (top) {
2569-
// key == array[bot + --top]
2657+
// the meaning of the following statement is: key == array[bot + --top]
25702658
int test = (*f1)(key, v->data[v->begin + (bot + (--top))]);
25712659
if (test == 0) {
25722660
*item_index = bot + top;
@@ -2580,16 +2668,17 @@ static bool p_adaptive_binary_search(ivector v, const void *key,
25802668
*item_index = bot + top;
25812669
return false;
25822670
}
2583-
#endif // ! TRADITIONAL_BINARY_SEARCH
2671+
#endif // ADAPTIVE TRADITIONAL_BINARY_SEARCH
25842672

25852673
bool vect_bsearch(ivector v, const void *key,
25862674
int (*f1)(const void *, const void *),
25872675
zvect_index *item_index) {
2676+
*item_index = 0;
2677+
25882678
// Check parameters:
25892679
if ((key == NULL) || (f1 == NULL) || (p_vect_size(v) == 0))
25902680
return false;
25912681

2592-
*item_index = 0;
25932682
// check if the vector exists:
25942683
zvect_retval rval = p_vect_check(v);
25952684
if (rval)
@@ -2612,7 +2701,7 @@ bool vect_bsearch(ivector v, const void *key,
26122701
*item_index = 0;
26132702
return false;
26142703
}
2615-
#endif // ! TRADITIONAL_BINARY_SEARCH
2704+
#endif // ADAPTIVE TRADITIONAL_BINARY_SEARCH
26162705

26172706
// VECT_BSEARCH_DONE_PROCESSING:
26182707
// TODO: Add mutex unlock
@@ -2624,71 +2713,58 @@ bool vect_bsearch(ivector v, const void *key,
26242713
return false;
26252714
}
26262715

2627-
/*
2628-
* Although if the vect_add_* doesn't belong to this group of
2629-
* functions, the vect_add_ordered is an exception because it
2630-
* requires vect_bserach and vect_qsort to be available.
2631-
*/
2632-
void vect_add_ordered(ivector v, const void *value,
2633-
int (*f1)(const void *, const void *)) {
2716+
// Traditional Linear Search Algorithm,
2717+
// useful with non sorted vectors:
2718+
bool vect_lsearch(ivector v, const void *key,
2719+
int (*f1)(const void *, const void *),
2720+
zvect_index *item_index) {
2721+
*item_index = 0;
2722+
26342723
// Check parameters:
2635-
if (value == NULL)
2636-
return;
2724+
if ((key == NULL) || (f1 == NULL) || (p_vect_size(v) == 0))
2725+
return false;
26372726

26382727
// check if the vector exists:
26392728
zvect_retval rval = p_vect_check(v);
26402729
if (rval)
2641-
goto VECT_ADD_ORD_JOB_DONE;
2642-
2643-
#if (ZVECT_THREAD_SAFE == 1)
2644-
zvect_retval lock_owner = (locking_disabled || (v->flags & ZV_NOLOCKING)) ? 0 : get_mutex_lock(v, 2);
2645-
#endif
2730+
goto VECT_LSEARCH_JOB_DONE;
26462731

2647-
// Few tricks to make it faster:
2732+
// TODO: Add mutex locking
26482733
zvect_index vsize = p_vect_size(v);
2649-
if (vsize == 0) {
2650-
// If the vector is empty clearly we can just
2651-
// use vect_add and add the value normally!
2652-
vect_add(v, value);
2653-
goto VECT_ADD_ORD_DONE_PROCESSING;
2654-
}
2655-
2656-
if ((*f1)(value, v->data[v->begin + (vsize - 1)]) > 0) {
2657-
// If the compare function returns that
2658-
// the value passed should go after the
2659-
// last value in the vector, just do so!
2660-
vect_add(v, value);
2661-
goto VECT_ADD_ORD_DONE_PROCESSING;
2734+
if ((vsize & (1<<0))==0 && (vsize>4)) {
2735+
for (register zvect_index x=0; x<vsize; x+=4) {
2736+
if ((*f1)(key, v->data[v->begin + x]) != 0) {
2737+
*item_index = x;
2738+
return true;
2739+
}
2740+
if ((*f1)(key, v->data[v->begin + (x+1)]) != 0) {
2741+
*item_index = x;
2742+
return true;
2743+
}
2744+
if ((*f1)(key, v->data[v->begin + (x+2)]) != 0) {
2745+
*item_index = x;
2746+
return true;
2747+
}
2748+
if ((*f1)(key, v->data[v->begin + (x+3)]) != 0) {
2749+
*item_index = x;
2750+
return true;
2751+
}
2752+
}
2753+
} else {
2754+
for (register zvect_index x=0; x<vsize; x++) {
2755+
if ((*f1)(key, v->data[v->begin + x]) != 0) {
2756+
*item_index = x;
2757+
return true;
2758+
}
2759+
}
26622760
}
26632761

2664-
// Ok previous checks didn't help us, so we need
2665-
// to get "heavy weapons" out and find where in
2666-
// the vector we should add "value":
2667-
zvect_index item_index = 0;
2668-
2669-
// Here is another trick:
2670-
// I improved adaptive binary search to ALWAYS
2671-
// return an index (even when it doesn't find a
2672-
// searched item), this works for both: regular
2673-
// searches which will also use the bool to
2674-
// know if we actually found the item in that
2675-
// item_index or not and the vect_add_ordered
2676-
// which will use item_index (which will be the
2677-
// place where value should have been) to insert
2678-
// value as an ordered item :)
2679-
p_adaptive_binary_search(v, value, &item_index, f1);
2680-
2681-
vect_add_at(v, value, item_index);
2682-
2683-
VECT_ADD_ORD_DONE_PROCESSING:
2684-
#if (ZVECT_THREAD_SAFE == 1)
2685-
if (lock_owner)
2686-
get_mutex_unlock(v, 2);
2687-
#endif
2688-
2689-
VECT_ADD_ORD_JOB_DONE:
2690-
if(rval)
2762+
VECT_LSEARCH_JOB_DONE:
2763+
if (rval)
26912764
p_throw_error(rval, NULL);
2765+
2766+
*item_index = 0;
2767+
return false;
26922768
}
26932769

26942770
#endif // ZVECT_DMF_EXTENSIONS

src/zvector.h

+23
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,29 @@ void vect_qsort(vector const v, int (*compare_func)(const void *, const void*));
496496
*/
497497
bool vect_bsearch(vector const v, const void *key, int (*f1)(const void *, const void *), zvect_index *item_index);
498498

499+
/*
500+
* vect_lsearch is a function that allows to perform
501+
* traditional linear search over an ordered or not
502+
* ordered vector. If the vector size is a multiple of
503+
* 2 the fuction optimize the traditional loop using
504+
* 4 unrolled consecutive searches, while if the vector
505+
* size is odd it uses traditional loop (for now).
506+
*
507+
* It finds the item "key" using the comparison function
508+
* "f1", which has to be provided by the user as a pointer
509+
* to a user-written comparison function that accept the
510+
* vector's items (as defined by the user).
511+
*
512+
* For example to search for the number 5 in a vector
513+
* called v using a compare function called "my_compare"
514+
* use:
515+
* int i = 5;
516+
* vect_lsearch(v, &i, my_compare);
517+
*/
518+
bool vect_lsearch(ivector v, const void *key,
519+
int (*f1)(const void *, const void *),
520+
zvect_index *item_index);
521+
499522
/*
500523
* vect_add_ordered allows the insertion of new items in
501524
* an ordered fashion. Please note that for this to work

0 commit comments

Comments
 (0)