COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
AssignHelper.h
1//
2// Copyright 2020 - 2025 (C). Alex Robenko. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8#pragma once
9
10#include "comms/Assert.h"
11#include "comms/details/tag.h"
12#include "comms/util/detect.h"
14
15#include <iterator>
16#include <type_traits>
17
18namespace comms
19{
20
21namespace util
22{
23
24namespace details
25{
26
27template <typename...>
28class AssignHelper
29{
30public:
31 template <typename T, typename TIter>
32 static void assign(T& obj, TIter from, TIter to)
33 {
34 using ObjType = typename std::decay<decltype(obj)>::type;
35 static_assert(!std::is_same<Tag<ObjType>, UnknownTag<> >::value, "Assignment to provided type is not supported");
36 assignInternal(obj, from, to, Tag<ObjType>());
37 }
38
39private:
40 template <typename... TParams>
41 using UseAssignTag = comms::details::tag::Tag1<>;
42
43 template <typename... TParams>
44 using UsePtrSizeConstructorTag = comms::details::tag::Tag2<>;
45
46 template <typename... TParams>
47 using StdSpanTag = comms::details::tag::Tag3<>;
48
49 template <typename... TParams>
50 using UnknownTag = comms::details::tag::Tag4<>;
51
52 template <typename... TParams>
53 using HasReserveTag = comms::details::tag::Tag5<>;
54
55 template <typename... TParams>
56 using NoReserveTag = comms::details::tag::Tag6<>;
57
58
59 template <typename T>
60 using ConstructorTag =
61 typename comms::util::LazyShallowConditional<
62 comms::util::detect::hasPtrSizeConstructor<T>()
63 >::template Type<
64 UsePtrSizeConstructorTag,
65 UnknownTag
66 >;
67
68 template <typename T>
69 using SpanConstructorTag =
70 typename comms::util::LazyShallowConditional<
71 comms::util::detect::details::IsStdSpan<T>::Value
72 >::template Type<
73 StdSpanTag,
74 ConstructorTag,
75 T
76 >;
77
78 template <typename T>
79 using Tag =
80 typename comms::util::LazyShallowConditional<
81 comms::util::detect::hasAssignFunc<T>()
82 >::template Type<
83 UseAssignTag,
84 SpanConstructorTag,
85 T
86 >;
87
88 template <typename T>
89 using ReserveTag =
90 typename comms::util::LazyShallowConditional<
91 comms::util::detect::hasReserveFunc<T>()
92 >::template Type<
93 HasReserveTag,
94 NoReserveTag
95 >;
96
97 template <typename T, typename TIter, typename... TParams>
98 static void assignInternal(T& obj, TIter from, TIter to, UseAssignTag<TParams...>)
99 {
100 using ObjType = typename std::decay<decltype(obj)>::type;
101 auto len = static_cast<std::size_t>(std::distance(from, to));
102 reserveInternal(obj, len, ReserveTag<ObjType>());
103 obj.assign(from, to);
104 }
105
106 template <typename T, typename TIter, typename... TParams>
107 static void assignInternal(T& obj, TIter from, TIter to, UsePtrSizeConstructorTag<TParams...>)
108 {
109 using IterType = typename std::decay<TIter>::type;
110 using IterTag = typename std::iterator_traits<IterType>::iterator_category;
111 static_assert(std::is_base_of<std::random_access_iterator_tag, IterTag>::value,
112 "Only random access iterator is supported for provided type assignments");
113
114 auto diff = std::distance(from, to);
115 if (diff < 0) {
116 static constexpr bool Invalid_iterators_used_for_assignment = false;
117 static_cast<void>(Invalid_iterators_used_for_assignment);
118 COMMS_ASSERT(Invalid_iterators_used_for_assignment);
119 return;
120 }
121
122 using ObjType = typename std::decay<decltype(obj)>::type;
123
124 if (diff == 0) {
125 obj = ObjType();
126 return;
127 }
128
129 obj = ObjType(&(*from), static_cast<std::size_t>(diff));
130 }
131
132 template <typename T, typename TIter, typename... TParams>
133 static void assignInternal(T& obj, TIter from, TIter to, StdSpanTag<TParams...>)
134 {
135 using ObjType = typename std::decay<decltype(obj)>::type;
136 using ConstPointerType = typename ObjType::const_pointer;
137 using PointerType = typename ObjType::pointer;
138 auto fromPtr = const_cast<PointerType>(reinterpret_cast<ConstPointerType>(&(*from)));
139 auto toPtr = fromPtr + std::distance(from, to);
140 assignInternal(obj, fromPtr, toPtr, UsePtrSizeConstructorTag<TParams...>());
141 }
142
143 template <typename T, typename... TParams>
144 static void reserveInternal(T& obj, std::size_t len, HasReserveTag<TParams...>)
145 {
146 obj.reserve(len);
147 }
148
149 template <typename T, typename... TParams>
150 static void reserveInternal(T& obj, std::size_t len, NoReserveTag<TParams...>)
151 {
152 static_cast<void>(obj);
153 static_cast<void>(len);
154 }
155};
156
157} // namespace details
158
159} // namespace util
160
161} // namespace comms
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
void assign(T &obj, TIter from, TIter to)
Assigns a new value to provided object.
Definition assign.h:39
Main namespace for all classes / functions of COMMS library.
Replacement to some types from standard type_traits.
Various compile-time detection functions of whether specific member functions and/or types exist.