0

I have my own implementation of C hash_map_t struct that I can use as below?

// string value allocator

allocator_t *str_value_allocator;
allocator_init(&str_value_allocator, string_allocate_handler, string_deallocate_handler);
str_hash_map_init(&str_hash_map, str_value_allocator, 5);

str_hash_map_put(str_hash_map, test_key, test_val, strlen(test_val));
str_hash_map_get(str_hash_map, test_key, NULL)
str_hash_map_remove(str_hash_map, test_key)

str_hash_map_free(str_hash_map);

I would like to use this hash map in function like below:

void handle_keyboard_input(char **tokens, size_t num_tokens) {

    char *virtual_key_name = strtok(tokens[1], " ");
    size_t num_flags = 0;
    char **modifier_flags = str_split(tokens[2], ", ", &num_flags);

    // map virtual_key_name (char *) to virtual_key code (int) 
    // foreach modifier flag (char *) map to modifier flag code (int) 
}

I can create 2 hash_maps for key_name -> key_code mapping and flag_name -> flag_code mapping. The problem is that I don't want to create this flag each time the request handler function is called but have only one data structure instance from first call of the function and in successive function invocations I want to reuse this data structure (data store) already created.

My hash_map is created on the heap so there isn't possibility to allocate it like the array somewhere inside library source code file.

In Java or even C++ I could create some Singleton pattern or static member but such concept is not available in C language. Probably I could create this hash_map at program startup somewhere at the beginning of program but how could I pass reference to library used by the program.

My recent idea was to use static hash_map_t variable inside my handle_keyboard_input function and somehow initialised it only when it is NULL (the first function call), and if variable isn't NULL in successive calls just reuse previously initialised hash_map_t structure.

What will be the best approach to this problem?

UPDATE

Could I use such code?

static str_hash_map_t *virtual_keys_map = NULL;
static str_hash_map_t *modifier_flags_map = NULL;

if (virtual_keys_map == NULL) {
    virtual_keys_map_init(&virtual_keys_map);
}

if (modifier_flags_map == NULL) {
    modifier_flags_map_init(&modifier_flags_map);
}
vgru
  • 49,838
  • 16
  • 120
  • 201
Michał Ziobro
  • 10,759
  • 11
  • 88
  • 143
  • A static(pointer)variable within a function is a singleton, too. Or , even simpler, a global variable. – wildplasser Aug 20 '17 at 15:11
  • So I could use such code like in my UPDATE section? – Michał Ziobro Aug 20 '17 at 15:12
  • What's the problem in allocating these structs at startup? I doesn't make sense to check for NULL before calling each separate function. It's also possible for dll libraries to expose init functions, if you want to do this automatically. – vgru Aug 20 '17 at 15:29
  • This is C library used by Cocoa App program, which starts server, and then it handle request, and then if there is request of specific type there is invocation of function, and then I should use this hash_map. I don't know how to easily initiate this hashmap previously, ( server startup) and then use it. Should I make this struct global and initiate it somewhere? How to access this pointer? – Michał Ziobro Aug 20 '17 at 17:06

2 Answers2

1

Since this appears to be a library, you have several options:

  1. You can make your library more "object oriented" and force the user to do the proper instantiation. For example, you would have your ADT struct defined as KeyboardHandler, and then your handle_keyboard_input would look something like this instead:

    void KH_handle_input(KeyboardHandler self, char **tokens, size_t num_tokens);
    

    Which means the caller is now responsible for doing the instantiation of that single part:

    // caller must get the ADT instance at some point, and you don't care when
    KeyboardHandler kh = KH_init();
    KH_handle_input(kh, some_tokens, num_tokens);
    
    // some other part can be initialized later
    MouseHandler mh = MH_init();
    MH_handle_input(mh, some_tokens, num_tokens);
    
  2. It's possible to create a library initializer for both Windows and POSIX dlls. So you can let this be done automatically instead.

  3. Otherwise, it seems like you will have to make this "check" anytime your functions want to use this potentially-uninitialized hash tables (perhaps it's a single function, but anyway). In which case, I would at least refactor it into a separate function:

    void handle_keyboard_input(char **tokens, size_t num_tokens) {
        initialize_hashes_if_needed();
        // ...and then the rest of the function            
    }
    

    The reasoning is that you don't want to have to modify several functions if you decide there is something else that needs to be malloced.

vgru
  • 49,838
  • 16
  • 120
  • 201
0

Yes, code above cause that pointers will be initialised just once (or if you set them to NULL, condition will be true and it will init again) and stay in memory even if you get outside of function.

The lifetime of function static variables begins the first time the program flow encounters the declaration and it ends at program termination - in other words they are global variables.

Also the name of this variable is only accessible within the function, and has no linkage.

Still need to take great care if you think you need a globally-accessible variable. Read here.

static str_hash_map_t *virtual_keys_map = NULL;
static str_hash_map_t *modifier_flags_map = NULL;

if(virtual_keys_map == NULL) {
    virtual_keys_map_init(&virtual_keys_map);
}
if(modifier_flags_map == NULL) {
    modifier_flags_map_init(&modifier_flags_map);
}
kocica
  • 6,412
  • 2
  • 14
  • 35