mdds
block_funcs.hpp
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*************************************************************************
3 *
4 * Copyright (c) 2022 Kohei Yoshida
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 *
27 ************************************************************************/
28
29#pragma once
30
31#include "./types.hpp"
32#include "../global.hpp"
33
34#include <unordered_map>
35#include <functional>
36#include <sstream>
37
38namespace mdds { namespace mtv {
39
40namespace detail {
41
42inline void throw_unknown_block(const char* func, const mdds::mtv::element_t type)
43{
44 std::ostringstream os;
45 os << func << ": failed to map to a element block function (type=" << type << ")";
46 throw general_error(os.str());
47}
48
49template<typename Ret, typename... Args>
50auto& find_func(
51 const std::unordered_map<element_t, std::function<Ret(Args...)>>& func_map, element_t type,
52 const char* src_func_name)
53{
54 auto it = func_map.find(type);
55 if (it == func_map.end())
56 detail::throw_unknown_block(src_func_name, type);
57
58 return it->second;
59}
60
61} // namespace detail
62
63template<typename... Ts>
65{
66 static base_element_block* create_new_block(element_t type, std::size_t init_size)
67 {
68 static const std::unordered_map<element_t, std::function<base_element_block*(std::size_t)>> func_map{
69 {Ts::block_type, Ts::create_block}...};
70
71 auto& f = detail::find_func(func_map, type, __func__);
72 return f(init_size);
73 }
74
75 static base_element_block* clone_block(const base_element_block& block)
76 {
77 static const std::unordered_map<element_t, std::function<base_element_block*(const base_element_block&)>>
78 func_map{{Ts::block_type, Ts::clone_block}...};
79
80 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
81 return f(block);
82 }
83
84 static void delete_block(const base_element_block* p)
85 {
86 if (!p)
87 return;
88
89 static const std::unordered_map<element_t, std::function<void(const base_element_block*)>> func_map{
90 {Ts::block_type, Ts::delete_block}...};
91
92 // TODO: We should not throw an exception here as this gets called
93 // from a destructor and destructors should not throw exceptions.
94 auto& f = detail::find_func(func_map, get_block_type(*p), __func__);
95 f(p);
96 }
97
98 static void resize_block(base_element_block& block, std::size_t new_size)
99 {
100 static const std::unordered_map<element_t, std::function<void(base_element_block&, std::size_t)>> func_map{
101 {Ts::block_type, Ts::resize_block}...};
102
103 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
104 f(block, new_size);
105 }
106
107 static void print_block(const base_element_block& block)
108 {
109 static const std::unordered_map<element_t, std::function<void(const base_element_block&)>> func_map{
110 {Ts::block_type, Ts::print_block}...};
111
112 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
113 f(block);
114 }
115
116 static void erase(base_element_block& block, std::size_t pos)
117 {
118 static const std::unordered_map<element_t, std::function<void(base_element_block&, std::size_t)>> func_map{
119 {Ts::block_type, Ts::erase_value}...};
120
121 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
122 f(block, pos);
123 }
124
125 static void erase(base_element_block& block, std::size_t pos, std::size_t size)
126 {
127 static const std::unordered_map<element_t, std::function<void(base_element_block&, std::size_t, std::size_t)>>
128 func_map{{Ts::block_type, Ts::erase_values}...};
129
130 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
131 f(block, pos, size);
132 }
133
134 static void append_block(base_element_block& dest, const base_element_block& src)
135 {
136 static const std::unordered_map<element_t, std::function<void(base_element_block&, const base_element_block&)>>
137 func_map{{Ts::block_type, Ts::append_block}...};
138
139 auto& f = detail::find_func(func_map, get_block_type(dest), __func__);
140 f(dest, src);
141 }
142
143 static void append_values_from_block(
144 base_element_block& dest, const base_element_block& src, std::size_t begin_pos, std::size_t len)
145 {
146 using func_type = std::function<void(base_element_block&, const base_element_block&, std::size_t, std::size_t)>;
147 static const std::unordered_map<element_t, func_type> func_map{
148 {Ts::block_type, Ts::append_values_from_block}...};
149
150 auto& f = detail::find_func(func_map, get_block_type(dest), __func__);
151 f(dest, src, begin_pos, len);
152 }
153
154 static void assign_values_from_block(
155 base_element_block& dest, const base_element_block& src, std::size_t begin_pos, std::size_t len)
156 {
157 using func_type = std::function<void(base_element_block&, const base_element_block&, std::size_t, std::size_t)>;
158 static const std::unordered_map<element_t, func_type> func_map{
159 {Ts::block_type, Ts::assign_values_from_block}...};
160
161 auto& f = detail::find_func(func_map, get_block_type(dest), __func__);
162 f(dest, src, begin_pos, len);
163 }
164
165 static void prepend_values_from_block(
166 base_element_block& dest, const base_element_block& src, std::size_t begin_pos, std::size_t len)
167 {
168 using func_type = std::function<void(base_element_block&, const base_element_block&, std::size_t, std::size_t)>;
169 static const std::unordered_map<element_t, func_type> func_map{
170 {Ts::block_type, Ts::prepend_values_from_block}...};
171
172 auto& f = detail::find_func(func_map, get_block_type(dest), __func__);
173 f(dest, src, begin_pos, len);
174 }
175
176 static void swap_values(
177 base_element_block& blk1, base_element_block& blk2, std::size_t pos1, std::size_t pos2, std::size_t len)
178 {
179 element_t blk1_type = get_block_type(blk1);
180 assert(blk1_type == get_block_type(blk2));
181
182 using func_type =
183 std::function<void(base_element_block&, base_element_block&, std::size_t, std::size_t, std::size_t)>;
184 static const std::unordered_map<element_t, func_type> func_map{{Ts::block_type, Ts::swap_values}...};
185
186 auto& f = detail::find_func(func_map, blk1_type, __func__);
187 f(blk1, blk2, pos1, pos2, len);
188 }
189
190 static bool equal_block(const base_element_block& left, const base_element_block& right)
191 {
192 element_t block_type = get_block_type(left);
193 if (block_type != get_block_type(right))
194 return false;
195
196 using func_type = std::function<bool(const base_element_block&, const base_element_block&)>;
197 static const std::unordered_map<element_t, func_type> func_map{{Ts::block_type, Ts::equal_block}...};
198
199 auto& f = detail::find_func(func_map, block_type, __func__);
200 return f(left, right);
201 }
202
203 static void overwrite_values(base_element_block& block, std::size_t pos, std::size_t len)
204 {
205 using func_type = std::function<void(base_element_block&, std::size_t, std::size_t)>;
206 static const std::unordered_map<element_t, func_type> func_map{{Ts::block_type, Ts::overwrite_values}...};
207
208 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
209 f(block, pos, len);
210 }
211
212 static void shrink_to_fit(base_element_block& block)
213 {
214 using func_type = std::function<void(base_element_block&)>;
215 static const std::unordered_map<element_t, func_type> func_map{{Ts::block_type, Ts::shrink_to_fit}...};
216
217 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
218 f(block);
219 }
220
221 static std::size_t size(const base_element_block& block)
222 {
223 using func_type = std::function<std::size_t(const base_element_block&)>;
224 static const std::unordered_map<element_t, func_type> func_map{{Ts::block_type, Ts::size}...};
225
226 auto& f = detail::find_func(func_map, get_block_type(block), __func__);
227 return f(block);
228 }
229};
230
231}} // namespace mdds::mtv
232
233/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Definition: types.hpp:160
Definition: block_funcs.hpp:65