summaryrefslogtreecommitdiffstats
path: root/src/parser/string_pool_test.cpp
blob: 7d3f8644f41ac25c0e64df72a5e6ef4cef49a49e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "test_global.hpp"
#include <orcus/string_pool.hpp>

#include <type_traits>

using namespace orcus;

void test_basic()
{
    const char* static_text = "test";

    string_pool pool;
    assert(pool.size() == 0);

    std::pair<std::string_view, bool> ret = pool.intern("foo");
    assert(ret.first == "foo");
    assert(ret.second); // new instance

    ret = pool.intern("foo");
    assert(ret.first == "foo");
    assert(!ret.second); // existing instance.

    // Empty strings should not be interned.
    ret = pool.intern("");
    assert(ret.first.empty());
    assert(!ret.second);

    ret = pool.intern("A");
    std::cout << "interned string: " << ret.first << std::endl;
    assert(ret.second);
    assert(pool.size() == 2);

    // Duplicate string.
    ret = pool.intern("A");
    std::cout << "interned string: " << ret.first << std::endl;
    assert(!ret.second);

    ret = pool.intern("B");
    std::cout << "interned string: " << ret.first << std::endl;
    assert(pool.size() == 3);

    // Interning an already-intern string should return a string_view with
    // identical memory address.
    std::string_view str = ret.first;
    std::string_view str2 = pool.intern(str).first;
    assert(str == str2);
    assert(pool.size() == 3);
    assert(str.data() == str2.data()); // their memory address should be identical.

    std::string_view static_str(static_text);
    ret = pool.intern(static_str);
    str = ret.first;
    std::cout << "interned string: " << str << std::endl;
    assert(pool.size() == 4);
    assert(str == static_str);
    assert(str.data() != static_str.data());

    // Make sure that the pool remains usable after calling clear().
    pool.clear();
    assert(pool.size() == 0);
    ret = pool.intern(static_str);
    assert(ret.second); // it should be a new string
    assert(ret.first == static_str);
}

void test_merge()
{
    string_pool pool1;
    std::unique_ptr<string_pool> pool2(std::make_unique<string_pool>());

    pool1.intern("A");
    pool1.intern("B");
    pool1.intern("C");
    std::string_view v1 = pool1.intern("same value").first;

    pool2->intern("D");
    pool2->intern("E");
    pool2->intern("F");
    std::string_view v2 = pool2->intern("same value").first;

    assert(pool1.size() == 4);
    assert(pool2->size() == 4);

    pool1.merge(*pool2);

    assert(pool1.size() == 7);
    assert(pool2->size() == 0);

    pool2.reset(); // Delete the pool2 instance altogether.

    // This should not create a new entry.
    auto r = pool1.intern("F");
    assert(!r.second);

    // v2 still points to the original string in pool2, which should now be in
    // the merged store in pool1 (thus valid).
    assert(v1 == v2);

    std::vector<std::string_view> entries = pool1.get_interned_strings();
    assert(entries.size() == pool1.size());
}

void test_move()
{
    static_assert(!std::is_copy_constructible_v<orcus::string_pool>);
    static_assert(std::is_move_constructible_v<orcus::string_pool>);

    string_pool pool1;
    pool1.intern("A");
    pool1.intern("B");
    pool1.intern("C");
    pool1.intern("D");
    pool1.intern("E");

    string_pool pool2 = std::move(pool1);
    assert(pool2.size() == 5);
}

int main()
{
    test_basic();
    test_merge();
    test_move();

    return EXIT_SUCCESS;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */