COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
FixedLength.h
1//
2// Copyright 2015 - 2024 (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 <type_traits>
11#include <limits>
12
13#include "comms/Assert.h"
14#include "comms/util/SizeToType.h"
16#include "comms/ErrorStatus.h"
17#include "comms/details/tag.h"
18
19namespace comms
20{
21
22namespace field
23{
24
25namespace adapter
26{
27
28namespace details
29{
30
31template <std::size_t TLen>
32struct UnsignedValueMaskWrap
33{
34 static const std::uintmax_t Value =
35 static_cast<std::uintmax_t>(
36 (static_cast<std::uintmax_t>(1U) << (TLen * std::numeric_limits<std::uint8_t>::digits)) - 1U);
37};
38
39template <>
40struct UnsignedValueMaskWrap<sizeof(std::uintmax_t)>
41{
42 static const std::uintmax_t Value = std::numeric_limits<std::uintmax_t>::max();
43};
44
45
46} // namespace details
47
48
49template <std::size_t TLen, bool TSignExtend, typename TBase>
50class FixedLength : public TBase
51{
52 using BaseImpl = TBase;
53 using BaseSerialisedType = typename BaseImpl::SerialisedType;
54public:
55
56 using ValueType = typename BaseImpl::ValueType;
57
58 static_assert(TLen <= sizeof(BaseSerialisedType),
59 "The provided length limit is too big");
60
61 using SerialisedType =
63 (TLen < sizeof(BaseSerialisedType))
64 >::template Type<
65 typename comms::util::SizeToType<TLen, std::is_signed<BaseSerialisedType>::value>::Type,
66 BaseSerialisedType
67 >;
68
69 using Endian = typename BaseImpl::Endian;
70
71 FixedLength() = default;
72
73 explicit FixedLength(const ValueType& val)
74 : BaseImpl(val)
75 {
76 }
77
78 FixedLength(const FixedLength&) = default;
79 FixedLength(FixedLength&&) = default;
80 FixedLength& operator=(const FixedLength&) = default;
81 FixedLength& operator=(FixedLength&&) = default;
82
83 static constexpr std::size_t length()
84 {
85 return Length;
86 }
87
88 static constexpr std::size_t minLength()
89 {
90 return length();
91 }
92
93 static constexpr std::size_t maxLength()
94 {
95 return length();
96 }
97
98 static constexpr SerialisedType toSerialised(ValueType val)
99 {
100 return adjustToSerialised(BaseImpl::toSerialised(val), ConversionTag<>());
101 }
102
103 static constexpr ValueType fromSerialised(SerialisedType val)
104 {
105 return BaseImpl::fromSerialised(adjustFromSerialised(val, ConversionTag<>()));
106 }
107
108 template <typename TIter>
109 comms::ErrorStatus read(TIter& iter, std::size_t size)
110 {
111 if (size < length()) {
113 }
114
115 readNoStatus(iter);
117 }
118
119 template <typename TIter>
120 void readNoStatus(TIter& iter)
121 {
122 auto serialisedValue =
123 comms::util::readData<SerialisedType, Length>(iter, Endian());
124 BaseImpl::setValue(fromSerialised(serialisedValue));
125 }
126
127 template <typename TIter>
128 comms::ErrorStatus write(TIter& iter, std::size_t size) const
129 {
130 if (size < length()) {
132 }
133
134 writeNoStatus(iter);
136 }
137
138 template <typename TIter>
139 void writeNoStatus(TIter& iter) const
140 {
141 BaseImpl::template writeData<Length>(toSerialised(BaseImpl::getValue()), iter);
142 }
143
144private:
145
146 template <typename... TParams>
147 using JustCastTag = comms::details::tag::Tag1<>;
148
149 template <typename... TParams>
150 using SignExtendTag = comms::details::tag::Tag2<>;
151
152 template <typename... TParams>
153 using UnsignedTag = comms::details::tag::Tag3<>;
154
155 template <typename... TParams>
156 using SignedTag = comms::details::tag::Tag4<>;
157
158 template <typename...>
159 using ConversionTag =
160 typename comms::util::LazyShallowConditional<
161 (TLen < sizeof(SerialisedType))
162 >::template Type<
163 SignExtendTag,
164 JustCastTag
165 >;
166
167 template <typename...>
168 using HasSignTag =
169 typename comms::util::LazyShallowConditional<
170 std::is_signed<SerialisedType>::value && TSignExtend
171 >::template Type<
172 SignedTag,
173 UnsignedTag
174 >;
175
176 using UnsignedSerialisedType = typename std::make_unsigned<SerialisedType>::type;
177
178 template <typename... TParams>
179 static constexpr SerialisedType adjustToSerialised(BaseSerialisedType val, JustCastTag<TParams...>)
180 {
181 return static_cast<SerialisedType>(val);
182 }
183
184 template <typename... TParams>
185 static SerialisedType adjustToSerialised(BaseSerialisedType val, SignExtendTag<TParams...>)
186 {
187 auto valueTmp =
188 static_cast<UnsignedSerialisedType>(val) & UnsignedValueMask;
189
190 return signExtUnsignedSerialised(valueTmp, HasSignTag<>());
191 }
192
193 template <typename... TParams>
194 static constexpr BaseSerialisedType adjustFromSerialised(SerialisedType val, JustCastTag<TParams...>)
195 {
196 return castToBaseSerializedType(val, HasSignTag<>());
197 }
198
199 template <typename... TParams>
200 static BaseSerialisedType adjustFromSerialised(SerialisedType val, SignExtendTag<TParams...>)
201 {
202 auto valueTmp = static_cast<UnsignedSerialisedType>(val) & UnsignedValueMask;
203 return castToBaseSerializedType(signExtUnsignedSerialised(valueTmp, HasSignTag<>()), HasSignTag<>());
204 }
205
206 template <typename... TParams>
207 static constexpr SerialisedType signExtUnsignedSerialised(UnsignedSerialisedType val, UnsignedTag<TParams...>)
208 {
209 return static_cast<SerialisedType>(val);
210 }
211
212 template <typename... TParams>
213 static SerialisedType signExtUnsignedSerialised(UnsignedSerialisedType val, SignedTag<TParams...>)
214 {
215 static const UnsignedSerialisedType SignExtMask = ~(UnsignedValueMask);
216 static const UnsignedSerialisedType SignMask =
217 static_cast<UnsignedSerialisedType>(1U) << (BitLength - 1);
218
219 if ((val & SignMask) != 0) {
220 val |= SignExtMask;
221 }
222 return static_cast<SerialisedType>(val);
223 }
224
225 template <typename... TParams>
226 static constexpr BaseSerialisedType castToBaseSerializedType(SerialisedType val, UnsignedTag<TParams...>)
227 {
228 return static_cast<BaseSerialisedType>(static_cast<UnsignedSerialisedType>(val));
229 }
230
231 template <typename... TParams>
232 static constexpr BaseSerialisedType castToBaseSerializedType(SerialisedType val, SignedTag<TParams...>)
233 {
234 return static_cast<BaseSerialisedType>(val);
235 }
236
237 static const std::size_t Length = TLen;
238 static const std::size_t BitsInByte = std::numeric_limits<std::uint8_t>::digits;
239 static const std::size_t BitLength = Length * BitsInByte;
240
241 static const UnsignedSerialisedType UnsignedValueMask =
242 static_cast<UnsignedSerialisedType>(details::UnsignedValueMaskWrap<Length>::Value);
243
244 static_assert(0 < Length, "Length is expected to be greater than 0");
245};
246
247} // namespace adapter
248
249} // namespace field
250
251} // namespace comms
252
253
This file contains classes required for generic custom assertion functionality.
This file contain definition of error statuses used by comms module.
comms::option::def::FixedLength< TLen, TSignExtend > FixedLength
Same as comms::option::def::FixedLength.
Definition options.h:1488
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1438
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
@ Success
Used to indicate successful outcome of the operation.
STL namespace.
Replacement to std::conditional.
Definition type_traits.h:28
Replacement to some types from standard type_traits.