include/simdb/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
40 / 40
100.0%
Branches:
46 / 76
60.5%
Functions:
6 / 6
100.0%

utils/TinyStrings.hpp
Line Branch Exec Source
1 // <TinyStrings.hpp> -*- C++ -*-
2
3 #pragma once
4
5 #include "simdb/Assert.hpp"
6 #include "simdb/Exceptions.hpp"
7 #include "simdb/sqlite/DatabaseManager.hpp"
8 #include "simdb/sqlite/PreparedINSERT.hpp"
9 #include "simdb/utils/DeferredLock.hpp"
10 #include "simdb/utils/TypeTraits.hpp"
11 #include <mutex>
12
13 namespace simdb {
14
15 namespace detail {
16 static inline constexpr uint32_t BAD_STRING_ID = 0;
17 }
18
19 /// To keep SimDB collection as fast and small as possible, we serialize strings
20 /// not as actual strings, but as ints. This class is used to map strings to
21 /// ints in memory, and may be serialized to a database table at teardown.
22 template <bool MutexProtect = false> class TinyStrings
23 {
24 public:
25 6 TinyStrings() = default;
26
27 /// Add or get a string ID for the given string.
28 std::pair<uint32_t, bool> insert(const std::string& s)
29 {
30 DeferredLock<std::mutex> lock(mutex_);
31 if constexpr (MutexProtect)
32 {
33 lock.lock();
34 }
35
36 auto iter = map_->find(s);
37 if (iter == map_->end())
38 {
39 return std::make_pair(getStringID_(s), true);
40 } else
41 {
42 return std::make_pair(getStringID_(s), false);
43 }
44 }
45
46 /// Get a string ID for the given string
47 116397 uint32_t getStringID(const std::string& s)
48 {
49
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 116396 times.
116397 if (s.empty())
50 {
51 1 return detail::BAD_STRING_ID;
52 }
53
54 116396 DeferredLock<std::mutex> lock(mutex_);
55 if constexpr (MutexProtect)
56 {
57 lock.lock();
58 }
59
60
1/1
✓ Branch 6 → 7 taken 116396 times.
116396 return getStringID_(s);
61 116396 }
62
63 /// Get a string ID for the given string
64 5 uint32_t getStringID(const char* s)
65 {
66
1/9
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 13 taken 5 times.
✗ Branch 4 → 5 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 11 → 12 not taken.
5 simdb_assert(s != nullptr);
67
2/2
✓ Branch 15 → 16 taken 5 times.
✓ Branch 16 → 17 taken 5 times.
10 return getStringID(std::string(s));
68 }
69
70 /// Get a string ID for the given string (pointer)
71 template <typename S>
72 type_traits::enable_if_t<!type_traits::is_char_pointer_v<S> && type_traits::is_any_pointer_v<S>, uint32_t>
73 getStringID(const S& s)
74 {
75 if (s)
76 {
77 return getStringID(*s);
78 }
79 return detail::BAD_STRING_ID;
80 }
81
82 /// Serialize newly seen string mappings to the database.
83 8 void serialize(DatabaseManager* db_mgr)
84 {
85
1/12
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 21 taken 8 times.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 19 → 20 not taken.
8 simdb_assert(db_mgr, "TinyStrings::serialize requires a DatabaseManager");
86
87
1/1
✓ Branch 23 → 24 taken 7 times.
16 db_mgr->safeTransaction([&]() {
88 8 DeferredLock<std::mutex> lock(mutex_);
89 if constexpr (MutexProtect)
90 {
91 lock.lock();
92 }
93
94
2/2
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 2 times.
8 if (allowed_db_ == nullptr)
95 {
96 6 allowed_db_ = db_mgr;
97 } else
98 {
99
12/12
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 24 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
4 simdb_assert(allowed_db_ == db_mgr, "TinyStrings::serialize may only target one DatabaseManager");
100 }
101
102 7 const auto& schema = db_mgr->getSchema();
103
3/3
✓ Branch 27 → 28 taken 7 times.
✓ Branch 31 → 32 taken 6 times.
✓ Branch 31 → 54 taken 1 time.
14 if (!schema.hasTable("TinyStringIDs"))
104 {
105
1/1
✓ Branch 32 → 33 taken 6 times.
6 Schema append_schema;
106 using dt = simdb::SqlDataType;
107
2/2
✓ Branch 35 → 36 taken 6 times.
✓ Branch 36 → 37 taken 6 times.
12 auto& tbl = append_schema.addTable("TinyStringIDs");
108
2/2
✓ Branch 41 → 42 taken 6 times.
✓ Branch 42 → 43 taken 6 times.
12 tbl.addColumn("StringValue", dt::string_t);
109
2/2
✓ Branch 47 → 48 taken 6 times.
✓ Branch 48 → 49 taken 6 times.
6 tbl.addColumn("StringID", dt::uint32_t);
110
1/1
✓ Branch 51 → 52 taken 6 times.
6 db_mgr->appendSchema(append_schema);
111 6 }
112
113
2/2
✓ Branch 55 → 56 taken 7 times.
✓ Branch 56 → 57 taken 7 times.
7 auto inserter = db_mgr->prepareINSERT(SQL_TABLE("TinyStringIDs"));
114
2/2
✓ Branch 67 → 60 taken 89759 times.
✓ Branch 67 → 68 taken 7 times.
89766 for (const auto& [string_id, string_val] : unserialized_map_)
115 {
116
1/1
✓ Branch 64 → 65 taken 89759 times.
89759 inserter->createRecordWithColValues(string_val, string_id);
117 }
118
119 7 unserialized_map_.clear();
120 8 });
121 7 }
122
123 private:
124 116396 uint32_t getStringID_(const std::string& s)
125 {
126
1/1
✓ Branch 3 → 4 taken 116396 times.
116396 auto iter = map_->find(s);
127
2/2
✓ Branch 7 → 8 taken 89759 times.
✓ Branch 7 → 39 taken 26637 times.
116396 if (iter == map_->end())
128 {
129
1/12
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 29 taken 89759 times.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 27 → 28 not taken.
89759 simdb_assert(map_->size() != UINT32_MAX, "Too many TinyStrings created. UINT32_MAX has been reached.");
130
131 89759 uint32_t id = map_->size() + 1;
132
2/2
✓ Branch 32 → 33 taken 89759 times.
✓ Branch 33 → 34 taken 89759 times.
89759 map_->insert({s, id});
133
2/2
✓ Branch 35 → 36 taken 89759 times.
✓ Branch 36 → 37 taken 89759 times.
89759 unserialized_map_.insert({id, s});
134 89759 return id;
135 } else
136 {
137 26637 return iter->second;
138 }
139 }
140
141 using string_map_t = std::shared_ptr<std::unordered_map<std::string, uint32_t>>;
142 using unserialized_string_map_t = std::unordered_map<uint32_t, std::string>;
143
144 string_map_t map_ = std::make_shared<std::unordered_map<std::string, uint32_t>>();
145 unserialized_string_map_t unserialized_map_;
146
147 DatabaseManager* allowed_db_ = nullptr;
148 mutable std::mutex mutex_;
149 };
150
151 } // namespace simdb
152