mdds
Loading...
Searching...
No Matches
types.hpp
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3// SPDX-FileCopyrightText: 2021 - 2025 Kohei Yoshida
4//
5// SPDX-License-Identifier: MIT
6
7#pragma once
8
9#include "../global.hpp"
10#include "./types_util.hpp"
11#include "./delayed_delete_vector.hpp"
12
13#include <algorithm>
14#include <cassert>
15#include <memory>
16#include <cstdint>
17#include <vector>
18#include <sstream>
19
20#if defined(MDDS_UNIT_TEST) || defined(MDDS_MULTI_TYPE_VECTOR_DEBUG)
21#include <iostream>
22#endif
23
24namespace mdds { namespace mtv {
25
26using element_t = int;
27
28constexpr element_t element_type_empty = -1;
29
30constexpr element_t element_type_reserved_start = 0;
31constexpr element_t element_type_reserved_end = 49;
32
33constexpr element_t element_type_user_start = 50;
34
41enum class lu_factor_t : int
42{
43 none = 0,
44 lu4 = 4,
45 lu8 = 8,
46 lu16 = 16,
47 lu32 = 32,
48 sse2_x64 = 1 << 8,
49 sse2_x64_lu4 = 1 << 8 | 4,
50 sse2_x64_lu8 = 1 << 8 | 8,
51 sse2_x64_lu16 = 1 << 8 | 16,
52 avx2_x64 = 2 << 8,
53 avx2_x64_lu4 = 2 << 8 | 4,
54 avx2_x64_lu8 = 2 << 8 | 8,
55};
56
76enum class trace_method_t : int
77{
78 unspecified = 0,
79 accessor = 1,
80 accessor_with_pos_hint = 1 << 8 | 1,
81 mutator = 2,
82 mutator_with_pos_hint = 1 << 8 | 2,
83 constructor = 3,
84 destructor = 4
85};
86
91{
92 trace_method_t type = trace_method_t::unspecified;
93
99 const void* instance = nullptr;
100
102 const char* function_name = nullptr;
103
108 std::string function_args;
109
111 const char* filepath = nullptr;
112
114 int line_number = -1;
115};
116
120class element_block_error : public mdds::general_error
121{
122public:
123 element_block_error(const std::string& msg) : mdds::general_error(msg)
124 {}
125};
126
128element_t get_block_type(const base_element_block&) noexcept;
129
134class base_element_block
135{
136 friend element_t get_block_type(const base_element_block&) noexcept;
137
138protected:
139 element_t type;
140 base_element_block(element_t _t) noexcept : type(_t)
141 {}
142};
143
147template<typename ValueT>
149
156template<typename BlockT, typename = void>
158{
159 using store_type = typename BlockT::store_type;
160
161 BlockT* operator()(const BlockT& blk) const
162 {
163 auto bt = get_block_type(blk);
164 std::ostringstream os;
165 os << "cloning of this block type is not implemented (type=" << bt << ")";
166 throw element_block_error(os.str());
167 }
168};
169
175template<typename BlockT>
176struct clone_block<BlockT, std::enable_if_t<std::is_copy_constructible<BlockT>::value>>
177{
178 using store_type = typename BlockT::store_type;
179
180 BlockT* operator()(const BlockT& src) const
181 {
182 return new BlockT(src);
183 }
184};
185
192template<typename BlockT>
193struct clone_block<BlockT, std::void_t<decltype(clone_value<typename BlockT::value_type>{})>>
194{
195 using store_type = typename BlockT::store_type;
196 using value_type = typename BlockT::value_type;
197 using CV = clone_value<value_type>;
198
199 BlockT* operator()(const BlockT& src) const
200 {
201 auto dest_blk = std::make_unique<BlockT>();
202 auto cloned(src.store());
203
205 std::transform(typename CV::exec_policy{}, cloned.begin(), cloned.end(), cloned.begin(), CV{});
206 else
207 std::transform(cloned.begin(), cloned.end(), cloned.begin(), CV{});
208
209 dest_blk->store().swap(cloned);
210 return dest_blk.release();
211 }
212};
213
214template<typename Self, element_t TypeId, typename ValueT, template<typename, typename> class StoreT>
215class element_block : public base_element_block
216{
217public:
218 using store_type = StoreT<ValueT, std::allocator<ValueT>>;
219 static constexpr element_t block_type = TypeId;
220
221protected:
222 store_type m_array;
223
224 element_block() noexcept(std::is_nothrow_default_constructible_v<store_type>) : base_element_block(TypeId)
225 {}
226 element_block(size_t n) : base_element_block(TypeId), m_array(n)
227 {}
228 element_block(size_t n, const ValueT& val) : base_element_block(TypeId), m_array(n, val)
229 {}
230
231 template<typename Iter>
232 element_block(const Iter& it_begin, const Iter& it_end) : base_element_block(TypeId), m_array(it_begin, it_end)
233 {}
234
235public:
236 typedef typename store_type::iterator iterator;
237 typedef typename store_type::reverse_iterator reverse_iterator;
238 typedef typename store_type::const_iterator const_iterator;
239 typedef typename store_type::const_reverse_iterator const_reverse_iterator;
240 typedef ValueT value_type;
241
242 const store_type& store() const noexcept
243 {
244 return m_array;
245 }
246
247 store_type& store() noexcept
248 {
249 return m_array;
250 }
251
252private:
253 template<bool Mutable>
254 class base_range_type
255 {
256 using elem_block_type = mdds::detail::mutable_t<base_element_block, Mutable>;
257 elem_block_type& m_blk;
258
259 public:
260 using iter_type = std::conditional_t<Mutable, iterator, const_iterator>;
261
262 base_range_type(elem_block_type& blk) : m_blk(blk)
263 {}
264
265 iter_type begin()
266 {
267 return element_block::begin(m_blk);
268 }
269
270 iter_type end()
271 {
272 return element_block::end(m_blk);
273 }
274 };
275
276 static constexpr bool nothrow_eq_comparable_v = noexcept(std::declval<store_type>() == std::declval<store_type>());
277
278public:
279 using range_type = base_range_type<true>;
280 using const_range_type = base_range_type<false>;
281
282 bool operator==(const Self& r) const noexcept(nothrow_eq_comparable_v)
283 {
284 return m_array == r.m_array;
285 }
286
287 bool operator!=(const Self& r) const noexcept(nothrow_eq_comparable_v)
288 {
289 return !operator==(r);
290 }
291
292 static const value_type& at(const base_element_block& block, typename store_type::size_type pos)
293 {
294 return get(block).m_array.at(pos);
295 }
296
297 static value_type& at(base_element_block& block, typename store_type::size_type pos)
298 {
299 return get(block).m_array.at(pos);
300 }
301
302 static value_type* data(base_element_block& block)
303 {
304 return get(block).m_array.data();
305 }
306
307 static typename store_type::size_type size(const base_element_block& block)
308 {
309 return get(block).m_array.size();
310 }
311
312 static iterator begin(base_element_block& block)
313 {
314 return get(block).m_array.begin();
315 }
316
317 static iterator end(base_element_block& block)
318 {
319 return get(block).m_array.end();
320 }
321
322 static const_iterator begin(const base_element_block& block)
323 {
324 return get(block).m_array.begin();
325 }
326
327 static const_iterator end(const base_element_block& block)
328 {
329 return get(block).m_array.end();
330 }
331
332 static const_iterator cbegin(const base_element_block& block)
333 {
334 return get(block).m_array.begin();
335 }
336
337 static const_iterator cend(const base_element_block& block)
338 {
339 return get(block).m_array.end();
340 }
341
342 static reverse_iterator rbegin(base_element_block& block)
343 {
344 return get(block).m_array.rbegin();
345 }
346
347 static reverse_iterator rend(base_element_block& block)
348 {
349 return get(block).m_array.rend();
350 }
351
352 static const_reverse_iterator rbegin(const base_element_block& block)
353 {
354 return get(block).m_array.rbegin();
355 }
356
357 static const_reverse_iterator rend(const base_element_block& block)
358 {
359 return get(block).m_array.rend();
360 }
361
362 static const_reverse_iterator crbegin(const base_element_block& block)
363 {
364 return get(block).m_array.rbegin();
365 }
366
367 static const_reverse_iterator crend(const base_element_block& block)
368 {
369 return get(block).m_array.rend();
370 }
371
372 static const_range_type range(const base_element_block& block)
373 {
374 return const_range_type(block);
375 }
376
377 static range_type range(base_element_block& block)
378 {
379 return range_type(block);
380 }
381
382 static Self& get(base_element_block& block)
383 {
384#ifdef MDDS_MULTI_TYPE_VECTOR_DEBUG
385 if (get_block_type(block) != TypeId)
386 {
387 std::ostringstream os;
388 os << "incorrect block type: expected block type=" << TypeId
389 << ", passed block type=" << get_block_type(block);
390 throw general_error(os.str());
391 }
392#endif
393 return static_cast<Self&>(block);
394 }
395
396 static const Self& get(const base_element_block& block)
397 {
398#ifdef MDDS_MULTI_TYPE_VECTOR_DEBUG
399 if (get_block_type(block) != TypeId)
400 {
401 std::ostringstream os;
402 os << "incorrect block type: expected block type=" << TypeId
403 << ", passed block type=" << get_block_type(block);
404 throw general_error(os.str());
405 }
406#endif
407 return static_cast<const Self&>(block);
408 }
409
410 static void set_value(base_element_block& blk, size_t pos, const ValueT& val)
411 {
412 get(blk).m_array[pos] = val;
413 }
414
415 static void get_value(const base_element_block& blk, size_t pos, ValueT& val)
416 {
417 val = get(blk).m_array[pos];
418 }
419
420 static value_type get_value(const base_element_block& blk, size_t pos)
421 {
422 return get(blk).m_array[pos];
423 }
424
425 template<typename T = ValueT>
426 static void append_value(base_element_block& blk, T&& val)
427 {
428 get(blk).m_array.push_back(std::forward<T>(val));
429 }
430
431 template<typename... Args>
432 static void emplace_back_value(base_element_block& blk, Args&&... args)
433 {
434 get(blk).m_array.emplace_back(std::forward<Args>(args)...);
435 }
436
437 static void prepend_value(base_element_block& blk, const ValueT& val)
438 {
439 store_type& blk2 = get(blk).m_array;
440 blk2.insert(blk2.begin(), val);
441 }
442
443 static Self* create_block(size_t init_size)
444 {
445 return new Self(init_size);
446 }
447
448 static void delete_block(const base_element_block* p)
449 {
450 delete static_cast<const Self*>(p);
451 }
452
453 static void resize_block(base_element_block& blk, size_t new_size)
454 {
455 store_type& st = get(blk).m_array;
456 st.resize(new_size);
457
458 // Test if the vector's capacity is larger than twice its current
459 // size, and if so, shrink its capacity to free up some memory.
460 if (new_size < (detail::get_block_capacity(st) / 2))
461 detail::shrink_to_fit(st);
462 }
463
464#ifdef MDDS_UNIT_TEST
465 static void print_block(const base_element_block& blk)
466 {
467 const store_type& blk2 = get(blk).m_array;
468 for (const auto& val : blk2)
469 std::cout << val << " ";
470
471 std::cout << std::endl;
472 }
473#else
474 static void print_block(const base_element_block&)
475 {}
476#endif
477
478 static void erase_value(base_element_block& blk, size_t pos)
479 {
480 store_type& blk2 = get(blk).m_array;
481 blk2.erase(blk2.begin() + pos);
482 }
483
484 static void erase_values(base_element_block& blk, size_t pos, size_t size)
485 {
486 store_type& blk2 = get(blk).m_array;
487 blk2.erase(blk2.begin() + pos, blk2.begin() + pos + size);
488 }
489
490 static void append_block(base_element_block& dest, const base_element_block& src)
491 {
492 store_type& d = get(dest).m_array;
493 const store_type& s = get(src).m_array;
494 d.insert(d.end(), s.begin(), s.end());
495 }
496
497 static void append_values_from_block(
498 base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
499 {
500 store_type& d = get(dest).m_array;
501 const store_type& s = get(src).m_array;
502 std::pair<const_iterator, const_iterator> its = get_iterator_pair(s, begin_pos, len);
503 detail::reserve(d, d.size() + len);
504 d.insert(d.end(), its.first, its.second);
505 }
506
507 static void assign_values_from_block(
508 base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
509 {
510 store_type& d = get(dest).m_array;
511 const store_type& s = get(src).m_array;
512 std::pair<const_iterator, const_iterator> its = get_iterator_pair(s, begin_pos, len);
513 d.assign(its.first, its.second);
514 }
515
516 static void prepend_values_from_block(
517 base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
518 {
519 store_type& d = get(dest).m_array;
520 const store_type& s = get(src).m_array;
521 std::pair<const_iterator, const_iterator> its = get_iterator_pair(s, begin_pos, len);
522 detail::reserve(d, d.size() + len);
523 d.insert(d.begin(), its.first, its.second);
524 }
525
526 static void swap_values(base_element_block& blk1, base_element_block& blk2, size_t pos1, size_t pos2, size_t len)
527 {
528 store_type& st1 = get(blk1).m_array;
529 store_type& st2 = get(blk2).m_array;
530 assert(pos1 + len <= st1.size());
531 assert(pos2 + len <= st2.size());
532
533 typename store_type::iterator it1 = st1.begin(), it2 = st2.begin();
534 std::advance(it1, pos1);
535 std::advance(it2, pos2);
536
537 for (size_t i = 0; i < len; ++i, ++it1, ++it2)
538 {
539 value_type v1 = *it1, v2 = *it2;
540 *it1 = v2;
541 *it2 = v1;
542 }
543 }
544
545 static bool equal_block(const base_element_block& left, const base_element_block& right)
546 {
547 return get(left) == get(right);
548 }
549
550 template<typename Iter>
551 static void set_values(base_element_block& block, size_t pos, const Iter& it_begin, const Iter& it_end)
552 {
553 store_type& d = get(block).m_array;
554 typename store_type::iterator it_dest = d.begin();
555 std::advance(it_dest, pos);
556 for (Iter it = it_begin; it != it_end; ++it, ++it_dest)
557 *it_dest = *it;
558 }
559
560 template<typename Iter>
561 static void append_values(base_element_block& block, const Iter& it_begin, const Iter& it_end)
562 {
563 store_type& d = get(block).m_array;
564 typename store_type::iterator it = d.end();
565 d.insert(it, it_begin, it_end);
566 }
567
568 template<typename Iter>
569 static void prepend_values(base_element_block& block, const Iter& it_begin, const Iter& it_end)
570 {
571 store_type& d = get(block).m_array;
572 d.insert(d.begin(), it_begin, it_end);
573 }
574
575 template<typename Iter>
576 static void assign_values(base_element_block& dest, const Iter& it_begin, const Iter& it_end)
577 {
578 store_type& d = get(dest).m_array;
579 d.assign(it_begin, it_end);
580 }
581
582 template<typename Iter>
583 static void insert_values(base_element_block& block, size_t pos, const Iter& it_begin, const Iter& it_end)
584 {
585 store_type& blk = get(block).m_array;
586 blk.insert(blk.begin() + pos, it_begin, it_end);
587 }
588
589 static size_t capacity(const base_element_block& block)
590 {
591 const store_type& blk = get(block).m_array;
592 return detail::get_block_capacity(blk);
593 }
594
595 static void reserve(base_element_block& block, std::size_t size)
596 {
597 store_type& blk = get(block).m_array;
598 detail::reserve(blk, size);
599 }
600
601 static void shrink_to_fit(base_element_block& block)
602 {
603 store_type& blk = get(block).m_array;
604 detail::shrink_to_fit(blk);
605 }
606
607private:
608 static std::pair<const_iterator, const_iterator> get_iterator_pair(
609 const store_type& array, size_t begin_pos, size_t len)
610 {
611 assert(begin_pos + len <= array.size());
612 const_iterator it = array.begin();
613 std::advance(it, begin_pos);
614 const_iterator it_end = it;
615 std::advance(it_end, len);
616 return std::pair<const_iterator, const_iterator>(it, it_end);
617 }
618};
619
620template<typename Self, element_t TypeId, typename ValueT, template<typename, typename> class StoreT>
621class copyable_element_block : public element_block<Self, TypeId, ValueT, StoreT>
622{
623 using base_type = element_block<Self, TypeId, ValueT, StoreT>;
624
625protected:
626 copyable_element_block() noexcept(std::is_nothrow_default_constructible_v<base_type>) : base_type()
627 {}
628 copyable_element_block(size_t n) : base_type(n)
629 {}
630 copyable_element_block(size_t n, const ValueT& val) : base_type(n, val)
631 {}
632
633 template<typename Iter>
634 copyable_element_block(const Iter& it_begin, const Iter& it_end) : base_type(it_begin, it_end)
635 {}
636
637public:
638 using base_type::get;
639
640 static Self* copy_block(const base_element_block& blk)
641 {
642 // Use copy constructor to copy the data.
643 return new Self(get(blk));
644 }
645
646 static Self* clone_block(const base_element_block& src)
647 {
648 return mdds::mtv::clone_block<Self>{}(get(src));
649 }
650};
651
655template<typename Self, element_t TypeId, typename ValueT, template<typename, typename> class StoreT>
656class noncopyable_element_block : public element_block<Self, TypeId, ValueT, StoreT>
657{
658 using base_type = element_block<Self, TypeId, ValueT, StoreT>;
659
660protected:
661 noncopyable_element_block() noexcept(std::is_nothrow_default_constructible_v<base_type>) : base_type()
662 {}
663 noncopyable_element_block(size_t n) : base_type(n)
664 {}
665 noncopyable_element_block(size_t n, const ValueT& val) : base_type(n, val)
666 {}
667
668 template<typename Iter>
669 noncopyable_element_block(const Iter& it_begin, const Iter& it_end) : base_type(it_begin, it_end)
670 {}
671
672public:
673 using base_type::get;
674
675 noncopyable_element_block(const noncopyable_element_block&) = delete;
676 noncopyable_element_block& operator=(const noncopyable_element_block&) = delete;
677
678 static Self* copy_block(const base_element_block&)
679 {
680 throw element_block_error("attempted to copy a noncopyable element block.");
681 }
682
683 static Self* clone_block(const base_element_block& src)
684 {
685 return mdds::mtv::clone_block<Self>{}(get(src));
686 }
687};
688
696inline element_t get_block_type(const base_element_block& blk) noexcept
697{
698 return blk.type;
699}
700
705template<element_t TypeId, typename ValueT, template<typename, typename> class StoreT = delayed_delete_vector>
706struct default_element_block
707 : public copyable_element_block<default_element_block<TypeId, ValueT, StoreT>, TypeId, ValueT, StoreT>
708{
709 using self_type = default_element_block<TypeId, ValueT, StoreT>;
710 using base_type = copyable_element_block<self_type, TypeId, ValueT, StoreT>;
711
712 default_element_block() noexcept(std::is_nothrow_default_constructible_v<base_type>) : base_type()
713 {}
714 default_element_block(size_t n) : base_type(n)
715 {}
716 default_element_block(size_t n, const ValueT& val) : base_type(n, val)
717 {}
718
719 template<typename Iter>
720 default_element_block(const Iter& it_begin, const Iter& it_end) : base_type(it_begin, it_end)
721 {}
722
723 static self_type* create_block_with_value(size_t init_size, const ValueT& val)
724 {
725 return new self_type(init_size, val);
726 }
727
728 template<typename Iter>
729 static self_type* create_block_with_values(const Iter& it_begin, const Iter& it_end)
730 {
731 return new self_type(it_begin, it_end);
732 }
733
734 static void overwrite_values(base_element_block&, size_t, size_t)
735 {
736 // Do nothing.
737 }
738};
739
744template<element_t TypeId, typename ValueT, template<typename, typename> class StoreT = delayed_delete_vector>
745struct managed_element_block
746 : public copyable_element_block<managed_element_block<TypeId, ValueT, StoreT>, TypeId, ValueT*, StoreT>
747{
748 using self_type = managed_element_block<TypeId, ValueT, StoreT>;
749 using base_type = copyable_element_block<self_type, TypeId, ValueT*, StoreT>;
750
751 using base_type::get;
752 using base_type::m_array;
753 using base_type::reserve;
754 using base_type::set_value;
755
756 managed_element_block() noexcept(std::is_nothrow_default_constructible_v<base_type>) : base_type()
757 {}
758 managed_element_block(size_t n) : base_type(n)
759 {}
760 managed_element_block(const managed_element_block& r) : base_type()
761 {
762 detail::reserve(m_array, r.m_array.size());
763 for (const auto& v : r.m_array)
764 m_array.push_back(new ValueT(*v));
765 }
766
767 template<typename Iter>
768 managed_element_block(const Iter& it_begin, const Iter& it_end) : base_type(it_begin, it_end)
769 {}
770
771 ~managed_element_block()
772 {
773 std::for_each(m_array.begin(), m_array.end(), std::default_delete<ValueT>());
774 }
775
776 static self_type* create_block_with_value(size_t init_size, ValueT* val)
777 {
778 // Managed blocks don't support initialization with value.
779 if (init_size > 1)
780 throw general_error("You can't create a managed block with initial value.");
781
782 std::unique_ptr<self_type> blk = std::make_unique<self_type>(init_size);
783 if (init_size == 1)
784 set_value(*blk, 0, val);
785
786 return blk.release();
787 }
788
789 template<typename Iter>
790 static self_type* create_block_with_values(const Iter& it_begin, const Iter& it_end)
791 {
792 return new self_type(it_begin, it_end);
793 }
794
795 static void overwrite_values(base_element_block& block, size_t pos, size_t len)
796 {
797 managed_element_block& blk = get(block);
798 typename managed_element_block::store_type::iterator it = blk.m_array.begin() + pos;
799 typename managed_element_block::store_type::iterator it_end = it + len;
800 std::for_each(it, it_end, std::default_delete<ValueT>());
801 }
802};
803
809template<element_t TypeId, typename ValueT, template<typename, typename> class StoreT = delayed_delete_vector>
810struct noncopyable_managed_element_block
811 : public noncopyable_element_block<
812 noncopyable_managed_element_block<TypeId, ValueT, StoreT>, TypeId, ValueT*, StoreT>
813{
814 using self_type = noncopyable_managed_element_block<TypeId, ValueT, StoreT>;
815 using base_type = noncopyable_element_block<self_type, TypeId, ValueT*, StoreT>;
816
817 using base_type::get;
818 using base_type::m_array;
819 using base_type::set_value;
820
821 noncopyable_managed_element_block() noexcept(std::is_nothrow_default_constructible_v<base_type>) : base_type()
822 {}
823 noncopyable_managed_element_block(size_t n) : base_type(n)
824 {}
825
826 template<typename Iter>
827 noncopyable_managed_element_block(const Iter& it_begin, const Iter& it_end) : base_type(it_begin, it_end)
828 {}
829
830 ~noncopyable_managed_element_block()
831 {
832 std::for_each(m_array.begin(), m_array.end(), std::default_delete<ValueT>());
833 }
834
835 static self_type* create_block_with_value(size_t init_size, ValueT* val)
836 {
837 // Managed blocks don't support initialization with value.
838 if (init_size > 1)
839 throw general_error("You can't create a managed block with initial value.");
840
841 std::unique_ptr<self_type> blk = std::make_unique<self_type>(init_size);
842 if (init_size == 1)
843 set_value(*blk, 0, val);
844
845 return blk.release();
846 }
847
848 template<typename Iter>
849 static self_type* create_block_with_values(const Iter& it_begin, const Iter& it_end)
850 {
851 return new self_type(it_begin, it_end);
852 }
853
854 static void overwrite_values(base_element_block& block, size_t pos, size_t len)
855 {
856 noncopyable_managed_element_block& blk = get(block);
857 typename noncopyable_managed_element_block::store_type::iterator it = blk.m_array.begin() + pos;
858 typename noncopyable_managed_element_block::store_type::iterator it_end = it + len;
859 std::for_each(it, it_end, std::default_delete<ValueT>());
860 }
861
862 static bool equal_block(const base_element_block& left, const base_element_block& right)
863 {
864 const auto& array1 = get(left).m_array;
865 const auto& array2 = get(right).m_array;
866
867 if (array1.size() != array2.size())
868 return false;
869
870 return std::equal(array1.begin(), array1.end(), array2.begin(), [](const ValueT* p1, const ValueT* p2) {
871 return *p1 == *p2;
872 });
873 }
874};
875
876namespace detail {
877
878template<typename Blk>
879bool get_block_element_at(const mdds::mtv::base_element_block& data, size_t offset, std::true_type)
880{
881 auto it = Blk::cbegin(data);
882 std::advance(it, offset);
883 return *it;
884}
885
886template<typename Blk>
887typename Blk::value_type get_block_element_at(const mdds::mtv::base_element_block& data, size_t offset, std::false_type)
888{
889 return Blk::at(data, offset);
890}
891
892template<typename Blk>
893typename Blk::value_type get_block_element_at(const mdds::mtv::base_element_block& data, size_t offset)
894{
895 typename mdds::mtv::detail::has_std_vector_bool_store<Blk>::type v;
896 return get_block_element_at<Blk>(data, offset, v);
897}
898
899} // namespace detail
900
901}} // namespace mdds::mtv
902
903/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Definition global.hpp:60
Definition types.hpp:135
friend element_t get_block_type(const base_element_block &) noexcept
Definition types.hpp:696
Definition delayed_delete_vector.hpp:22
Definition types.hpp:121
Definition types.hpp:158
Definition types.hpp:148
Definition types_util.hpp:143
std::string function_args
Definition types.hpp:108
const char * function_name
Definition types.hpp:102
int line_number
Definition types.hpp:114
const void * instance
Definition types.hpp:99
const char * filepath
Definition types.hpp:111