Repository: numpy/numpy
File: numpy/_core/src/multiarray/stringdtype/dtype.c (C)

Code before:
                // numpy treats NaN as truthy, following python
                return 1;
            }
            else {
                return 0;
            }
        }
    }
    return NpyString_size((npy_packed_static_string *)data) != 0;
}

// Implementation of PyArray_CompareFunc.
// Compares unicode strings by their code points.
int
compare(void *a, void *b, void *arr)
{
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)PyArray_DESCR(arr);
    // acquire the allocator here but let _compare get its own reference via
    // descr so we can assume in _compare that the mutex is already acquired
    NpyString_acquire_allocator(descr);
    int ret = _compare(a, b, descr, descr);
    NpyString_release_allocator(descr->allocator);
    return ret;
}

int
_sort_compare(const void *a, const void *b, void *context)
{
    PyArrayMethod_Context *sort_context = (PyArrayMethod_Context *)context;
    PyArray_StringDTypeObject *sdescr =
        (PyArray_StringDTypeObject *)sort_context->descriptors[0];

    int ret = _compare((void *)a, (void *)b, sdescr, sdescr);
    return ret;
}

// We assume the allocator mutex is already held.
int
_compare(void *a, void *b, PyArray_StringDTypeObject *descr_a,
         PyArray_StringDTypeObject *descr_b)
{
    npy_string_allocator *allocator_a = descr_a->allocator;
    npy_string_allocator *allocator_b = descr_b->allocator;
    // descr_a and descr_b are either the same object or objects
    // that are equal, so we can safely refer only to descr_a.
    // This is enforced in the resolve_descriptors for comparisons
    //
    // Note that even though the default_string isn't checked in comparisons,
    // it will still be the same for both descrs because the value of
    // default_string is always the empty string unless na_object is a string.
    int has_null = descr_a->na_object != NULL;

Review comment (suggestion):
Good to add the comment! 

Nitpicky suggestion - does it make sense to define `_sort_compare` after `_compare`, given that it needs `_compare` but not vice versa? Or even together with `stringdtype_wrap_sort_loop` (in that case, repeat the comment...)

Code after:
                // numpy treats NaN as truthy, following python
                return 1;
            }
            else {
                return 0;
            }
        }
    }
    return NpyString_size((npy_packed_static_string *)data) != 0;
}

// Implementation of PyArray_CompareFunc.
// Compares unicode strings by their code points.
int
compare(void *a, void *b, void *arr)
{
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)PyArray_DESCR(arr);
    // acquire the allocator here but let _compare get its own reference via
    // descr so we can assume in _compare that the mutex is already acquired
    NpyString_acquire_allocator(descr);
    int ret = _compare(a, b, descr, descr);
    NpyString_release_allocator(descr->allocator);
    return ret;
}

// We assume the allocator mutex is already held.
int
_compare(void *a, void *b, PyArray_StringDTypeObject *descr_a,
         PyArray_StringDTypeObject *descr_b)
{
    npy_string_allocator *allocator_a = descr_a->allocator;
    npy_string_allocator *allocator_b = descr_b->allocator;
    // descr_a and descr_b are either the same object or objects
    // that are equal, so we can safely refer only to descr_a.
    // This is enforced in the resolve_descriptors for comparisons
    //
    // Note that even though the default_string isn't checked in comparisons,
    // it will still be the same for both descrs because the value of
    // default_string is always the empty string unless na_object is a string.
    int has_null = descr_a->na_object != NULL;
    int has_string_na = descr_a->has_string_na;
    int has_nan_na = descr_a->has_nan_na;
    npy_static_string *default_string = &descr_a->default_string;
    const npy_packed_static_string *ps_a = (npy_packed_static_string *)a;
    npy_static_string s_a = {0, NULL};
    int a_is_null = NpyString_load(allocator_a, ps_a, &s_a);
    const npy_packed_static_string *ps_b = (npy_packed_static_string *)b;
    npy_static_string s_b = {0, NULL};
    int b_is_null = NpyString_load(allocator_b, ps_b, &s_b);
    if (NPY_UNLIKELY(a_is_null == -1 || b_is_null == -1)) {
        char *msg = "Failed to load string in string comparison";