github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/utils/hash64.c (about)

     1  /*
     2   * Copyright (c) 2013 Intel Corporation
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *     http://www.apache.org/licenses/LICENSE-2.0
     8   * Unless required by applicable law or agreed to in writing, software
     9   * distributed under the License is distributed on an "AS IS" BASIS,
    10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11   * See the License for the specific language governing permissions and
    12   * limitations under the License.
    13   */
    14  
    15  #include <vmm_defs.h>
    16  #include <heap.h>
    17  #include <hash64_api.h>
    18  #include <common_libc.h>
    19  #include <vmm_dbg.h>
    20  #include "hash64.h"
    21  #include "file_codes.h"
    22  
    23  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(HASH64_C)
    24  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(HASH64_C, __condition)
    25  
    26  INLINE void* hash64_uint64_to_ptr(UINT64 value) {
    27      return (void*)(value);
    28  }
    29  
    30  INLINE UINT64 hash64_ptr_to_uint64(void* ptr) {
    31      return (UINT64)ptr;
    32  }
    33  
    34  INLINE void* hash64_allocate_node(HASH64_TABLE* hash) {
    35      HASH64_NODE_ALLOCATION_FUNC node_alloc_func = hash64_get_node_alloc_func(hash);
    36      void* context = hash64_get_allocation_deallocation_context(hash);
    37  
    38      return node_alloc_func(context);
    39  }
    40  
    41  INLINE void hash64_free_node(HASH64_TABLE* hash, void* data) {
    42      HASH64_NODE_DEALLOCATION_FUNC node_dealloc_func = hash64_get_node_dealloc_func(hash);
    43      void* context = hash64_get_allocation_deallocation_context(hash);
    44  
    45      node_dealloc_func(context, data);
    46  }
    47  
    48  INLINE void* hash64_mem_alloc(HASH64_TABLE* hash, UINT32 size) {
    49      HASH64_INTERNAL_MEM_ALLOCATION_FUNC mem_alloc_func = hash64_get_mem_alloc_func(hash);
    50      if (mem_alloc_func == NULL) {
    51          return vmm_memory_alloc(size);
    52      }
    53      else {
    54          return mem_alloc_func(size);
    55      }
    56  }
    57  
    58  INLINE void hash64_mem_free(HASH64_TABLE* hash, void* data) {
    59      HASH64_INTERNAL_MEM_DEALLOCATION_FUNC mem_dealloc_func = hash64_get_mem_dealloc_func(hash);
    60      if (mem_dealloc_func == NULL) {
    61          vmm_memory_free(data);
    62      }
    63      else {
    64          mem_dealloc_func(data);
    65      }
    66  }
    67  
    68  static HASH64_NODE** hash64_retrieve_appropriate_array_cell(
    69                              HASH64_TABLE* hash, UINT64 key) {
    70      HASH64_FUNC hash_func;
    71      UINT32 cell_index;
    72      HASH64_NODE** array;
    73  
    74      hash_func = hash64_get_hash_func(hash);
    75      cell_index = hash_func(key, hash64_get_hash_size(hash));
    76      array = hash64_get_array(hash);
    77      return &(array[cell_index]);
    78  }
    79  
    80  static HASH64_NODE* hash64_find(HASH64_TABLE* hash,
    81                           UINT64 key) {
    82      HASH64_NODE** cell;
    83      HASH64_NODE* node;
    84  
    85      cell = hash64_retrieve_appropriate_array_cell(hash, key);
    86      node = *cell;
    87  
    88      while (node != NULL) {
    89          if (hash64_node_get_key(node) == key) {
    90              break;
    91          }
    92          node = hash64_node_get_next(node);
    93      }
    94      return node;
    95  }
    96  
    97  static BOOLEAN hash64_insert_internal(HASH64_TABLE* hash,
    98                      UINT64 key, UINT64 value, BOOLEAN update_when_found) {
    99      HASH64_NODE* node = NULL;
   100  
   101      if (update_when_found) {
   102          node = hash64_find(hash, key);
   103      }
   104      else {
   105          // The key should not exist
   106          // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   107          VMM_ASSERT(hash64_find(hash, key) == NULL);
   108      }
   109  
   110      if (node == NULL) {
   111          HASH64_NODE** cell;
   112  
   113          node = hash64_allocate_node(hash);
   114          if (node == NULL) {
   115             return FALSE;
   116          }
   117          cell = hash64_retrieve_appropriate_array_cell(hash, key);
   118  
   119          hash64_node_set_next(node, *cell);
   120          *cell = node;
   121  
   122          hash64_node_set_key(node, key);
   123  
   124          hash64_inc_element_count(hash);
   125      }
   126      else {
   127          // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   128          VMM_ASSERT(hash64_node_get_key(node) == key);
   129      }
   130      hash64_node_set_value(node, value);
   131      VMM_ASSERT(hash64_find(hash, key) != NULL);
   132      return TRUE;
   133  }
   134  
   135  static HASH64_HANDLE hash64_create_hash_internal(
   136              HASH64_FUNC hash_func,
   137              HASH64_INTERNAL_MEM_ALLOCATION_FUNC mem_alloc_func,
   138              HASH64_INTERNAL_MEM_DEALLOCATION_FUNC mem_dealloc_func,
   139              HASH64_NODE_ALLOCATION_FUNC node_alloc_func,
   140              HASH64_NODE_DEALLOCATION_FUNC node_dealloc_func,
   141              void* node_allocation_deallocation_context,
   142              UINT32 hash_size, BOOLEAN is_multiple_values_hash) {
   143      HASH64_TABLE* hash;
   144      HASH64_NODE** array;
   145      UINT32 index;
   146  
   147      if (mem_alloc_func == NULL) {
   148          hash = (HASH64_TABLE*)vmm_memory_alloc(sizeof(HASH64_TABLE));
   149      }
   150      else {
   151          hash = (HASH64_TABLE*)mem_alloc_func(sizeof(HASH64_TABLE));
   152      }
   153  
   154      if (hash == NULL) {
   155          goto hash_allocation_failed;
   156      }
   157  
   158      if (mem_alloc_func == NULL) {
   159          array = (HASH64_NODE**)vmm_memory_alloc(sizeof(HASH64_NODE*) * hash_size);
   160      }
   161      else {
   162          array = (HASH64_NODE**)mem_alloc_func(sizeof(HASH64_NODE*) * hash_size);
   163      }
   164  
   165      if (array == NULL) {
   166          goto array_allocation_failed;
   167      }
   168      for (index = 0; index < hash_size; index++) {
   169          array[index] = NULL;
   170      }
   171  
   172      // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   173      VMM_ASSERT(node_alloc_func != NULL);
   174      // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   175      VMM_ASSERT(node_dealloc_func != NULL);
   176  
   177      hash64_set_hash_size(hash, hash_size);
   178      hash64_set_array(hash, array);
   179      // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   180      VMM_ASSERT(hash_func != NULL);
   181      hash64_set_hash_func(hash, hash_func);
   182      hash64_set_mem_alloc_func(hash, mem_alloc_func);
   183      hash64_set_mem_dealloc_func(hash, mem_dealloc_func);
   184      hash64_set_node_alloc_func(hash, node_alloc_func);
   185      hash64_set_node_dealloc_func(hash, node_dealloc_func);
   186      hash64_set_allocation_deallocation_context(hash, node_allocation_deallocation_context);
   187      hash64_clear_element_count(hash);
   188      if (is_multiple_values_hash) {
   189          hash64_set_multiple_values_hash(hash);
   190      }
   191      else {
   192          hash64_set_single_value_hash(hash);
   193      }
   194      return (HASH64_HANDLE)hash;
   195  
   196  array_allocation_failed:
   197      // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   198      VMM_ASSERT(hash != NULL);
   199      if (mem_dealloc_func == NULL) {
   200          vmm_memory_free(hash);
   201      }
   202      else {
   203          mem_dealloc_func(hash);
   204      }
   205  hash_allocation_failed:
   206      return HASH64_INVALID_HANDLE;
   207  }
   208  
   209  static void hash64_destroy_hash_internal(HASH64_TABLE* hash) {
   210          HASH64_INTERNAL_MEM_DEALLOCATION_FUNC mem_dealloc_func;
   211          HASH64_NODE_DEALLOCATION_FUNC node_dealloc_func;
   212          HASH64_NODE** array;
   213          UINT32 i;
   214  
   215      array = hash64_get_array(hash);
   216      mem_dealloc_func = hash64_get_mem_dealloc_func(hash);
   217      node_dealloc_func = hash64_get_node_dealloc_func(hash);
   218      for (i = 0; i < hash64_get_hash_size(hash); i++) {
   219          HASH64_NODE* node = array[i];
   220  
   221          if (hash64_get_element_count(hash) == 0) {
   222              VMM_ASSERT(node == NULL);
   223              break;
   224          }
   225  
   226          while (node != NULL) {
   227              HASH64_NODE* next_node = hash64_node_get_next(node);
   228  
   229              VMM_ASSERT(hash64_get_element_count(hash) != 0);
   230  
   231              if (hash64_is_multiple_values_hash(hash)) {
   232                  UINT64 node_value = hash64_node_get_value(node);
   233                  HASH64_NODE* internal_node = (HASH64_NODE*)hash64_uint64_to_ptr(node_value);
   234                  while (internal_node != NULL) {
   235                      HASH64_NODE* next_internal_node = hash64_node_get_next(internal_node);
   236                      node_dealloc_func(hash64_get_allocation_deallocation_context(hash), internal_node);
   237                      internal_node = next_internal_node;
   238                  }
   239              }
   240              node_dealloc_func(hash64_get_allocation_deallocation_context(hash), node);
   241              hash64_dec_element_count(hash);
   242              node = next_node;
   243          }
   244      }
   245  
   246      VMM_ASSERT(hash64_get_element_count(hash) == 0);
   247  
   248      if (mem_dealloc_func == NULL) {
   249          vmm_memory_free(array);
   250          vmm_memory_free(hash);
   251      }
   252      else {
   253          mem_dealloc_func(array);
   254          mem_dealloc_func(hash);
   255      }
   256  }
   257  
   258  
   259  UINT32 hash64_get_node_size(void) {
   260      return sizeof(HASH64_NODE);
   261  }
   262  
   263  HASH64_HANDLE hash64_create_hash( HASH64_FUNC hash_func,
   264                      HASH64_INTERNAL_MEM_ALLOCATION_FUNC mem_alloc_func,
   265                      HASH64_INTERNAL_MEM_DEALLOCATION_FUNC mem_dealloc_func,
   266                      HASH64_NODE_ALLOCATION_FUNC node_alloc_func,
   267                      HASH64_NODE_DEALLOCATION_FUNC node_dealloc_func,
   268                      void* node_allocation_deallocation_context,
   269                      UINT32 hash_size) {
   270      return hash64_create_hash_internal(hash_func, mem_alloc_func, 
   271                      mem_dealloc_func, node_alloc_func, node_dealloc_func,
   272                      node_allocation_deallocation_context, hash_size, FALSE);
   273  }
   274  
   275  void hash64_destroy_hash(HASH64_HANDLE hash_handle) {
   276      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   277  
   278      VMM_ASSERT(!hash64_is_multiple_values_hash(hash));
   279      hash64_destroy_hash_internal(hash);
   280  }
   281  
   282  UINT32 hash64_default_hash_func(UINT64 key, UINT32 size)
   283  {
   284      return (UINT32)(key % size);
   285  }
   286  
   287  #pragma warning (push)
   288  #pragma warning (disable : 4100)
   289  
   290  void* hash64_default_node_alloc_func(void* context UNUSED)
   291  {
   292      return vmm_memory_alloc(hash64_get_node_size());
   293  }
   294  
   295  void hash64_default_node_dealloc_func(void* context UNUSED, void* data)
   296  {
   297      vmm_memory_free(data);
   298  }
   299  
   300  #pragma warning (pop)
   301  
   302  
   303  HASH64_HANDLE hash64_create_default_hash(UINT32 hash_size)
   304  {
   305      return hash64_create_hash(hash64_default_hash_func, NULL, NULL,
   306                                hash64_default_node_alloc_func, hash64_default_node_dealloc_func,
   307                                NULL, hash_size);
   308  }
   309  
   310  BOOLEAN hash64_lookup(HASH64_HANDLE hash_handle, UINT64 key, UINT64* value) {
   311      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   312      HASH64_NODE* node;
   313  
   314      if (hash == NULL) {
   315          return FALSE;
   316      }
   317      node = hash64_find(hash, key);
   318      if (node != NULL) {
   319          VMM_ASSERT(hash64_node_get_key(node) == key);
   320          *value = hash64_node_get_value(node);
   321          return TRUE;
   322      }
   323      return FALSE;
   324  }
   325  
   326  BOOLEAN hash64_insert(HASH64_HANDLE hash_handle,
   327                       UINT64 key, UINT64 value) {
   328      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   329  
   330      if (hash == NULL) {
   331          return FALSE;
   332      }
   333      return hash64_insert_internal(hash, key, value, FALSE);
   334  }
   335  
   336  BOOLEAN hash64_update(HASH64_HANDLE hash_handle,
   337                       UINT64 key, UINT64 value) {
   338      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   339  
   340      if (hash == NULL) {
   341          return FALSE;
   342      }
   343      return hash64_insert_internal(hash, key, value, TRUE);
   344  }
   345  
   346  BOOLEAN hash64_remove(HASH64_HANDLE hash_handle,
   347                       UINT64 key) {
   348      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   349      HASH64_NODE* node;
   350      HASH64_NODE** cell;
   351  
   352      if (hash == NULL) {
   353          return FALSE;
   354      }
   355      VMM_ASSERT(hash64_find(hash, key) != NULL);
   356      cell = hash64_retrieve_appropriate_array_cell(hash, key);
   357      node = *cell;
   358      if (node == NULL) {
   359          return FALSE;
   360      }
   361      if (hash64_node_get_key(node) == key) {
   362          *cell = hash64_node_get_next(node);
   363          VMM_ASSERT(hash64_find(hash, key) == NULL);
   364          hash64_free_node(hash, node);
   365          VMM_ASSERT(hash64_get_element_count(hash) > 0);
   366          hash64_dec_element_count(hash);
   367          return TRUE;
   368      }
   369  
   370      while(node != NULL) {
   371          HASH64_NODE* prev_node = node;
   372          node = hash64_node_get_next(node);
   373  
   374          if ((node != NULL) &&
   375              (hash64_node_get_key(node) == key)) {
   376              hash64_node_set_next(prev_node, hash64_node_get_next(node));
   377              VMM_ASSERT(hash64_find(hash, key) == NULL);
   378              hash64_free_node(hash, node);
   379              VMM_ASSERT(hash64_get_element_count(hash) > 0);
   380              hash64_dec_element_count(hash);
   381              return TRUE;
   382          }
   383      }
   384      return FALSE;
   385  }
   386  
   387  BOOLEAN hash64_is_empty(HASH64_HANDLE hash_handle) {
   388      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   389  
   390      if (hash == NULL) {
   391          return FALSE;
   392      }
   393  
   394      return (hash64_get_element_count(hash) == 0);
   395  }
   396  
   397  BOOLEAN hash64_change_size_and_rehash(HASH64_HANDLE hash_handle,
   398                                        UINT32 hash_size) {
   399      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   400      HASH64_NODE** old_array;
   401      HASH64_NODE** new_array;
   402      UINT32 old_hash_size;
   403      UINT32 i;
   404  
   405      if (hash == NULL) {
   406          return FALSE;
   407      }
   408  
   409      new_array = (HASH64_NODE**)hash64_mem_alloc(hash, sizeof(HASH64_NODE*) * hash_size);
   410  
   411      if (new_array == NULL) {
   412          return FALSE;
   413      }
   414  
   415      vmm_zeromem(new_array, sizeof(HASH64_NODE*) * hash_size);
   416  
   417      old_array = hash64_get_array(hash);
   418      old_hash_size = hash64_get_hash_size(hash);
   419  
   420      hash64_set_array(hash, new_array);
   421      hash64_set_hash_size(hash, hash_size);
   422  
   423      for (i = 0; i < old_hash_size; i++) {
   424          HASH64_NODE* node = old_array[i];
   425          while (node != NULL) {
   426              HASH64_NODE* next_node = hash64_node_get_next(node);
   427              UINT64 key;
   428              HASH64_NODE** new_cell;
   429  
   430              key = hash64_node_get_key(node);
   431              new_cell = hash64_retrieve_appropriate_array_cell(hash, key);
   432              hash64_node_set_next(node, *new_cell);
   433              *new_cell = node;
   434  
   435              node = next_node;
   436          }
   437          old_array[i] = NULL;
   438      }
   439  
   440      hash64_mem_free(hash, old_array);
   441      return TRUE;
   442  }
   443  
   444  UINT32 hash64_get_num_of_elements(HASH64_HANDLE hash_handle) {
   445      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   446  
   447      VMM_ASSERT(hash != NULL);
   448      return hash64_get_element_count(hash);
   449  }
   450  #ifdef ENABLE_VTLB
   451  UINT32 hash64_get_current_size(HASH64_HANDLE hash_handle) {
   452      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   453  
   454      VMM_ASSERT(hash != NULL);
   455      return hash64_get_hash_size(hash);
   456  }
   457  
   458  HASH64_HANDLE hash64_create_multiple_values_hash( HASH64_FUNC hash_func,
   459                      HASH64_INTERNAL_MEM_ALLOCATION_FUNC mem_alloc_func,
   460                      HASH64_INTERNAL_MEM_DEALLOCATION_FUNC mem_dealloc_func,
   461                      HASH64_NODE_ALLOCATION_FUNC node_alloc_func,
   462                      HASH64_NODE_DEALLOCATION_FUNC node_dealloc_func,
   463                      void* node_allocation_deallocation_context,
   464                      UINT32 hash_size) {
   465      return hash64_create_hash_internal(hash_func, mem_alloc_func, 
   466                      mem_dealloc_func, node_alloc_func,
   467                      node_dealloc_func, node_allocation_deallocation_context,
   468                      hash_size, TRUE);
   469  }
   470  #endif
   471  
   472  
   473  void hash64_destroy_multiple_values_hash(HASH64_HANDLE hash_handle) {
   474          HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   475  
   476          VMM_ASSERT(hash64_is_multiple_values_hash(hash));
   477      hash64_destroy_hash_internal(hash);
   478  }
   479  
   480  #ifdef ENABLE_VTLB
   481  BOOLEAN hash64_lookup_in_multiple_values_hash(HASH64_HANDLE hash_handle,
   482                        UINT64 key, HASH64_MULTIPLE_VALUES_HASH_ITERATOR* iter) {
   483      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   484      HASH64_NODE* top_node;
   485      UINT64 top_node_value;
   486  
   487      if (hash == NULL) {
   488          return FALSE;
   489      }
   490      VMM_ASSERT(hash64_is_multiple_values_hash(hash));
   491      top_node = hash64_find(hash, key);
   492      if (top_node == NULL) {
   493          return FALSE;
   494      }
   495      top_node_value = hash64_node_get_value(top_node);
   496      *iter = (HASH64_MULTIPLE_VALUES_HASH_ITERATOR)hash64_uint64_to_ptr(top_node_value);
   497      return TRUE;
   498  }
   499  
   500  
   501  HASH64_MULTIPLE_VALUES_HASH_ITERATOR
   502  hash64_multiple_values_hash_iterator_get_next(HASH64_MULTIPLE_VALUES_HASH_ITERATOR iter) {
   503      HASH64_NODE* node = (HASH64_NODE*)iter;
   504      return (HASH64_MULTIPLE_VALUES_HASH_ITERATOR)hash64_node_get_next(node);
   505  }
   506  
   507  UINT64 hash64_multiple_values_hash_iterator_get_value(
   508              HASH64_MULTIPLE_VALUES_HASH_ITERATOR iter) {
   509      HASH64_NODE* node = (HASH64_NODE*)iter;
   510      return hash64_node_get_value(node);
   511  }
   512  
   513  BOOLEAN hash64_insert_into_multiple_values_hash(HASH64_HANDLE hash_handle,
   514                        UINT64 key, UINT64 value) {
   515      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   516      HASH64_NODE* top_node;
   517      UINT64 top_node_value;
   518      HASH64_NODE* node;
   519      HASH64_NODE* node_tmp;
   520  
   521      if (hash == NULL) {
   522          return FALSE;
   523      }
   524  
   525      VMM_ASSERT(hash64_is_multiple_values_hash(hash));
   526  
   527      top_node = hash64_find(hash, key);
   528  
   529  
   530      if (top_node == NULL) {
   531          HASH64_NODE** cell;
   532          top_node = hash64_allocate_node(hash);
   533          if (top_node == NULL) {
   534              return FALSE;
   535          }
   536          hash64_node_set_key(top_node, key);
   537          hash64_node_set_value(top_node, hash64_ptr_to_uint64(NULL));
   538          cell = hash64_retrieve_appropriate_array_cell(hash, key);
   539          hash64_node_set_next(top_node, *cell);
   540          *cell = top_node;
   541          hash64_inc_element_count(hash);
   542      }
   543  
   544      node = hash64_allocate_node(hash);
   545      if (node == NULL) {
   546          return FALSE;
   547      }
   548  
   549      hash64_node_set_key(node, key);
   550      hash64_node_set_value(node, value);
   551  
   552      top_node_value = hash64_node_get_value(top_node);
   553      node_tmp = (HASH64_NODE*)hash64_uint64_to_ptr(top_node_value);
   554      if ((node_tmp == NULL) ||
   555          (hash64_node_get_value(node_tmp) >= value)) {
   556          hash64_node_set_next(node, node_tmp);
   557          hash64_node_set_value(top_node, hash64_ptr_to_uint64(node));
   558          return TRUE;
   559      }
   560  
   561      while (1) {
   562          HASH64_NODE* next_node_tmp = hash64_node_get_next(node_tmp);
   563          if ((next_node_tmp == NULL) ||
   564              (hash64_node_get_value(next_node_tmp) >= value)) {
   565              break;
   566          }
   567          node_tmp = next_node_tmp;
   568      }
   569  
   570      hash64_node_set_next(node, hash64_node_get_next(node_tmp));
   571      hash64_node_set_next(node_tmp, node);
   572  
   573      return TRUE;
   574  }
   575  
   576  BOOLEAN hash64_remove_from_multiple_values_hash(HASH64_HANDLE hash_handle,
   577                        UINT64 key, UINT64 value) {
   578      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   579      HASH64_NODE* top_node;
   580      UINT64 top_node_value;
   581      HASH64_NODE* node;
   582  
   583      if (hash == NULL) {
   584          return FALSE;
   585      }
   586  
   587      VMM_ASSERT(hash64_is_multiple_values_hash(hash));
   588  
   589      top_node = hash64_find(hash, key);
   590  
   591      if (top_node == NULL) {
   592          return FALSE;
   593      }
   594  
   595      top_node_value = hash64_node_get_value(top_node);
   596      node = (HASH64_NODE*)hash64_uint64_to_ptr(top_node_value);
   597  
   598      if (hash64_node_get_value(node) == value) {
   599          HASH64_NODE* next_node = hash64_node_get_next(node);
   600          hash64_free_node(hash, node);
   601          top_node_value = hash64_ptr_to_uint64(next_node);
   602          hash64_node_set_value(top_node, top_node_value);
   603          if (next_node == NULL) {
   604              BOOLEAN res;
   605              // There is only one value
   606              res = hash64_remove(hash_handle, key);
   607              VMM_ASSERT(res);
   608          }
   609          return TRUE;
   610      }
   611  
   612      while (node != NULL) {
   613          HASH64_NODE* prev_node = node;
   614  
   615          node = hash64_node_get_next(node);
   616          if (node != NULL) {
   617              if (hash64_node_get_value(node) == value) {
   618                  hash64_node_set_next(prev_node, hash64_node_get_next(node));
   619                  hash64_free_node(hash, node);
   620                  return TRUE;
   621              }
   622              else if (hash64_node_get_value(node) > value) {
   623                  break; // no point to search in sorted list
   624              }
   625          }
   626      }
   627      return FALSE;
   628  }
   629  
   630  BOOLEAN hash64_is_value_in_multiple_values_hash(HASH64_HANDLE hash_handle,
   631                          UINT64 key, UINT64 value) {
   632      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   633      HASH64_MULTIPLE_VALUES_HASH_ITERATOR iter;
   634  
   635      if (hash == NULL) {
   636          return FALSE;
   637      }
   638  
   639      VMM_ASSERT(hash64_is_multiple_values_hash(hash));
   640  
   641      if (!hash64_lookup_in_multiple_values_hash(hash_handle, key, &iter)) {
   642          return FALSE;
   643      }
   644  
   645      while (iter != HASH64_NULL_ITERATOR) {
   646          UINT64 iter_value = hash64_multiple_values_hash_iterator_get_value(iter);
   647          if (iter_value == value) {
   648              return TRUE;
   649          }
   650          iter = hash64_multiple_values_hash_iterator_get_next(iter);
   651      }
   652      return FALSE;
   653  }
   654  
   655  BOOLEAN hash64_remove_range_from_multiple_values_hash(HASH64_HANDLE hash_handle,
   656                             UINT64 key, UINT64 value_from, UINT64 value_to) {
   657      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   658      HASH64_NODE* top_node;
   659      HASH64_NODE* node;
   660      UINT64 top_node_value;
   661      BOOLEAN removed_any_value = FALSE;
   662  
   663      if (hash == NULL) {
   664          return FALSE;
   665      }
   666  
   667      VMM_ASSERT(hash64_is_multiple_values_hash(hash));
   668  
   669      top_node = hash64_find(hash, key);
   670  
   671      if (top_node == NULL) {
   672          return FALSE;
   673      }
   674  
   675      top_node_value = hash64_node_get_value(top_node);
   676      node = (HASH64_NODE*)hash64_uint64_to_ptr(top_node_value);
   677  
   678      VMM_ASSERT(node != NULL);
   679      VMM_ASSERT(value_from <= value_to);
   680  
   681      if (hash64_node_get_value(node) > value_to) {
   682          return FALSE;
   683      }
   684  
   685      if (hash64_node_get_value(node) >= value_from) {
   686          while ((node != NULL) &&
   687                 (hash64_node_get_value(node) <= value_to)) {
   688              // remove from the beginning of the list
   689              HASH64_NODE* node_to_remove = node;
   690              node = hash64_node_get_next(node);
   691              hash64_free_node(hash, node_to_remove);
   692              removed_any_value = TRUE;
   693          }
   694  
   695          if (removed_any_value) {
   696              VMM_ASSERT((node == NULL) || (hash64_node_get_value(node) > value_to));
   697              top_node_value = hash64_ptr_to_uint64(node);
   698              hash64_node_set_value(top_node, top_node_value);
   699              if (node == NULL) {
   700                  BOOLEAN res;
   701                  // all the entries were removed
   702                  res = hash64_remove(hash_handle, key);
   703                  VMM_ASSERT(res);
   704              }
   705              return TRUE;
   706          }
   707      }
   708  
   709      while (node != NULL) {
   710          HASH64_NODE* next_node = hash64_node_get_next(node);
   711          VMM_ASSERT(hash64_node_get_value(node) < value_from);
   712          if ((next_node != NULL) &&
   713              (hash64_node_get_value(next_node) > value_to)) {
   714              break;
   715          }
   716  
   717          if ((next_node != NULL) &&
   718              (hash64_node_get_value(next_node) >= value_from)) {
   719              hash64_node_set_next(node, hash64_node_get_next(next_node));
   720              hash64_free_node(hash, next_node);
   721              removed_any_value = TRUE;
   722          }
   723          else {
   724              node = next_node;
   725          }
   726      }
   727      return removed_any_value;
   728  }
   729  
   730  BOOLEAN hash64_multiple_values_is_empty(HASH64_HANDLE hash_handle) {
   731      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   732  
   733      if (hash == NULL) {
   734          return FALSE;
   735      }
   736  
   737      return (hash64_get_element_count(hash) == 0);
   738  }
   739  #endif
   740  
   741  #ifdef DEBUG
   742  void hash64_print(HASH64_HANDLE hash_handle) {
   743      HASH64_TABLE* hash = (HASH64_TABLE*)hash_handle;
   744      HASH64_NODE** array;
   745      UINT32 i;
   746  
   747      VMM_LOG(mask_anonymous, level_trace,"Hash64:\n");
   748      VMM_LOG(mask_anonymous, level_trace,"========================\n");
   749      if (hash == NULL) {
   750          VMM_LOG(mask_anonymous, level_trace,"%s: ERROR in parameter\n", __FUNCTION__);
   751          return;
   752      }
   753      VMM_LOG(mask_anonymous, level_trace,"Num of cells: %d\n", hash64_get_hash_size(hash));
   754      VMM_LOG(mask_anonymous, level_trace,"Num of elements: %d\n", hash64_get_element_count(hash));
   755  
   756      array = hash64_get_array(hash);
   757      for (i = 0; i < hash64_get_hash_size(hash); i++) {
   758          if (array[i] != NULL) {
   759              HASH64_NODE* node = array[i];
   760              VMM_LOG(mask_anonymous, level_trace,"[%d]: ", i);
   761  
   762              while (node != NULL) {
   763                  if (hash64_is_multiple_values_hash(hash)) {
   764                      UINT32 counter = 0;
   765                      HASH64_NODE* node_value = hash64_uint64_to_ptr(hash64_node_get_value(node));
   766                      while (node_value != NULL) {
   767                          counter++;
   768                          node_value = hash64_node_get_next(node_value);
   769                      }
   770                      VMM_LOG(mask_anonymous, level_trace,"(%P : %d); ", hash64_node_get_key(node), counter);
   771                  }
   772                  else {
   773                      VMM_LOG(mask_anonymous, level_trace,"(%P : %P); ", hash64_node_get_key(node), hash64_node_get_value(node));
   774                  }
   775                  node = hash64_node_get_next(node);
   776              }
   777  
   778              VMM_LOG(mask_anonymous, level_trace,"\n");
   779          }
   780      }
   781  }
   782  #endif
   783