Home | History | Annotate | Download | only in containers
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/containers/small_map.h"
      6 
      7 #include <stddef.h>
      8 
      9 #include <algorithm>
     10 #include <functional>
     11 #include <map>
     12 
     13 #include "base/containers/hash_tables.h"
     14 #include "base/logging.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace base {
     18 
     19 TEST(SmallMap, General) {
     20   SmallMap<hash_map<int, int> > m;
     21 
     22   EXPECT_TRUE(m.empty());
     23 
     24   m[0] = 5;
     25 
     26   EXPECT_FALSE(m.empty());
     27   EXPECT_EQ(m.size(), 1u);
     28 
     29   m[9] = 2;
     30 
     31   EXPECT_FALSE(m.empty());
     32   EXPECT_EQ(m.size(), 2u);
     33 
     34   EXPECT_EQ(m[9], 2);
     35   EXPECT_EQ(m[0], 5);
     36   EXPECT_FALSE(m.UsingFullMap());
     37 
     38   SmallMap<hash_map<int, int> >::iterator iter(m.begin());
     39   ASSERT_TRUE(iter != m.end());
     40   EXPECT_EQ(iter->first, 0);
     41   EXPECT_EQ(iter->second, 5);
     42   ++iter;
     43   ASSERT_TRUE(iter != m.end());
     44   EXPECT_EQ((*iter).first, 9);
     45   EXPECT_EQ((*iter).second, 2);
     46   ++iter;
     47   EXPECT_TRUE(iter == m.end());
     48 
     49   m[8] = 23;
     50   m[1234] = 90;
     51   m[-5] = 6;
     52 
     53   EXPECT_EQ(m[   9],  2);
     54   EXPECT_EQ(m[   0],  5);
     55   EXPECT_EQ(m[1234], 90);
     56   EXPECT_EQ(m[   8], 23);
     57   EXPECT_EQ(m[  -5],  6);
     58   EXPECT_EQ(m.size(), 5u);
     59   EXPECT_FALSE(m.empty());
     60   EXPECT_TRUE(m.UsingFullMap());
     61 
     62   iter = m.begin();
     63   for (int i = 0; i < 5; i++) {
     64     EXPECT_TRUE(iter != m.end());
     65     ++iter;
     66   }
     67   EXPECT_TRUE(iter == m.end());
     68 
     69   const SmallMap<hash_map<int, int> >& ref = m;
     70   EXPECT_TRUE(ref.find(1234) != m.end());
     71   EXPECT_TRUE(ref.find(5678) == m.end());
     72 }
     73 
     74 TEST(SmallMap, PostFixIteratorIncrement) {
     75   SmallMap<hash_map<int, int> > m;
     76   m[0] = 5;
     77   m[2] = 3;
     78 
     79   {
     80     SmallMap<hash_map<int, int> >::iterator iter(m.begin());
     81     SmallMap<hash_map<int, int> >::iterator last(iter++);
     82     ++last;
     83     EXPECT_TRUE(last == iter);
     84   }
     85 
     86   {
     87     SmallMap<hash_map<int, int> >::const_iterator iter(m.begin());
     88     SmallMap<hash_map<int, int> >::const_iterator last(iter++);
     89     ++last;
     90     EXPECT_TRUE(last == iter);
     91   }
     92 }
     93 
     94 // Based on the General testcase.
     95 TEST(SmallMap, CopyConstructor) {
     96   SmallMap<hash_map<int, int> > src;
     97 
     98   {
     99     SmallMap<hash_map<int, int> > m(src);
    100     EXPECT_TRUE(m.empty());
    101   }
    102 
    103   src[0] = 5;
    104 
    105   {
    106     SmallMap<hash_map<int, int> > m(src);
    107     EXPECT_FALSE(m.empty());
    108     EXPECT_EQ(m.size(), 1u);
    109   }
    110 
    111   src[9] = 2;
    112 
    113   {
    114     SmallMap<hash_map<int, int> > m(src);
    115     EXPECT_FALSE(m.empty());
    116     EXPECT_EQ(m.size(), 2u);
    117 
    118     EXPECT_EQ(m[9], 2);
    119     EXPECT_EQ(m[0], 5);
    120     EXPECT_FALSE(m.UsingFullMap());
    121   }
    122 
    123   src[8] = 23;
    124   src[1234] = 90;
    125   src[-5] = 6;
    126 
    127   {
    128     SmallMap<hash_map<int, int> > m(src);
    129     EXPECT_EQ(m[   9],  2);
    130     EXPECT_EQ(m[   0],  5);
    131     EXPECT_EQ(m[1234], 90);
    132     EXPECT_EQ(m[   8], 23);
    133     EXPECT_EQ(m[  -5],  6);
    134     EXPECT_EQ(m.size(), 5u);
    135     EXPECT_FALSE(m.empty());
    136     EXPECT_TRUE(m.UsingFullMap());
    137   }
    138 }
    139 
    140 template<class inner>
    141 static void SmallMapToMap(SmallMap<inner> const& src, inner* dest) {
    142   typename SmallMap<inner>::const_iterator it;
    143   for (it = src.begin(); it != src.end(); ++it) {
    144     dest->insert(std::make_pair(it->first, it->second));
    145   }
    146 }
    147 
    148 template<class inner>
    149 static bool SmallMapEqual(SmallMap<inner> const& a,
    150                           SmallMap<inner> const& b) {
    151   inner ia, ib;
    152   SmallMapToMap(a, &ia);
    153   SmallMapToMap(b, &ib);
    154 
    155   // On most systems we can use operator== here, but under some lesser STL
    156   // implementations it doesn't seem to work. So we manually compare.
    157   if (ia.size() != ib.size())
    158     return false;
    159   for (typename inner::iterator ia_it = ia.begin(), ib_it = ib.begin();
    160        ia_it != ia.end(); ++ia_it, ++ib_it) {
    161     if (*ia_it != *ib_it)
    162       return false;
    163   }
    164   return true;
    165 }
    166 
    167 TEST(SmallMap, AssignmentOperator) {
    168   SmallMap<hash_map<int, int> > src_small;
    169   SmallMap<hash_map<int, int> > src_large;
    170 
    171   src_small[1] = 20;
    172   src_small[2] = 21;
    173   src_small[3] = 22;
    174   EXPECT_FALSE(src_small.UsingFullMap());
    175 
    176   src_large[1] = 20;
    177   src_large[2] = 21;
    178   src_large[3] = 22;
    179   src_large[5] = 23;
    180   src_large[6] = 24;
    181   src_large[7] = 25;
    182   EXPECT_TRUE(src_large.UsingFullMap());
    183 
    184   // Assignments to empty.
    185   SmallMap<hash_map<int, int> > dest_small;
    186   dest_small = src_small;
    187   EXPECT_TRUE(SmallMapEqual(dest_small, src_small));
    188   EXPECT_EQ(dest_small.UsingFullMap(),
    189             src_small.UsingFullMap());
    190 
    191   SmallMap<hash_map<int, int> > dest_large;
    192   dest_large = src_large;
    193   EXPECT_TRUE(SmallMapEqual(dest_large, src_large));
    194   EXPECT_EQ(dest_large.UsingFullMap(),
    195             src_large.UsingFullMap());
    196 
    197   // Assignments which assign from full to small, and vice versa.
    198   dest_small = src_large;
    199   EXPECT_TRUE(SmallMapEqual(dest_small, src_large));
    200   EXPECT_EQ(dest_small.UsingFullMap(),
    201             src_large.UsingFullMap());
    202 
    203   dest_large = src_small;
    204   EXPECT_TRUE(SmallMapEqual(dest_large, src_small));
    205   EXPECT_EQ(dest_large.UsingFullMap(),
    206             src_small.UsingFullMap());
    207 
    208   // Double check that SmallMapEqual works:
    209   dest_large[42] = 666;
    210   EXPECT_FALSE(SmallMapEqual(dest_large, src_small));
    211 }
    212 
    213 TEST(SmallMap, Insert) {
    214   SmallMap<hash_map<int, int> > sm;
    215 
    216   // loop through the transition from small map to map.
    217   for (int i = 1; i <= 10; ++i) {
    218     VLOG(1) << "Iteration " << i;
    219     // insert an element
    220     std::pair<SmallMap<hash_map<int, int> >::iterator,
    221         bool> ret;
    222     ret = sm.insert(std::make_pair(i, 100*i));
    223     EXPECT_TRUE(ret.second);
    224     EXPECT_TRUE(ret.first == sm.find(i));
    225     EXPECT_EQ(ret.first->first, i);
    226     EXPECT_EQ(ret.first->second, 100*i);
    227 
    228     // try to insert it again with different value, fails, but we still get an
    229     // iterator back with the original value.
    230     ret = sm.insert(std::make_pair(i, -i));
    231     EXPECT_FALSE(ret.second);
    232     EXPECT_TRUE(ret.first == sm.find(i));
    233     EXPECT_EQ(ret.first->first, i);
    234     EXPECT_EQ(ret.first->second, 100*i);
    235 
    236     // check the state of the map.
    237     for (int j = 1; j <= i; ++j) {
    238       SmallMap<hash_map<int, int> >::iterator it = sm.find(j);
    239       EXPECT_TRUE(it != sm.end());
    240       EXPECT_EQ(it->first, j);
    241       EXPECT_EQ(it->second, j * 100);
    242     }
    243     EXPECT_EQ(sm.size(), static_cast<size_t>(i));
    244     EXPECT_FALSE(sm.empty());
    245   }
    246 }
    247 
    248 TEST(SmallMap, InsertRange) {
    249   // loop through the transition from small map to map.
    250   for (int elements = 0; elements <= 10; ++elements) {
    251     VLOG(1) << "Elements " << elements;
    252     hash_map<int, int> normal_map;
    253     for (int i = 1; i <= elements; ++i) {
    254       normal_map.insert(std::make_pair(i, 100*i));
    255     }
    256 
    257     SmallMap<hash_map<int, int> > sm;
    258     sm.insert(normal_map.begin(), normal_map.end());
    259     EXPECT_EQ(normal_map.size(), sm.size());
    260     for (int i = 1; i <= elements; ++i) {
    261       VLOG(1) << "Iteration " << i;
    262       EXPECT_TRUE(sm.find(i) != sm.end());
    263       EXPECT_EQ(sm.find(i)->first, i);
    264       EXPECT_EQ(sm.find(i)->second, 100*i);
    265     }
    266   }
    267 }
    268 
    269 TEST(SmallMap, Erase) {
    270   SmallMap<hash_map<std::string, int> > m;
    271   SmallMap<hash_map<std::string, int> >::iterator iter;
    272 
    273   m["monday"] = 1;
    274   m["tuesday"] = 2;
    275   m["wednesday"] = 3;
    276 
    277   EXPECT_EQ(m["monday"   ], 1);
    278   EXPECT_EQ(m["tuesday"  ], 2);
    279   EXPECT_EQ(m["wednesday"], 3);
    280   EXPECT_EQ(m.count("tuesday"), 1u);
    281   EXPECT_FALSE(m.UsingFullMap());
    282 
    283   iter = m.begin();
    284   ASSERT_TRUE(iter != m.end());
    285   EXPECT_EQ(iter->first, "monday");
    286   EXPECT_EQ(iter->second, 1);
    287   ++iter;
    288   ASSERT_TRUE(iter != m.end());
    289   EXPECT_EQ(iter->first, "tuesday");
    290   EXPECT_EQ(iter->second, 2);
    291   ++iter;
    292   ASSERT_TRUE(iter != m.end());
    293   EXPECT_EQ(iter->first, "wednesday");
    294   EXPECT_EQ(iter->second, 3);
    295   ++iter;
    296   EXPECT_TRUE(iter == m.end());
    297 
    298   EXPECT_EQ(m.erase("tuesday"), 1u);
    299 
    300   EXPECT_EQ(m["monday"   ], 1);
    301   EXPECT_EQ(m["wednesday"], 3);
    302   EXPECT_EQ(m.count("tuesday"), 0u);
    303   EXPECT_EQ(m.erase("tuesday"), 0u);
    304 
    305   iter = m.begin();
    306   ASSERT_TRUE(iter != m.end());
    307   EXPECT_EQ(iter->first, "monday");
    308   EXPECT_EQ(iter->second, 1);
    309   ++iter;
    310   ASSERT_TRUE(iter != m.end());
    311   EXPECT_EQ(iter->first, "wednesday");
    312   EXPECT_EQ(iter->second, 3);
    313   ++iter;
    314   EXPECT_TRUE(iter == m.end());
    315 
    316   m["thursday"] = 4;
    317   m["friday"] = 5;
    318   EXPECT_EQ(m.size(), 4u);
    319   EXPECT_FALSE(m.empty());
    320   EXPECT_FALSE(m.UsingFullMap());
    321 
    322   m["saturday"] = 6;
    323   EXPECT_TRUE(m.UsingFullMap());
    324 
    325   EXPECT_EQ(m.count("friday"), 1u);
    326   EXPECT_EQ(m.erase("friday"), 1u);
    327   EXPECT_TRUE(m.UsingFullMap());
    328   EXPECT_EQ(m.count("friday"), 0u);
    329   EXPECT_EQ(m.erase("friday"), 0u);
    330 
    331   EXPECT_EQ(m.size(), 4u);
    332   EXPECT_FALSE(m.empty());
    333   EXPECT_EQ(m.erase("monday"), 1u);
    334   EXPECT_EQ(m.size(), 3u);
    335   EXPECT_FALSE(m.empty());
    336 
    337   m.clear();
    338   EXPECT_FALSE(m.UsingFullMap());
    339   EXPECT_EQ(m.size(), 0u);
    340   EXPECT_TRUE(m.empty());
    341 }
    342 
    343 TEST(SmallMap, NonHashMap) {
    344   SmallMap<std::map<int, int>, 4, std::equal_to<int> > m;
    345   EXPECT_TRUE(m.empty());
    346 
    347   m[9] = 2;
    348   m[0] = 5;
    349 
    350   EXPECT_EQ(m[9], 2);
    351   EXPECT_EQ(m[0], 5);
    352   EXPECT_EQ(m.size(), 2u);
    353   EXPECT_FALSE(m.empty());
    354   EXPECT_FALSE(m.UsingFullMap());
    355 
    356   SmallMap<std::map<int, int>, 4, std::equal_to<int> >::iterator iter(
    357       m.begin());
    358   ASSERT_TRUE(iter != m.end());
    359   EXPECT_EQ(iter->first, 9);
    360   EXPECT_EQ(iter->second, 2);
    361   ++iter;
    362   ASSERT_TRUE(iter != m.end());
    363   EXPECT_EQ(iter->first, 0);
    364   EXPECT_EQ(iter->second, 5);
    365   ++iter;
    366   EXPECT_TRUE(iter == m.end());
    367   --iter;
    368   ASSERT_TRUE(iter != m.end());
    369   EXPECT_EQ(iter->first, 0);
    370   EXPECT_EQ(iter->second, 5);
    371 
    372   m[8] = 23;
    373   m[1234] = 90;
    374   m[-5] = 6;
    375 
    376   EXPECT_EQ(m[   9],  2);
    377   EXPECT_EQ(m[   0],  5);
    378   EXPECT_EQ(m[1234], 90);
    379   EXPECT_EQ(m[   8], 23);
    380   EXPECT_EQ(m[  -5],  6);
    381   EXPECT_EQ(m.size(), 5u);
    382   EXPECT_FALSE(m.empty());
    383   EXPECT_TRUE(m.UsingFullMap());
    384 
    385   iter = m.begin();
    386   ASSERT_TRUE(iter != m.end());
    387   EXPECT_EQ(iter->first, -5);
    388   EXPECT_EQ(iter->second, 6);
    389   ++iter;
    390   ASSERT_TRUE(iter != m.end());
    391   EXPECT_EQ(iter->first, 0);
    392   EXPECT_EQ(iter->second, 5);
    393   ++iter;
    394   ASSERT_TRUE(iter != m.end());
    395   EXPECT_EQ(iter->first, 8);
    396   EXPECT_EQ(iter->second, 23);
    397   ++iter;
    398   ASSERT_TRUE(iter != m.end());
    399   EXPECT_EQ(iter->first, 9);
    400   EXPECT_EQ(iter->second, 2);
    401   ++iter;
    402   ASSERT_TRUE(iter != m.end());
    403   EXPECT_EQ(iter->first, 1234);
    404   EXPECT_EQ(iter->second, 90);
    405   ++iter;
    406   EXPECT_TRUE(iter == m.end());
    407   --iter;
    408   ASSERT_TRUE(iter != m.end());
    409   EXPECT_EQ(iter->first, 1234);
    410   EXPECT_EQ(iter->second, 90);
    411 }
    412 
    413 TEST(SmallMap, DefaultEqualKeyWorks) {
    414   // If these tests compile, they pass. The EXPECT calls are only there to avoid
    415   // unused variable warnings.
    416   SmallMap<hash_map<int, int> > hm;
    417   EXPECT_EQ(0u, hm.size());
    418   SmallMap<std::map<int, int> > m;
    419   EXPECT_EQ(0u, m.size());
    420 }
    421 
    422 namespace {
    423 
    424 class hash_map_add_item : public hash_map<int, int> {
    425  public:
    426   hash_map_add_item() : hash_map<int, int>() {}
    427   explicit hash_map_add_item(const std::pair<int, int>& item)
    428       : hash_map<int, int>() {
    429     insert(item);
    430   }
    431 };
    432 
    433 void InitMap(ManualConstructor<hash_map_add_item>* map_ctor) {
    434   map_ctor->Init(std::make_pair(0, 0));
    435 }
    436 
    437 class hash_map_add_item_initializer {
    438  public:
    439   explicit hash_map_add_item_initializer(int item_to_add)
    440       : item_(item_to_add) {}
    441   hash_map_add_item_initializer()
    442       : item_(0) {}
    443   void operator()(ManualConstructor<hash_map_add_item>* map_ctor) const {
    444     map_ctor->Init(std::make_pair(item_, item_));
    445   }
    446 
    447   int item_;
    448 };
    449 
    450 }  // anonymous namespace
    451 
    452 TEST(SmallMap, SubclassInitializationWithFunctionPointer) {
    453   SmallMap<hash_map_add_item, 4, std::equal_to<int>,
    454       void (&)(ManualConstructor<hash_map_add_item>*)> m(InitMap);
    455 
    456   EXPECT_TRUE(m.empty());
    457 
    458   m[1] = 1;
    459   m[2] = 2;
    460   m[3] = 3;
    461   m[4] = 4;
    462 
    463   EXPECT_EQ(4u, m.size());
    464   EXPECT_EQ(0u, m.count(0));
    465 
    466   m[5] = 5;
    467   EXPECT_EQ(6u, m.size());
    468   // Our function adds an extra item when we convert to a map.
    469   EXPECT_EQ(1u, m.count(0));
    470 }
    471 
    472 TEST(SmallMap, SubclassInitializationWithFunctionObject) {
    473   SmallMap<hash_map_add_item, 4, std::equal_to<int>,
    474       hash_map_add_item_initializer> m(hash_map_add_item_initializer(-1));
    475 
    476   EXPECT_TRUE(m.empty());
    477 
    478   m[1] = 1;
    479   m[2] = 2;
    480   m[3] = 3;
    481   m[4] = 4;
    482 
    483   EXPECT_EQ(4u, m.size());
    484   EXPECT_EQ(0u, m.count(-1));
    485 
    486   m[5] = 5;
    487   EXPECT_EQ(6u, m.size());
    488   // Our functor adds an extra item when we convert to a map.
    489   EXPECT_EQ(1u, m.count(-1));
    490 }
    491 
    492 }  // namespace base
    493