Home | History | Annotate | Line # | Download | only in gcc
hash-map-tests.cc revision 1.1
      1  1.1  mrg /* Unit tests for hash-map.h.
      2  1.1  mrg    Copyright (C) 2015-2022 Free Software Foundation, Inc.
      3  1.1  mrg 
      4  1.1  mrg This file is part of GCC.
      5  1.1  mrg 
      6  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      7  1.1  mrg the terms of the GNU General Public License as published by the Free
      8  1.1  mrg Software Foundation; either version 3, or (at your option) any later
      9  1.1  mrg version.
     10  1.1  mrg 
     11  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  1.1  mrg for more details.
     15  1.1  mrg 
     16  1.1  mrg You should have received a copy of the GNU General Public License
     17  1.1  mrg along with GCC; see the file COPYING3.  If not see
     18  1.1  mrg <http://www.gnu.org/licenses/>.  */
     19  1.1  mrg 
     20  1.1  mrg #include "config.h"
     21  1.1  mrg #include "system.h"
     22  1.1  mrg #include "coretypes.h"
     23  1.1  mrg #include "tm.h"
     24  1.1  mrg #include "opts.h"
     25  1.1  mrg #include "hash-set.h"
     26  1.1  mrg #include "fixed-value.h"
     27  1.1  mrg #include "alias.h"
     28  1.1  mrg #include "flags.h"
     29  1.1  mrg #include "symtab.h"
     30  1.1  mrg #include "tree-core.h"
     31  1.1  mrg #include "stor-layout.h"
     32  1.1  mrg #include "tree.h"
     33  1.1  mrg #include "stringpool.h"
     34  1.1  mrg #include "selftest.h"
     35  1.1  mrg 
     36  1.1  mrg #if CHECKING_P
     37  1.1  mrg 
     38  1.1  mrg namespace selftest {
     39  1.1  mrg 
     40  1.1  mrg /* Construct a hash_map <const char *, int> and verify that
     41  1.1  mrg    various operations work correctly.  */
     42  1.1  mrg 
     43  1.1  mrg static void
     44  1.1  mrg test_map_of_strings_to_int ()
     45  1.1  mrg {
     46  1.1  mrg   hash_map <const char *, int> m;
     47  1.1  mrg 
     48  1.1  mrg   const char *ostrich = "ostrich";
     49  1.1  mrg   const char *elephant = "elephant";
     50  1.1  mrg   const char *ant = "ant";
     51  1.1  mrg   const char *spider = "spider";
     52  1.1  mrg   const char *millipede = "Illacme plenipes";
     53  1.1  mrg   const char *eric = "half a bee";
     54  1.1  mrg 
     55  1.1  mrg   /* A fresh hash_map should be empty.  */
     56  1.1  mrg   ASSERT_TRUE (m.is_empty ());
     57  1.1  mrg   ASSERT_EQ (NULL, m.get (ostrich));
     58  1.1  mrg 
     59  1.1  mrg   /* Populate the hash_map.  */
     60  1.1  mrg   ASSERT_EQ (false, m.put (ostrich, 2));
     61  1.1  mrg   ASSERT_EQ (false, m.put (elephant, 4));
     62  1.1  mrg   ASSERT_EQ (false, m.put (ant, 6));
     63  1.1  mrg   ASSERT_EQ (false, m.put (spider, 8));
     64  1.1  mrg   ASSERT_EQ (false, m.put (millipede, 750));
     65  1.1  mrg   ASSERT_EQ (false, m.put (eric, 3));
     66  1.1  mrg 
     67  1.1  mrg   /* Verify that we can recover the stored values.  */
     68  1.1  mrg   ASSERT_EQ (6, m.elements ());
     69  1.1  mrg   ASSERT_EQ (2, *m.get (ostrich));
     70  1.1  mrg   ASSERT_EQ (4, *m.get (elephant));
     71  1.1  mrg   ASSERT_EQ (6, *m.get (ant));
     72  1.1  mrg   ASSERT_EQ (8, *m.get (spider));
     73  1.1  mrg   ASSERT_EQ (750, *m.get (millipede));
     74  1.1  mrg   ASSERT_EQ (3, *m.get (eric));
     75  1.1  mrg 
     76  1.1  mrg   /* Verify removing an item.  */
     77  1.1  mrg   m.remove (eric);
     78  1.1  mrg   ASSERT_EQ (5, m.elements ());
     79  1.1  mrg   ASSERT_EQ (NULL, m.get (eric));
     80  1.1  mrg 
     81  1.1  mrg   m.remove (eric);
     82  1.1  mrg   ASSERT_EQ (5, m.elements ());
     83  1.1  mrg   ASSERT_EQ (NULL, m.get (eric));
     84  1.1  mrg 
     85  1.1  mrg   /* A plain char * key is hashed based on its value (address), rather
     86  1.1  mrg      than the string it points to.  */
     87  1.1  mrg   char *another_ant = static_cast <char *> (xcalloc (4, 1));
     88  1.1  mrg   another_ant[0] = 'a';
     89  1.1  mrg   another_ant[1] = 'n';
     90  1.1  mrg   another_ant[2] = 't';
     91  1.1  mrg   another_ant[3] = 0;
     92  1.1  mrg   ASSERT_NE (ant, another_ant);
     93  1.1  mrg   unsigned prev_size = m.elements ();
     94  1.1  mrg   ASSERT_EQ (false, m.put (another_ant, 7));
     95  1.1  mrg   ASSERT_EQ (prev_size + 1, m.elements ());
     96  1.1  mrg 
     97  1.1  mrg   /* Need to use string_hash or nofree_string_hash key types to hash
     98  1.1  mrg      based on the string contents.  */
     99  1.1  mrg   hash_map <nofree_string_hash, int> string_map;
    100  1.1  mrg   ASSERT_EQ (false, string_map.put (ant, 1));
    101  1.1  mrg   ASSERT_EQ (1, string_map.elements ());
    102  1.1  mrg   ASSERT_EQ (true, string_map.put (another_ant, 5));
    103  1.1  mrg   ASSERT_EQ (1, string_map.elements ());
    104  1.1  mrg 
    105  1.1  mrg   free (another_ant);
    106  1.1  mrg }
    107  1.1  mrg 
    108  1.1  mrg /* Construct a hash_map using int_hash and verify that
    109  1.1  mrg    various operations work correctly.  */
    110  1.1  mrg 
    111  1.1  mrg static void
    112  1.1  mrg test_map_of_int_to_strings ()
    113  1.1  mrg {
    114  1.1  mrg   const int EMPTY = -1;
    115  1.1  mrg   const int DELETED = -2;
    116  1.1  mrg   typedef int_hash <int, EMPTY, DELETED> int_hash_t;
    117  1.1  mrg   hash_map <int_hash_t, const char *> m;
    118  1.1  mrg 
    119  1.1  mrg   const char *ostrich = "ostrich";
    120  1.1  mrg   const char *elephant = "elephant";
    121  1.1  mrg   const char *ant = "ant";
    122  1.1  mrg   const char *spider = "spider";
    123  1.1  mrg   const char *millipede = "Illacme plenipes";
    124  1.1  mrg   const char *eric = "half a bee";
    125  1.1  mrg 
    126  1.1  mrg   /* A fresh hash_map should be empty.  */
    127  1.1  mrg   ASSERT_EQ (0, m.elements ());
    128  1.1  mrg   ASSERT_EQ (NULL, m.get (2));
    129  1.1  mrg 
    130  1.1  mrg   /* Populate the hash_map.  */
    131  1.1  mrg   ASSERT_EQ (false, m.put (2, ostrich));
    132  1.1  mrg   ASSERT_EQ (false, m.put (4, elephant));
    133  1.1  mrg   ASSERT_EQ (false, m.put (6, ant));
    134  1.1  mrg   ASSERT_EQ (false, m.put (8, spider));
    135  1.1  mrg   ASSERT_EQ (false, m.put (750, millipede));
    136  1.1  mrg   ASSERT_EQ (false, m.put (3, eric));
    137  1.1  mrg 
    138  1.1  mrg   /* Verify that we can recover the stored values.  */
    139  1.1  mrg   ASSERT_EQ (6, m.elements ());
    140  1.1  mrg   ASSERT_EQ (*m.get (2), ostrich);
    141  1.1  mrg   ASSERT_EQ (*m.get (4), elephant);
    142  1.1  mrg   ASSERT_EQ (*m.get (6), ant);
    143  1.1  mrg   ASSERT_EQ (*m.get (8), spider);
    144  1.1  mrg   ASSERT_EQ (*m.get (750), millipede);
    145  1.1  mrg   ASSERT_EQ (*m.get (3), eric);
    146  1.1  mrg }
    147  1.1  mrg 
    148  1.1  mrg typedef class hash_map_test_val_t
    149  1.1  mrg {
    150  1.1  mrg public:
    151  1.1  mrg   static int ndefault;
    152  1.1  mrg   static int ncopy;
    153  1.1  mrg   static int nassign;
    154  1.1  mrg   static int ndtor;
    155  1.1  mrg 
    156  1.1  mrg   hash_map_test_val_t ()
    157  1.1  mrg     : ptr (&ptr)
    158  1.1  mrg   {
    159  1.1  mrg     ++ndefault;
    160  1.1  mrg   }
    161  1.1  mrg 
    162  1.1  mrg   hash_map_test_val_t (const hash_map_test_val_t &rhs)
    163  1.1  mrg     : ptr (&ptr)
    164  1.1  mrg   {
    165  1.1  mrg     ++ncopy;
    166  1.1  mrg     gcc_assert (rhs.ptr == &rhs.ptr);
    167  1.1  mrg   }
    168  1.1  mrg 
    169  1.1  mrg   hash_map_test_val_t& operator= (const hash_map_test_val_t &rhs)
    170  1.1  mrg   {
    171  1.1  mrg     ++nassign;
    172  1.1  mrg     gcc_assert (ptr == &ptr);
    173  1.1  mrg     gcc_assert (rhs.ptr == &rhs.ptr);
    174  1.1  mrg     return *this;
    175  1.1  mrg   }
    176  1.1  mrg 
    177  1.1  mrg   ~hash_map_test_val_t ()
    178  1.1  mrg   {
    179  1.1  mrg     gcc_assert (ptr == &ptr);
    180  1.1  mrg     ++ndtor;
    181  1.1  mrg   }
    182  1.1  mrg 
    183  1.1  mrg   void *ptr;
    184  1.1  mrg } val_t;
    185  1.1  mrg 
    186  1.1  mrg int val_t::ndefault;
    187  1.1  mrg int val_t::ncopy;
    188  1.1  mrg int val_t::nassign;
    189  1.1  mrg int val_t::ndtor;
    190  1.1  mrg 
    191  1.1  mrg static void
    192  1.1  mrg test_map_of_type_with_ctor_and_dtor ()
    193  1.1  mrg {
    194  1.1  mrg   typedef hash_map <void *, val_t> Map;
    195  1.1  mrg 
    196  1.1  mrg   {
    197  1.1  mrg     /* Test default ctor.  */
    198  1.1  mrg     Map m;
    199  1.1  mrg     (void)&m;
    200  1.1  mrg   }
    201  1.1  mrg 
    202  1.1  mrg   ASSERT_TRUE (val_t::ndefault == 0);
    203  1.1  mrg   ASSERT_TRUE (val_t::ncopy == 0);
    204  1.1  mrg   ASSERT_TRUE (val_t::nassign == 0);
    205  1.1  mrg   ASSERT_TRUE (val_t::ndtor == 0);
    206  1.1  mrg 
    207  1.1  mrg   {
    208  1.1  mrg     /* Test single insertion.  */
    209  1.1  mrg     Map m;
    210  1.1  mrg     void *p = &p;
    211  1.1  mrg     m.get_or_insert (p);
    212  1.1  mrg   }
    213  1.1  mrg 
    214  1.1  mrg   ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor);
    215  1.1  mrg 
    216  1.1  mrg   {
    217  1.1  mrg     /* Test copy ctor.  */
    218  1.1  mrg     Map m1;
    219  1.1  mrg     void *p = &p;
    220  1.1  mrg     val_t &rv1 = m1.get_or_insert (p);
    221  1.1  mrg 
    222  1.1  mrg     int ncopy = val_t::ncopy;
    223  1.1  mrg     int nassign = val_t::nassign;
    224  1.1  mrg 
    225  1.1  mrg     Map m2 (m1);
    226  1.1  mrg     val_t *pv2 = m2.get (p);
    227  1.1  mrg 
    228  1.1  mrg     ASSERT_TRUE (ncopy + 1 == val_t::ncopy);
    229  1.1  mrg     ASSERT_TRUE (nassign == val_t::nassign);
    230  1.1  mrg 
    231  1.1  mrg     ASSERT_TRUE (&rv1 != pv2);
    232  1.1  mrg   }
    233  1.1  mrg 
    234  1.1  mrg   ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor);
    235  1.1  mrg 
    236  1.1  mrg #if 0   /* Avoid testing until bug 90959 is fixed.  */
    237  1.1  mrg   {
    238  1.1  mrg     /* Test copy assignment into an empty map.  */
    239  1.1  mrg     Map m1;
    240  1.1  mrg     void *p = &p;
    241  1.1  mrg     val_t &rv1 = m1.get_or_insert (p);
    242  1.1  mrg 
    243  1.1  mrg     int ncopy = val_t::ncopy;
    244  1.1  mrg     int nassign = val_t::nassign;
    245  1.1  mrg 
    246  1.1  mrg     Map m2;
    247  1.1  mrg     m2 = m1;
    248  1.1  mrg     val_t *pv2 = m2.get (p);
    249  1.1  mrg 
    250  1.1  mrg     ASSERT_TRUE (ncopy == val_t::ncopy);
    251  1.1  mrg     ASSERT_TRUE (nassign + 1 == val_t::nassign);
    252  1.1  mrg 
    253  1.1  mrg     ASSERT_TRUE (&rv1 != pv2);
    254  1.1  mrg   }
    255  1.1  mrg 
    256  1.1  mrg   ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor);
    257  1.1  mrg 
    258  1.1  mrg #endif
    259  1.1  mrg 
    260  1.1  mrg   {
    261  1.1  mrg     Map m;
    262  1.1  mrg     void *p = &p, *q = &q;
    263  1.1  mrg     val_t &v1 = m.get_or_insert (p);
    264  1.1  mrg     val_t &v2 = m.get_or_insert (q);
    265  1.1  mrg 
    266  1.1  mrg     ASSERT_TRUE (v1.ptr == &v1.ptr && &v2.ptr == v2.ptr);
    267  1.1  mrg   }
    268  1.1  mrg 
    269  1.1  mrg   ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor);
    270  1.1  mrg 
    271  1.1  mrg   {
    272  1.1  mrg     Map m;
    273  1.1  mrg     void *p = &p, *q = &q;
    274  1.1  mrg     m.get_or_insert (p);
    275  1.1  mrg     m.remove (p);
    276  1.1  mrg     m.get_or_insert (q);
    277  1.1  mrg     m.remove (q);
    278  1.1  mrg 
    279  1.1  mrg     ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor);
    280  1.1  mrg   }
    281  1.1  mrg 
    282  1.1  mrg 
    283  1.1  mrg   /* Verify basic construction and destruction of Value objects.  */
    284  1.1  mrg   {
    285  1.1  mrg     /* Configure, arbitrary.  */
    286  1.1  mrg     const size_t N_init = 0;
    287  1.1  mrg     const int N_elem = 28;
    288  1.1  mrg 
    289  1.1  mrg     void *a[N_elem];
    290  1.1  mrg     for (size_t i = 0; i < N_elem; ++i)
    291  1.1  mrg       a[i] = &a[i];
    292  1.1  mrg 
    293  1.1  mrg     val_t::ndefault = 0;
    294  1.1  mrg     val_t::ncopy = 0;
    295  1.1  mrg     val_t::nassign = 0;
    296  1.1  mrg     val_t::ndtor = 0;
    297  1.1  mrg     Map m (N_init);
    298  1.1  mrg     ASSERT_EQ (val_t::ndefault
    299  1.1  mrg 	       + val_t::ncopy
    300  1.1  mrg 	       + val_t::nassign
    301  1.1  mrg 	       + val_t::ndtor, 0);
    302  1.1  mrg 
    303  1.1  mrg     for (int i = 0; i < N_elem; ++i)
    304  1.1  mrg       {
    305  1.1  mrg 	m.get_or_insert (a[i]);
    306  1.1  mrg 	ASSERT_EQ (val_t::ndefault, 1 + i);
    307  1.1  mrg 	ASSERT_EQ (val_t::ncopy, 0);
    308  1.1  mrg 	ASSERT_EQ (val_t::nassign, 0);
    309  1.1  mrg 	ASSERT_EQ (val_t::ndtor, i);
    310  1.1  mrg 
    311  1.1  mrg 	m.remove (a[i]);
    312  1.1  mrg 	ASSERT_EQ (val_t::ndefault, 1 + i);
    313  1.1  mrg 	ASSERT_EQ (val_t::ncopy, 0);
    314  1.1  mrg 	ASSERT_EQ (val_t::nassign, 0);
    315  1.1  mrg 	ASSERT_EQ (val_t::ndtor, 1 + i);
    316  1.1  mrg       }
    317  1.1  mrg   }
    318  1.1  mrg }
    319  1.1  mrg 
    320  1.1  mrg /* Verify aspects of 'hash_table::expand', in particular that it doesn't leak
    321  1.1  mrg    Value objects.  */
    322  1.1  mrg 
    323  1.1  mrg static void
    324  1.1  mrg test_map_of_type_with_ctor_and_dtor_expand (bool remove_some_inline)
    325  1.1  mrg {
    326  1.1  mrg   /* Configure, so that hash table expansion triggers a few times.  */
    327  1.1  mrg   const size_t N_init = 0;
    328  1.1  mrg   const int N_elem = 70;
    329  1.1  mrg   size_t expand_c_expected = 4;
    330  1.1  mrg   size_t expand_c = 0;
    331  1.1  mrg 
    332  1.1  mrg   /* For stability of this testing, we need all Key values 'k' to produce
    333  1.1  mrg      unique hash values 'Traits::hash (k)', as otherwise the dynamic
    334  1.1  mrg      insert/remove behavior may diverge across different architectures.  This
    335  1.1  mrg      is, for example, a problem when using the standard 'pointer_hash::hash',
    336  1.1  mrg      which is simply doing a 'k >> 3' operation, which is fine on 64-bit
    337  1.1  mrg      architectures, but on 32-bit architectures produces the same hash value
    338  1.1  mrg      for subsequent 'a[i] = &a[i]' array elements.  Therefore, use an
    339  1.1  mrg      'int_hash'.  */
    340  1.1  mrg 
    341  1.1  mrg   int a[N_elem];
    342  1.1  mrg   for (size_t i = 0; i < N_elem; ++i)
    343  1.1  mrg     a[i] = i;
    344  1.1  mrg 
    345  1.1  mrg   const int EMPTY = -1;
    346  1.1  mrg   const int DELETED = -2;
    347  1.1  mrg   typedef hash_map<int_hash<int, EMPTY, DELETED>, val_t> Map;
    348  1.1  mrg 
    349  1.1  mrg   /* Note that we are starting with a fresh 'Map'.  Even if an existing one has
    350  1.1  mrg      been cleared out completely, there remain 'deleted' elements, and these
    351  1.1  mrg      would disturb the following logic, where we don't have access to the
    352  1.1  mrg      actual 'm_n_deleted' value.  */
    353  1.1  mrg   size_t m_n_deleted = 0;
    354  1.1  mrg 
    355  1.1  mrg   val_t::ndefault = 0;
    356  1.1  mrg   val_t::ncopy = 0;
    357  1.1  mrg   val_t::nassign = 0;
    358  1.1  mrg   val_t::ndtor = 0;
    359  1.1  mrg   Map m (N_init);
    360  1.1  mrg 
    361  1.1  mrg   /* In the following, in particular related to 'expand', we're adapting from
    362  1.1  mrg      the internal logic of 'hash_table', glossing over "some details" not
    363  1.1  mrg      relevant for this testing here.  */
    364  1.1  mrg 
    365  1.1  mrg   /* Per 'hash_table::hash_table'.  */
    366  1.1  mrg   size_t m_size;
    367  1.1  mrg   {
    368  1.1  mrg     unsigned int size_prime_index_ = hash_table_higher_prime_index (N_init);
    369  1.1  mrg     m_size = prime_tab[size_prime_index_].prime;
    370  1.1  mrg   }
    371  1.1  mrg 
    372  1.1  mrg   int n_expand_moved = 0;
    373  1.1  mrg 
    374  1.1  mrg   for (int i = 0; i < N_elem; ++i)
    375  1.1  mrg     {
    376  1.1  mrg       size_t elts = m.elements ();
    377  1.1  mrg 
    378  1.1  mrg       /* Per 'hash_table::find_slot_with_hash'.  */
    379  1.1  mrg       size_t m_n_elements = elts + m_n_deleted;
    380  1.1  mrg       bool expand = m_size * 3 <= m_n_elements * 4;
    381  1.1  mrg 
    382  1.1  mrg       m.get_or_insert (a[i]);
    383  1.1  mrg       if (expand)
    384  1.1  mrg 	{
    385  1.1  mrg 	  ++expand_c;
    386  1.1  mrg 
    387  1.1  mrg 	  /* Per 'hash_table::expand'.  */
    388  1.1  mrg 	  {
    389  1.1  mrg 	    unsigned int nindex = hash_table_higher_prime_index (elts * 2);
    390  1.1  mrg 	    m_size = prime_tab[nindex].prime;
    391  1.1  mrg 	  }
    392  1.1  mrg 	  m_n_deleted = 0;
    393  1.1  mrg 
    394  1.1  mrg 	  /* All non-deleted elements have been moved.  */
    395  1.1  mrg 	  n_expand_moved += i;
    396  1.1  mrg 	  if (remove_some_inline)
    397  1.1  mrg 	    n_expand_moved -= (i + 2) / 3;
    398  1.1  mrg 	}
    399  1.1  mrg 
    400  1.1  mrg       ASSERT_EQ (val_t::ndefault, 1 + i);
    401  1.1  mrg       ASSERT_EQ (val_t::ncopy, n_expand_moved);
    402  1.1  mrg       ASSERT_EQ (val_t::nassign, 0);
    403  1.1  mrg       if (remove_some_inline)
    404  1.1  mrg 	ASSERT_EQ (val_t::ndtor, n_expand_moved + (i + 2) / 3);
    405  1.1  mrg       else
    406  1.1  mrg 	ASSERT_EQ (val_t::ndtor, n_expand_moved);
    407  1.1  mrg 
    408  1.1  mrg       /* Remove some inline.  This never triggers an 'expand' here, but via
    409  1.1  mrg 	 'm_n_deleted' does influence any following one.  */
    410  1.1  mrg       if (remove_some_inline
    411  1.1  mrg 	  && !(i % 3))
    412  1.1  mrg 	{
    413  1.1  mrg 	  m.remove (a[i]);
    414  1.1  mrg 	  /* Per 'hash_table::remove_elt_with_hash'.  */
    415  1.1  mrg 	  m_n_deleted++;
    416  1.1  mrg 
    417  1.1  mrg 	  ASSERT_EQ (val_t::ndefault, 1 + i);
    418  1.1  mrg 	  ASSERT_EQ (val_t::ncopy, n_expand_moved);
    419  1.1  mrg 	  ASSERT_EQ (val_t::nassign, 0);
    420  1.1  mrg 	  ASSERT_EQ (val_t::ndtor, n_expand_moved + 1 + (i + 2) / 3);
    421  1.1  mrg 	}
    422  1.1  mrg     }
    423  1.1  mrg   ASSERT_EQ (expand_c, expand_c_expected);
    424  1.1  mrg 
    425  1.1  mrg   int ndefault = val_t::ndefault;
    426  1.1  mrg   int ncopy = val_t::ncopy;
    427  1.1  mrg   int nassign = val_t::nassign;
    428  1.1  mrg   int ndtor = val_t::ndtor;
    429  1.1  mrg 
    430  1.1  mrg   for (int i = 0; i < N_elem; ++i)
    431  1.1  mrg     {
    432  1.1  mrg       if (remove_some_inline
    433  1.1  mrg 	  && !(i % 3))
    434  1.1  mrg 	continue;
    435  1.1  mrg 
    436  1.1  mrg       m.remove (a[i]);
    437  1.1  mrg       ++ndtor;
    438  1.1  mrg       ASSERT_EQ (val_t::ndefault, ndefault);
    439  1.1  mrg       ASSERT_EQ (val_t::ncopy, ncopy);
    440  1.1  mrg       ASSERT_EQ (val_t::nassign, nassign);
    441  1.1  mrg       ASSERT_EQ (val_t::ndtor, ndtor);
    442  1.1  mrg     }
    443  1.1  mrg   ASSERT_EQ (val_t::ndefault + val_t::ncopy, val_t::ndtor);
    444  1.1  mrg }
    445  1.1  mrg 
    446  1.1  mrg /* Test calling empty on a hash_map that has a key type with non-zero
    447  1.1  mrg    "empty" value.  */
    448  1.1  mrg 
    449  1.1  mrg static void
    450  1.1  mrg test_nonzero_empty_key ()
    451  1.1  mrg {
    452  1.1  mrg   typedef int_hash<int, INT_MIN, INT_MAX> IntHash;
    453  1.1  mrg   hash_map<int, int, simple_hashmap_traits<IntHash, int> > x;
    454  1.1  mrg 
    455  1.1  mrg   for (int i = 1; i != 32; ++i)
    456  1.1  mrg     x.put (i, i);
    457  1.1  mrg 
    458  1.1  mrg   ASSERT_EQ (x.get (0), NULL);
    459  1.1  mrg   ASSERT_EQ (*x.get (1), 1);
    460  1.1  mrg 
    461  1.1  mrg   x.empty ();
    462  1.1  mrg 
    463  1.1  mrg   ASSERT_EQ (x.get (0), NULL);
    464  1.1  mrg   ASSERT_EQ (x.get (1), NULL);
    465  1.1  mrg }
    466  1.1  mrg 
    467  1.1  mrg /* Run all of the selftests within this file.  */
    468  1.1  mrg 
    469  1.1  mrg void
    470  1.1  mrg hash_map_tests_cc_tests ()
    471  1.1  mrg {
    472  1.1  mrg   test_map_of_strings_to_int ();
    473  1.1  mrg   test_map_of_int_to_strings ();
    474  1.1  mrg   test_map_of_type_with_ctor_and_dtor ();
    475  1.1  mrg   test_map_of_type_with_ctor_and_dtor_expand (false);
    476  1.1  mrg   test_map_of_type_with_ctor_and_dtor_expand (true);
    477  1.1  mrg   test_nonzero_empty_key ();
    478  1.1  mrg }
    479  1.1  mrg 
    480  1.1  mrg } // namespace selftest
    481  1.1  mrg 
    482  1.1  mrg #endif /* CHECKING_P */
    483