[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] *-map, *-omap: Allow passing NULL to search
From: |
Bruno Haible |
Subject: |
Re: [PATCH] *-map, *-omap: Allow passing NULL to search |
Date: |
Mon, 11 Feb 2019 02:32:11 +0100 |
User-agent: |
KMail/5.1.3 (Linux/4.4.0-141-generic; KDE/5.18.0; x86_64; ; ) |
Hi Colin,
> It's sometimes convenient to have a map whose values may be NULL, but in
> that case it's a little awkward to determine whether a key exists in the
> map: gl_map_get returns NULL for both "key not found" and "value is
> NULL", so one needs a local variable just for the purpose of passing its
> address to gl_map_search.
Yes. You can consider it "a little awkward", and you can get away with it
through an inline function like this:
static bool
gl_map_entry_exists (gl_map_t map, const void *key)
{
const void *value;
return gl_map_search (map, key, &value);
}
> Instead, allow the return pointers to be NULL, so that one can use
> gl_map_search (map, NULL, NULL) to check existence.
What you propose is MORE awkward, for two reasons:
1) For this code, performance is relevant.
On modern processors, conditional jumps are significantly more
costly than a simple instruction on values and addresses in the
cache. (Something like between 5 and 20 cycles, when a single
elementary arithmetic or load/store instruction is 1 cycle.)
Why? Because modern processors are pipelined, and a conditional jump
stalls the pipeline. Or, in processors which have speculative execution,
when there are more conditional jumps, the speculative execution
depth is obviously reduced.
So, allocating a variable on the stack, filling it, and then ignoring
its value is FASTER than a conditional jump whose effect is to save
1 store instruction.
You'll also notice that this is why I wrote
GL_MAP_INLINE const void *
gl_map_get (gl_map_t map, const void *key)
{
const void *value = NULL;
gl_map_search (map, key, &value);
return value;
}
and not
GL_MAP_INLINE const void *
gl_map_get (gl_map_t map, const void *key)
{
const void *value;
if (gl_map_search (map, key, &value)
return value;
else
return NULL;
}
2) Allowing NULL pointers as arguments in all possible places is
*not* a good coding style in general. (It may be a good practice,
though, when you're being paid for a consulting project and your
code will never be maintained once you have delivered it.)
A large portion of these NULL checks is redundant; it clutters
up the code and triggers conditional jumps. Additionally, it
increases the burden of unit-testing the code.
It can be discussed whether the public API gl_map.h and gl_omap.h
should include functions like gl_map_entry_exists. Some people (like
the GNOME glib authors) attempt to provide all possible variants that
might some day be useful. Whereas I chose to provide a set of functions
that is not so large, and omit functions that can be implemented by the
user in a straightforward way. (gl_map_get is a notable exception to
this rule.) gl_map_entry_exists is clearly part of those functions
that users can implement themselves.
Bruno