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