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