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