libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

ordered_map.cpp (9003B)


      1 #include "libshit/container/ordered_map.hpp"
      2 
      3 #include "libshit/doctest.hpp"
      4 #include "libshit/utils.hpp"
      5 
      6 #include <ostream>
      7 #include <string>
      8 
      9 namespace Libshit::Test
     10 {
     11   TEST_SUITE_BEGIN("Libshit::OrderedMap");
     12   namespace
     13   {
     14     struct OMItemTest final : public OrderedMapItem, public Lua::DynamicObject
     15     {
     16       LIBSHIT_DYNAMIC_OBJECT;
     17     public:
     18       OMItemTest(std::string k, int v) : k{Move(k)}, v{v} { ++count; }
     19       ~OMItemTest() { --count; }
     20       OMItemTest(const OMItemTest&) = delete;
     21       void operator=(const OMItemTest&) = delete;
     22 
     23       std::string k;
     24       int v;
     25       static size_t count;
     26 
     27       bool operator==(const OMItemTest& o) const noexcept
     28       { return k == o.k && v == o.v; }
     29     };
     30     std::ostream& operator<<(std::ostream& os, const OMItemTest& i)
     31     { return os << "OMItemTest{" << i.k << ", " << i.v << '}'; }
     32     size_t OMItemTest::count;
     33 
     34     struct OMItemTestTraits
     35     {
     36       using type = std::string;
     37       const std::string& operator()(const OMItemTest& x) { return x.k; }
     38     };
     39 
     40     using X = OMItemTest;
     41     using OM = OrderedMap<OMItemTest, OMItemTestTraits>;
     42   }
     43 
     44   TEST_CASE("basic test")
     45   {
     46     X::count = 0;
     47     {
     48       OM om;
     49       CHECK(om.empty());
     50       CHECK(om.size() == 0);
     51       om.emplace_back("foo",2);
     52       om.emplace_back("bar",7);
     53       CHECK(!om.empty());
     54       CHECK(om.size() == 2);
     55 
     56       SUBCASE("at")
     57       {
     58         CHECK(om.at(0) == X("foo", 2));
     59         CHECK(om.at(1) == X("bar", 7));
     60         CHECK_THROWS(om.at(2));
     61       }
     62 
     63       SUBCASE("operator[]")
     64       {
     65         CHECK(om[0] == X("foo", 2));
     66         CHECK(om[1] == X("bar", 7));
     67       }
     68 
     69       SUBCASE("front/back")
     70       {
     71         CHECK(om.front() == X("foo", 2));
     72         CHECK(om.back() == X("bar", 7));
     73       }
     74 
     75       SUBCASE("iterator")
     76       {
     77         auto it = om.begin();
     78         REQUIRE(it != om.end());
     79         CHECK(it->k == "foo");
     80         ++it;
     81         REQUIRE(it != om.end());
     82         CHECK(*it == X("bar", 7));
     83         ++it;
     84         CHECK(it == om.end());
     85       }
     86 
     87       SUBCASE("reserve")
     88       {
     89         CHECK(om.capacity() >= 2);
     90         om.reserve(10);
     91         REQUIRE(om.size() == 2);
     92         CHECK(om.capacity() >= 10);
     93 
     94         CHECK(om[1] == X("bar", 7));
     95       }
     96 
     97       SUBCASE("clear")
     98       {
     99         om.clear();
    100         CHECK(om.empty());
    101       }
    102 
    103       SUBCASE("insert")
    104       {
    105         om.insert(om.begin()+1, MakeSmart<X>("def", 9));
    106         REQUIRE(om.size() == 3);
    107         CHECK(om[0] == X("foo", 2));
    108         CHECK(om[1] == X("def", 9));
    109         CHECK(om[2] == X("bar", 7));
    110       }
    111 
    112       SUBCASE("insert existing")
    113       {
    114         om.insert(om.begin(), MakeSmart<X>("bar", -1));
    115         REQUIRE(om.size() == 2);
    116         CHECK(om[0] == X("foo", 2));
    117         CHECK(om[1] == X("bar", 7));
    118       }
    119 
    120       SUBCASE("emplace")
    121       {
    122         om.emplace(om.begin(), "aa", 5);
    123         REQUIRE(om.size() == 3);
    124         CHECK(om[0] == X("aa", 5));
    125         CHECK(om[1] == X("foo", 2));
    126         CHECK(om[2] == X("bar", 7));
    127       }
    128 
    129       SUBCASE("emplace existing")
    130       {
    131         om.emplace(om.begin(), "foo", -1);
    132         REQUIRE(om.size() == 2);
    133         CHECK(om[0] == X("foo", 2));
    134         CHECK(om[1] == X("bar", 7));
    135       }
    136 
    137       SUBCASE("erase one")
    138       {
    139         om.erase(om.begin());
    140         REQUIRE(om.size() == 1);
    141         CHECK(om[0] == X("bar", 7));
    142       }
    143 
    144       SUBCASE("erase range")
    145       {
    146         om.erase(om.begin(), om.begin()+1);
    147         REQUIRE(om.size() == 1);
    148         CHECK(om[0] == X("bar", 7));
    149       }
    150 
    151       SUBCASE("erase everything")
    152       {
    153         om.erase(om.begin(), om.end());
    154         CHECK(om.empty());
    155       }
    156 
    157       SUBCASE("push_back")
    158       {
    159         om.push_back(MakeSmart<X>("zed",3));
    160         REQUIRE(om.size() == 3);
    161         CHECK(om[0] == X("foo", 2));
    162         CHECK(om[1] == X("bar", 7));
    163         CHECK(om[2] == X("zed", 3));
    164       }
    165 
    166       SUBCASE("push_back existing")
    167       {
    168         om.push_back(MakeSmart<X>("bar",77));
    169         REQUIRE(om.size() == 2);
    170         CHECK(om[0] == X("foo", 2));
    171         CHECK(om[1] == X("bar", 7));
    172       }
    173 
    174       SUBCASE("pop_back")
    175       {
    176         om.pop_back();
    177         REQUIRE(om.size() == 1);
    178         CHECK(om[0] == X("foo", 2));
    179         om.pop_back();
    180         REQUIRE(om.empty());
    181       }
    182 
    183       SUBCASE("nth")
    184       {
    185         CHECK(om.nth(0) == om.begin());
    186         CHECK(om.nth(0)->k == "foo");
    187         CHECK(*om.nth(1) == X("bar", 7));
    188         CHECK(om.nth(2) == om.end());
    189         CHECK(om.index_of(om.nth(1)) == 1);
    190       }
    191 
    192       SUBCASE("map find")
    193       {
    194         CHECK(om.count("foo") == 1);
    195         CHECK(om.count("baz") == 0);
    196         CHECK(*om.find("foo") == X("foo", 2));
    197         CHECK(om.find("baz") == om.end());
    198       }
    199 
    200       SUBCASE("iterator_to")
    201       {
    202         X& x = om[1];
    203         CHECK(om.iterator_to(x) == om.nth(1));
    204       }
    205 
    206       SUBCASE("key_change")
    207       {
    208         om[0].k = "abc";
    209         CHECK(om.count("abc") == 0); // wrong rb-tree
    210         om.key_change(om.begin());
    211         CHECK(om.count("abc") == 1); // fixed
    212       }
    213     }
    214     CHECK(X::count == 0);
    215   }
    216 
    217 #if LIBSHIT_WITH_LUA
    218   TEST_CASE("lua binding")
    219   {
    220     Lua::State vm;
    221     auto om = MakeSmart<OM>();
    222     vm.Push(om);
    223     lua_setglobal(vm, "om");
    224     vm.DoString("it = libshit.test.om_item_test");
    225 
    226     SUBCASE("lua push_back")
    227     {
    228       vm.DoString("om:push_back(it('xy',2))");
    229       CHECK(om->size() == 1);
    230       CHECK(om->at(0) == X("xy", 2));
    231     }
    232 
    233     SUBCASE("lua insert")
    234     {
    235       vm.DoString("return om:insert(0, it('bar', 7))");
    236       REQUIRE(lua_gettop(vm) == 2);
    237       CHECK(vm.Get<bool>(-2));
    238       CHECK(vm.Get<int>(-1) == 0);
    239       lua_pop(vm, 2);
    240 
    241       vm.DoString("return om:insert(0, it('foo', 2))");
    242       REQUIRE(lua_gettop(vm) == 2);
    243       CHECK(vm.Get<bool>(-2));
    244       CHECK(vm.Get<int>(-1) == 0);
    245       lua_pop(vm, 2);
    246 
    247       vm.DoString("return om:insert(0, it('bar', 13))");
    248       REQUIRE(lua_gettop(vm) == 2);
    249       CHECK(!vm.Get<bool>(-2));
    250       CHECK(vm.Get<int>(-1) == 1);
    251       lua_pop(vm, 2);
    252 
    253       CHECK(om->size() == 2);
    254       CHECK(om->at(0) == X("foo", 2));
    255       CHECK(om->at(1) == X("bar", 7));
    256     }
    257 
    258     SUBCASE("populate")
    259     {
    260       om->emplace_back("abc", 7);
    261       om->emplace_back("xyz", -2);
    262       om->emplace_back("foo", 5);
    263 
    264       SUBCASE("get")
    265       {
    266         vm.DoString("return om[0]");
    267         REQUIRE(lua_gettop(vm) == 1);
    268         CHECK(vm.Get<X>(-1) == X("abc", 7));
    269         lua_pop(vm, 1);
    270 
    271         vm.DoString("return om[3]");
    272         REQUIRE(lua_gettop(vm) == 1);
    273         CHECK(lua_isnil(vm, -1));
    274         lua_pop(vm, 1);
    275 
    276         vm.DoString("return om.xyz");
    277         REQUIRE(lua_gettop(vm) == 1);
    278         CHECK(vm.Get<X>(-1) == X("xyz", -2));
    279         lua_pop(vm, 1);
    280 
    281         vm.DoString("return om.blahblah");
    282         REQUIRE(lua_gettop(vm) == 1);
    283         CHECK(lua_isnil(vm, -1));
    284         lua_pop(vm, 1);
    285 
    286         vm.DoString("return om[{}]");
    287         REQUIRE(lua_gettop(vm) == 1);
    288         CHECK(lua_isnil(vm, -1));
    289         lua_pop(vm, 1);
    290       }
    291 
    292       SUBCASE("erase")
    293       {
    294         vm.DoString("return om:erase(1)");
    295         REQUIRE(lua_gettop(vm) == 1);
    296 
    297         CHECK(vm.Get<size_t>(-1) == 1);
    298         CHECK(om->size() == 2);
    299         CHECK(om->at(0) == X("abc", 7));
    300         CHECK(om->at(1) == X("foo", 5));
    301         lua_pop(vm, 1);
    302       }
    303 
    304       SUBCASE("erase range")
    305       {
    306         vm.DoString("return om:erase(1, 3)");
    307         REQUIRE(lua_gettop(vm) == 1);
    308 
    309         CHECK(vm.Get<size_t>(-1) == 1);
    310         CHECK(om->size() == 1);
    311         CHECK(om->at(0) == X("abc", 7));
    312         lua_pop(vm, 1);
    313       }
    314 
    315       SUBCASE("remove")
    316       {
    317         vm.DoString("return om:remove(1)");
    318         REQUIRE(lua_gettop(vm) == 1);
    319 
    320         CHECK(vm.Get<X>(-1) == X("xyz", -2));
    321         CHECK(om->size() == 2);
    322         CHECK(om->at(0) == X("abc", 7));
    323         CHECK(om->at(1) == X("foo", 5));
    324         lua_pop(vm, 1);
    325       }
    326 
    327       SUBCASE("find")
    328       {
    329         vm.DoString("return om:find('xyz')");
    330         REQUIRE(lua_gettop(vm) == 2);
    331         CHECK(vm.Get<size_t>(-2) == 1);
    332         CHECK(vm.Get<X>(-1) == X("xyz", -2));
    333         lua_pop(vm, 2);
    334 
    335         vm.DoString("return om:find('not')");
    336         REQUIRE(lua_gettop(vm) == 1);
    337         CHECK(lua_isnil(vm, -1));
    338         lua_pop(vm, 1);
    339       }
    340 
    341       SUBCASE("to_table")
    342       {
    343         vm.DoString(R"(
    344 local t = om:to_table()
    345 assert(type(t) == 'table')
    346 assert(t[0].k == 'abc' and t[0].v == 7)
    347 assert(t[1].k == 'xyz' and t[1].v == -2)
    348 assert(t[2].k == 'foo' and t[2].v == 5)
    349 assert(t[3] == nil)
    350 )");
    351       }
    352 
    353       SUBCASE("ipairs")
    354       {
    355         vm.DoString(R"(
    356 local nexti = 0
    357 local map = {[0] = {k='abc',v=7}, {k='xyz',v=-2}, {k='foo',v=5} }
    358 for i,v in ipairs(om) do
    359   assert(i == nexti) nexti = i+1
    360   assert(v.k == map[i].k)
    361   assert(v.v == map[i].v)
    362 end
    363 assert(nexti == 3)
    364 )");
    365       }
    366     }
    367   }
    368 #endif
    369   TEST_SUITE_END();
    370 }
    371 
    372 #include <libshit/container/ordered_map.lua.hpp>
    373 LIBSHIT_ORDERED_MAP_LUAGEN(
    374   om_item_test, Libshit::Test::OMItemTest, Libshit::Test::OMItemTestTraits);
    375 #include "ordered_map.binding.hpp"