xref: /reactos/sdk/lib/ucrt/stdlib/bsearch.cpp (revision 04e0dc4a)
1*04e0dc4aSTimo Kreuzer //
2*04e0dc4aSTimo Kreuzer // bsearch.cpp
3*04e0dc4aSTimo Kreuzer //
4*04e0dc4aSTimo Kreuzer //      Copyright (c) Microsoft Corporation. All rights reserved.
5*04e0dc4aSTimo Kreuzer //
6*04e0dc4aSTimo Kreuzer // Defines bsearch(), which performs a binary search over an array.
7*04e0dc4aSTimo Kreuzer //
8*04e0dc4aSTimo Kreuzer #include <corecrt_internal.h>
9*04e0dc4aSTimo Kreuzer #include <search.h>
10*04e0dc4aSTimo Kreuzer 
11*04e0dc4aSTimo Kreuzer #ifdef _M_CEE
12*04e0dc4aSTimo Kreuzer     #define __fileDECL __clrcall
13*04e0dc4aSTimo Kreuzer #else
14*04e0dc4aSTimo Kreuzer     #define __fileDECL __cdecl
15*04e0dc4aSTimo Kreuzer #endif
16*04e0dc4aSTimo Kreuzer 
17*04e0dc4aSTimo Kreuzer /***
18*04e0dc4aSTimo Kreuzer *char *bsearch() - do a binary search on an array
19*04e0dc4aSTimo Kreuzer *
20*04e0dc4aSTimo Kreuzer *Purpose:
21*04e0dc4aSTimo Kreuzer *   Does a binary search of a sorted array for a key.
22*04e0dc4aSTimo Kreuzer *
23*04e0dc4aSTimo Kreuzer *Entry:
24*04e0dc4aSTimo Kreuzer *   const char *key    - key to search for
25*04e0dc4aSTimo Kreuzer *   const char *base   - base of sorted array to search
26*04e0dc4aSTimo Kreuzer *   unsigned int num   - number of elements in array
27*04e0dc4aSTimo Kreuzer *   unsigned int width - number of bytes per element
28*04e0dc4aSTimo Kreuzer *   int (*compare)()   - pointer to function that compares two array
29*04e0dc4aSTimo Kreuzer *           elements, returning neg when #1 < #2, pos when #1 > #2, and
30*04e0dc4aSTimo Kreuzer *           0 when they are equal. Function is passed pointers to two
31*04e0dc4aSTimo Kreuzer *           array elements.
32*04e0dc4aSTimo Kreuzer *
33*04e0dc4aSTimo Kreuzer *Exit:
34*04e0dc4aSTimo Kreuzer *   if key is found:
35*04e0dc4aSTimo Kreuzer *           returns pointer to occurrence of key in array
36*04e0dc4aSTimo Kreuzer *   if key is not found:
37*04e0dc4aSTimo Kreuzer *           returns nullptr
38*04e0dc4aSTimo Kreuzer *
39*04e0dc4aSTimo Kreuzer *Exceptions:
40*04e0dc4aSTimo Kreuzer *   Input parameters are validated. Refer to the validation section of the function.
41*04e0dc4aSTimo Kreuzer *
42*04e0dc4aSTimo Kreuzer *******************************************************************************/
43*04e0dc4aSTimo Kreuzer 
44*04e0dc4aSTimo Kreuzer #ifdef __USE_CONTEXT
45*04e0dc4aSTimo Kreuzer     #define __COMPARE(context, p1, p2) (*compare)(context, p1, p2)
46*04e0dc4aSTimo Kreuzer #else
47*04e0dc4aSTimo Kreuzer     #define __COMPARE(context, p1, p2) (*compare)(p1, p2)
48*04e0dc4aSTimo Kreuzer #endif
49*04e0dc4aSTimo Kreuzer 
50*04e0dc4aSTimo Kreuzer #ifndef _M_CEE
51*04e0dc4aSTimo Kreuzer extern "C"
52*04e0dc4aSTimo Kreuzer #endif
53*04e0dc4aSTimo Kreuzer 
54*04e0dc4aSTimo Kreuzer _CRT_SECURITYSAFECRITICAL_ATTRIBUTE
55*04e0dc4aSTimo Kreuzer #ifdef __USE_CONTEXT
bsearch_s(void const * const key,void const * const base,size_t num,size_t const width,int (__fileDECL * const compare)(void *,void const *,void const *),void * const context)56*04e0dc4aSTimo Kreuzer void* __fileDECL bsearch_s(
57*04e0dc4aSTimo Kreuzer     void const* const key,
58*04e0dc4aSTimo Kreuzer     void const* const base,
59*04e0dc4aSTimo Kreuzer     size_t            num,
60*04e0dc4aSTimo Kreuzer     size_t      const width,
61*04e0dc4aSTimo Kreuzer     int (__fileDECL* const compare)(void*, void const*, void const*),
62*04e0dc4aSTimo Kreuzer     void*       const context
63*04e0dc4aSTimo Kreuzer     )
64*04e0dc4aSTimo Kreuzer #else // __USE_CONTEXT
65*04e0dc4aSTimo Kreuzer void* __fileDECL bsearch(
66*04e0dc4aSTimo Kreuzer     void const* const key,
67*04e0dc4aSTimo Kreuzer     void const* const base,
68*04e0dc4aSTimo Kreuzer     size_t            num,
69*04e0dc4aSTimo Kreuzer     size_t      const width,
70*04e0dc4aSTimo Kreuzer     int (__fileDECL* const compare)(void const*, void const*)
71*04e0dc4aSTimo Kreuzer     )
72*04e0dc4aSTimo Kreuzer #endif // __USE_CONTEXT
73*04e0dc4aSTimo Kreuzer {
74*04e0dc4aSTimo Kreuzer     _VALIDATE_RETURN(base != nullptr || num == 0, EINVAL, nullptr);
75*04e0dc4aSTimo Kreuzer     _VALIDATE_RETURN(width > 0, EINVAL, nullptr);
76*04e0dc4aSTimo Kreuzer     _VALIDATE_RETURN(compare != nullptr, EINVAL, nullptr);
77*04e0dc4aSTimo Kreuzer 
78*04e0dc4aSTimo Kreuzer     char const* lo = reinterpret_cast<char const*>(base);
79*04e0dc4aSTimo Kreuzer     char const* hi = reinterpret_cast<char const*>(base) + (num - 1) * width;
80*04e0dc4aSTimo Kreuzer 
81*04e0dc4aSTimo Kreuzer     // Reentrancy diligence: Save (and unset) global-state mode to the stack before making callout to 'compare'
82*04e0dc4aSTimo Kreuzer     __crt_state_management::scoped_global_state_reset saved_state;
83*04e0dc4aSTimo Kreuzer 
84*04e0dc4aSTimo Kreuzer     // We allow a nullptr key here because it breaks some older code and because
85*04e0dc4aSTimo Kreuzer     // we do not dereference this ourselves so we can't be sure that it's a
86*04e0dc4aSTimo Kreuzer     // problem for the comparison function
87*04e0dc4aSTimo Kreuzer 
88*04e0dc4aSTimo Kreuzer     while (lo <= hi)
89*04e0dc4aSTimo Kreuzer     {
90*04e0dc4aSTimo Kreuzer         size_t const half = num / 2;
91*04e0dc4aSTimo Kreuzer         if (half != 0)
92*04e0dc4aSTimo Kreuzer         {
93*04e0dc4aSTimo Kreuzer             char const* const mid = lo + (num & 1 ? half : (half - 1)) * width;
94*04e0dc4aSTimo Kreuzer 
95*04e0dc4aSTimo Kreuzer             int const result = __COMPARE(context, key, mid);
96*04e0dc4aSTimo Kreuzer             if (result == 0)
97*04e0dc4aSTimo Kreuzer             {
98*04e0dc4aSTimo Kreuzer                 return const_cast<void*>(static_cast<void const*>(mid));
99*04e0dc4aSTimo Kreuzer             }
100*04e0dc4aSTimo Kreuzer             else if (result < 0)
101*04e0dc4aSTimo Kreuzer             {
102*04e0dc4aSTimo Kreuzer                 hi = mid - width;
103*04e0dc4aSTimo Kreuzer                 num = num & 1 ? half : half - 1;
104*04e0dc4aSTimo Kreuzer             }
105*04e0dc4aSTimo Kreuzer             else
106*04e0dc4aSTimo Kreuzer             {
107*04e0dc4aSTimo Kreuzer                 lo = mid + width;
108*04e0dc4aSTimo Kreuzer                 num = half;
109*04e0dc4aSTimo Kreuzer             }
110*04e0dc4aSTimo Kreuzer         }
111*04e0dc4aSTimo Kreuzer         else if (num != 0)
112*04e0dc4aSTimo Kreuzer         {
113*04e0dc4aSTimo Kreuzer             return __COMPARE(context, key, lo)
114*04e0dc4aSTimo Kreuzer                 ? nullptr
115*04e0dc4aSTimo Kreuzer                 : const_cast<void*>(static_cast<void const*>(lo));
116*04e0dc4aSTimo Kreuzer         }
117*04e0dc4aSTimo Kreuzer         else
118*04e0dc4aSTimo Kreuzer         {
119*04e0dc4aSTimo Kreuzer             break;
120*04e0dc4aSTimo Kreuzer         }
121*04e0dc4aSTimo Kreuzer     }
122*04e0dc4aSTimo Kreuzer 
123*04e0dc4aSTimo Kreuzer     return nullptr;
124*04e0dc4aSTimo Kreuzer }
125*04e0dc4aSTimo Kreuzer 
126*04e0dc4aSTimo Kreuzer #undef __COMPARE
127