LCOV - code coverage report
Current view: top level - src/extension - someip_serializer.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 466 518 90.0 %
Date: 2026-09-30 18:30:16 Functions: 72 72 100.0 %
Branches: 463 623 74.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2026 by Thun Lu. All rights reserved.
       3                 :            :  * Author: Thun Lu <thun.lu@zohomail.cn>
       4                 :            :  * Repo:   https://github.com/thun-res/vlink
       5                 :            :  *  _    __   __      _           __
       6                 :            :  * | |  / /  / /     (_) ____    / /__
       7                 :            :  * | | / /  / /     / / / __ \  / //_/
       8                 :            :  * | |/ /  / /___  / / / / / / / ,<
       9                 :            :  * |___/  /_____/ /_/ /_/ /_/ /_/|_|
      10                 :            :  *
      11                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
      12                 :            :  * you may not use this file except in compliance with the License.
      13                 :            :  * You may obtain a copy of the License at
      14                 :            :  *
      15                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      16                 :            :  *
      17                 :            :  * Unless required by applicable law or agreed to in writing, software
      18                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      19                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      20                 :            :  * See the License for the specific language governing permissions and
      21                 :            :  * limitations under the License.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "./extension/someip_serializer.h"
      25                 :            : 
      26                 :            : #include <algorithm>
      27                 :            : #include <cstring>
      28                 :            : #include <iostream>
      29                 :            : #include <limits>
      30                 :            : #include <utility>
      31                 :            : 
      32                 :            : namespace vlink {
      33                 :            : 
      34                 :            : namespace SomeipSerializer {  // NOLINT(readability-identifier-naming)
      35                 :            : 
      36                 :            : static constexpr uint8_t kUtf8Bom[] = {0xEF, 0xBB, 0xBF};
      37                 :            : static constexpr uint8_t kUtf16BomBig[] = {0xFE, 0xFF};
      38                 :            : static constexpr uint8_t kUtf16BomLittle[] = {0xFF, 0xFE};
      39                 :            : static constexpr size_t kUtf16UnitSize = 2U;
      40                 :            : static constexpr size_t kHeaderSize = 16U;
      41                 :            : 
      42                 :            : // Writer
      43                 :        173 : Writer::Writer(uint8_t* data, size_t capacity, size_t alignment, Endian endian) noexcept
      44                 :        173 :     : data_(data), capacity_(std::min(capacity, kMaxPayloadSize)), alignment_(alignment), endian_(endian) {}
      45                 :            : 
      46                 :     790023 : size_t Writer::position() const noexcept { return position_; }
      47                 :            : 
      48                 :         79 : bool Writer::is_size_only() const noexcept { return data_ == nullptr; }
      49                 :            : 
      50                 :         30 : Writer Writer::size_only() const noexcept {
      51                 :         30 :   Writer result = *this;
      52                 :         30 :   result.data_ = nullptr;
      53                 :            : 
      54                 :         30 :   return result;
      55                 :            : }
      56                 :            : 
      57                 :        402 : bool Writer::append(const uint8_t* data, size_t size) noexcept {
      58         [ +  + ]:        402 :   if VUNLIKELY (size > capacity_ - position_) {
      59                 :          2 :     return false;
      60                 :            :   }
      61                 :            : 
      62   [ +  +  +  + ]:        400 :   if (data_ && size > 0U) {
      63                 :        157 :     std::memcpy(data_ + position_, data, size);
      64                 :            :   }
      65                 :            : 
      66                 :        400 :   position_ += size;
      67                 :            : 
      68                 :        400 :   return true;
      69                 :            : }
      70                 :            : 
      71                 :     395184 : bool Writer::append_unsigned(uint64_t value, size_t width) noexcept { return append_unsigned(value, width, endian_); }
      72                 :            : 
      73                 :     395265 : bool Writer::append_unsigned(uint64_t value, size_t width, Endian endian) noexcept {
      74   [ +  +  +  +  :     395265 :   if VUNLIKELY (width == 0U || width > sizeof(value) || width > capacity_ - position_) {
          +  +  -  +  +  
                      + ]
      75                 :          2 :     return false;
      76                 :            :   }
      77                 :            : 
      78         [ +  + ]:     791101 :   for (size_t index = 0; index < width; ++index) {
      79         [ +  + ]:     395838 :     const size_t shift = (endian == Endian::kBig ? width - index - 1U : index) * 8U;
      80                 :            : 
      81         [ +  + ]:     395838 :     if (data_) {
      82                 :     132072 :       data_[position_ + index] = static_cast<uint8_t>((value >> shift) & 0xFFU);
      83                 :            :     }
      84                 :            :   }
      85                 :            : 
      86                 :     395263 :   position_ += width;
      87                 :            : 
      88                 :     395263 :   return true;
      89                 :            : }
      90                 :            : 
      91                 :        364 : bool Writer::begin_length_delimited(size_t& length_position, size_t& data_position, size_t width) noexcept {
      92   [ +  +  +  +  :        364 :   if VUNLIKELY (width != 1U && width != 2U && width != 4U) {
          +  +  -  +  -  
                      + ]
      93                 :          0 :     return false;
      94                 :            :   }
      95                 :            : 
      96                 :        364 :   length_position = position_;
      97                 :            : 
      98         [ +  + ]:        364 :   if VUNLIKELY (width > capacity_ - position_) {
      99                 :          1 :     return false;
     100                 :            :   }
     101                 :            : 
     102                 :        363 :   position_ += width;
     103                 :        363 :   data_position = position_;
     104                 :            : 
     105                 :        363 :   return true;
     106                 :            : }
     107                 :            : 
     108                 :        340 : bool Writer::end_length_delimited(size_t length_position, size_t data_position, size_t width) noexcept {
     109   [ +  +  +  +  :        340 :   if VUNLIKELY ((width != 1U && width != 2U && width != 4U) || position_ < data_position) {
          +  +  -  +  +  
             -  -  +  -  
                      + ]
     110                 :          0 :     return false;
     111                 :            :   }
     112                 :            : 
     113                 :        340 :   const size_t byte_length = position_ - data_position;
     114                 :        340 :   const uint64_t max_length = (uint64_t{1U} << (width * 8U)) - 1U;
     115                 :            : 
     116   [ +  +  -  +  :        340 :   if VUNLIKELY (byte_length > max_length || length_position > capacity_ || width > capacity_ - length_position) {
          +  +  -  +  +  
                      + ]
     117                 :          1 :     return false;
     118                 :            :   }
     119                 :            : 
     120         [ +  + ]:        339 :   if (data_) {
     121         [ +  + ]:        576 :     for (size_t index = 0U; index < width; ++index) {
     122                 :        421 :       const size_t shift = (width - index - 1U) * 8U;
     123                 :        421 :       data_[length_position + index] = static_cast<uint8_t>((byte_length >> shift) & 0xFFU);
     124                 :            :     }
     125                 :            :   }
     126                 :            : 
     127                 :        339 :   return true;
     128                 :            : }
     129                 :            : 
     130                 :        116 : bool Writer::align() noexcept {
     131         [ +  + ]:        116 :   if VLIKELY (alignment_ == 1U) {
     132                 :         95 :     return true;
     133                 :            :   }
     134                 :            : 
     135                 :         21 :   const size_t mask = alignment_ - 1U;
     136                 :         21 :   const size_t remainder = ((position_ & mask) + (kHeaderSize & mask)) & mask;
     137                 :         21 :   const size_t padding = (alignment_ - remainder) & mask;
     138                 :            : 
     139         [ -  + ]:         21 :   if VUNLIKELY (padding > capacity_ - position_) {
     140                 :          0 :     return false;
     141                 :            :   }
     142                 :            : 
     143   [ +  +  +  + ]:         21 :   if (data_ && padding > 0U) {
     144                 :          8 :     std::memset(data_ + position_, 0, padding);
     145                 :            :   }
     146                 :            : 
     147                 :         21 :   position_ += padding;
     148                 :            : 
     149                 :         21 :   return true;
     150                 :            : }
     151                 :            : 
     152                 :            : // Reader
     153                 :        108 : Reader::Reader(const uint8_t* data, size_t size, size_t alignment, Endian endian) noexcept
     154                 :        108 :     : data_(data), size_(size), alignment_(alignment), endian_(endian) {}
     155                 :            : 
     156                 :     197332 : size_t Reader::position() const noexcept { return position_; }
     157                 :            : 
     158                 :        113 : size_t Reader::size() const noexcept { return size_; }
     159                 :            : 
     160         [ +  + ]:         71 : const uint8_t* Reader::current_data() const noexcept { return position_ < size_ ? data_ + position_ : nullptr; }
     161                 :            : 
     162                 :          9 : bool Reader::read(uint8_t* data, size_t size, size_t end) noexcept {
     163   [ +  -  -  +  :          9 :   if VUNLIKELY (end > size_ || position_ > end || size > end - position_) {
          +  -  +  +  +  
                      + ]
     164                 :          1 :     return false;
     165                 :            :   }
     166                 :            : 
     167         [ +  - ]:          8 :   if (size > 0U) {
     168                 :          8 :     std::memcpy(data, data_ + position_, size);
     169                 :            :   }
     170                 :            : 
     171                 :          8 :   position_ += size;
     172                 :            : 
     173                 :          8 :   return true;
     174                 :            : }
     175                 :            : 
     176                 :        204 : bool Reader::skip(size_t size, size_t end) noexcept {
     177   [ +  -  -  +  :        204 :   if VUNLIKELY (end > size_ || position_ > end || size > end - position_) {
          +  -  +  +  +  
                      + ]
     178                 :          1 :     return false;
     179                 :            :   }
     180                 :            : 
     181                 :        203 :   position_ += size;
     182                 :            : 
     183                 :        203 :   return true;
     184                 :            : }
     185                 :            : 
     186                 :      65783 : bool Reader::read_unsigned(uint64_t& value, size_t width, size_t end) noexcept {
     187                 :      65783 :   return read_unsigned(value, width, endian_, end);
     188                 :            : }
     189                 :            : 
     190                 :      65850 : bool Reader::read_unsigned(uint64_t& value, size_t width, Endian endian, size_t end) noexcept {
     191   [ +  -  -  +  :      65850 :   if VUNLIKELY (width == 0U || width > sizeof(value) || end > size_ || position_ > end || width > end - position_) {
          +  -  -  +  +  
          -  -  +  +  -  
             +  +  +  + ]
     192                 :          5 :     return false;
     193                 :            :   }
     194                 :            : 
     195                 :      65845 :   value = 0;
     196                 :            : 
     197         [ +  + ]:     132044 :   for (size_t index = 0; index < width; ++index) {
     198         [ +  + ]:      66199 :     const size_t shift = (endian == Endian::kBig ? width - index - 1U : index) * 8U;
     199                 :      66199 :     value |= static_cast<uint64_t>(data_[position_ + index]) << shift;
     200                 :            :   }
     201                 :            : 
     202                 :      65845 :   position_ += width;
     203                 :            : 
     204                 :      65845 :   return true;
     205                 :            : }
     206                 :            : 
     207                 :        204 : bool Reader::begin_length_delimited(size_t end, size_t& value_end, size_t width) noexcept {
     208   [ +  +  +  +  :        204 :   if VUNLIKELY ((width != 1U && width != 2U && width != 4U) || end > size_ || position_ > end ||
          +  +  -  +  +  
          -  -  +  +  -  
          -  +  +  -  -  
                +  -  + ]
     209                 :            :                 width > end - position_) {
     210                 :          0 :     return false;
     211                 :            :   }
     212                 :            : 
     213                 :        204 :   uint32_t byte_length = 0U;
     214                 :            : 
     215         [ +  + ]:        748 :   for (size_t index = 0U; index < width; ++index) {
     216                 :        544 :     byte_length = (byte_length << 8U) | data_[position_ + index];
     217                 :            :   }
     218                 :            : 
     219                 :        204 :   position_ += width;
     220                 :            : 
     221         [ +  + ]:        204 :   if VUNLIKELY (byte_length > end - position_) {
     222                 :          3 :     return false;
     223                 :            :   }
     224                 :            : 
     225                 :        201 :   value_end = position_ + static_cast<size_t>(byte_length);
     226                 :            : 
     227                 :        201 :   return true;
     228                 :            : }
     229                 :            : 
     230                 :         53 : bool Reader::align(size_t end) noexcept {
     231         [ +  + ]:         53 :   if VLIKELY (alignment_ == 1U) {
     232                 :         45 :     return true;
     233                 :            :   }
     234                 :            : 
     235                 :          8 :   const size_t mask = alignment_ - 1U;
     236                 :          8 :   const size_t remainder = ((position_ & mask) + (kHeaderSize & mask)) & mask;
     237                 :          8 :   const size_t padding = (alignment_ - remainder) & mask;
     238                 :            : 
     239                 :          8 :   return skip(padding, end);
     240                 :            : }
     241                 :            : 
     242                 :            : // detail
     243                 :            : namespace detail {
     244                 :            : 
     245                 :        162 : static bool is_valid_utf8(const uint8_t* data, size_t size, size_t maximum) noexcept {
     246                 :        162 :   size_t position = 0;
     247                 :        162 :   size_t count = 0;
     248                 :            : 
     249         [ +  + ]:        474 :   while (position < size) {
     250                 :        335 :     const uint8_t first = data[position];
     251                 :            : 
     252         [ +  + ]:        335 :     if VLIKELY (first <= 0x7FU) {
     253                 :        298 :       ++position;
     254                 :            : 
     255         [ +  + ]:        298 :       if (maximum != std::numeric_limits<size_t>::max()) {
     256                 :        116 :         ++count;
     257         [ +  + ]:        116 :         if VUNLIKELY (count > maximum) {
     258                 :         10 :           return false;
     259                 :            :         }
     260                 :            :       }
     261                 :            : 
     262                 :        288 :       continue;
     263                 :            :     }
     264                 :            : 
     265                 :         37 :     size_t continuation_count = 0;
     266                 :         37 :     uint8_t second_min = 0x80U;
     267                 :         37 :     uint8_t second_max = 0xBFU;
     268                 :            : 
     269   [ +  +  +  + ]:         37 :     if (first >= 0xC2U && first <= 0xDFU) {
     270                 :          6 :       continuation_count = 1U;
     271   [ +  +  +  + ]:         31 :     } else if (first >= 0xE0U && first <= 0xEFU) {
     272                 :         16 :       continuation_count = 2U;
     273         [ +  + ]:         16 :       second_min = first == 0xE0U ? 0xA0U : 0x80U;
     274         [ +  + ]:         16 :       second_max = first == 0xEDU ? 0x9FU : 0xBFU;
     275   [ +  +  +  - ]:         15 :     } else if (first >= 0xF0U && first <= 0xF4U) {
     276                 :         13 :       continuation_count = 3U;
     277         [ +  + ]:         13 :       second_min = first == 0xF0U ? 0x90U : 0x80U;
     278         [ +  + ]:         13 :       second_max = first == 0xF4U ? 0x8FU : 0xBFU;
     279                 :            :     } else {
     280                 :          2 :       return false;
     281                 :            :     }
     282                 :            : 
     283         [ +  + ]:         35 :     if VUNLIKELY (continuation_count > size - position - 1U) {
     284                 :          1 :       return false;
     285                 :            :     }
     286                 :            : 
     287                 :         34 :     const uint8_t second = data[position + 1U];
     288                 :            : 
     289   [ +  +  +  +  :         34 :     if VUNLIKELY (second < second_min || second > second_max) {
                   +  + ]
     290                 :          8 :       return false;
     291                 :            :     }
     292                 :            : 
     293         [ +  + ]:         53 :     for (size_t index = 2U; index <= continuation_count; ++index) {
     294                 :         29 :       const uint8_t continuation = data[position + index];
     295                 :            : 
     296   [ +  +  -  +  :         29 :       if VUNLIKELY (continuation < 0x80U || continuation > 0xBFU) {
                   +  + ]
     297                 :          2 :         return false;
     298                 :            :       }
     299                 :            :     }
     300                 :            : 
     301                 :         24 :     position += continuation_count + 1U;
     302                 :            : 
     303         [ +  + ]:         24 :     if (maximum != std::numeric_limits<size_t>::max()) {
     304                 :          3 :       ++count;
     305         [ -  + ]:          3 :       if VUNLIKELY (count > maximum) {
     306                 :          0 :         return false;
     307                 :            :       }
     308                 :            :     }
     309                 :            :   }
     310                 :            : 
     311                 :        139 :   return true;
     312                 :            : }
     313                 :            : 
     314                 :         30 : static bool is_valid_utf16(const char16_t* data, size_t size, size_t maximum) noexcept {
     315                 :         30 :   size_t position = 0;
     316                 :         30 :   size_t count = 0;
     317                 :            : 
     318         [ +  + ]:         69 :   while (position < size) {
     319                 :         41 :     const auto unit = static_cast<uint16_t>(data[position]);
     320                 :            : 
     321   [ +  +  -  +  :         41 :     if VLIKELY (unit < 0xD800U || unit > 0xDFFFU) {
                   +  + ]
     322                 :         35 :       ++position;
     323                 :            : 
     324         [ +  + ]:         35 :       if (maximum != std::numeric_limits<size_t>::max()) {
     325                 :         27 :         ++count;
     326         [ +  + ]:         27 :         if VUNLIKELY (count > maximum) {
     327                 :          1 :           return false;
     328                 :            :         }
     329                 :            :       }
     330                 :            : 
     331                 :         34 :       continue;
     332                 :            :     }
     333                 :            : 
     334   [ +  -  +  +  :          6 :     if VUNLIKELY (unit > 0xDBFFU || position + 1U == size) {
                   +  + ]
     335                 :          1 :       return false;
     336                 :            :     }
     337                 :            : 
     338                 :          5 :     const auto low = static_cast<uint16_t>(data[position + 1U]);
     339                 :            : 
     340   [ +  -  -  +  :          5 :     if VUNLIKELY (low < 0xDC00U || low > 0xDFFFU) {
                   -  + ]
     341                 :          0 :       return false;
     342                 :            :     }
     343                 :            : 
     344                 :          5 :     position += 2U;
     345                 :            : 
     346         [ +  + ]:          5 :     if (maximum != std::numeric_limits<size_t>::max()) {
     347                 :          3 :       ++count;
     348         [ -  + ]:          3 :       if VUNLIKELY (count > maximum) {
     349                 :          0 :         return false;
     350                 :            :       }
     351                 :            :     }
     352                 :            :   }
     353                 :            : 
     354                 :         28 :   return true;
     355                 :            : }
     356                 :            : 
     357                 :         25 : static bool write_zeroes(Writer& writer, size_t size) noexcept {
     358         [ +  + ]:         25 :   if (writer.is_size_only()) {
     359                 :         13 :     return writer.append(nullptr, size);
     360                 :            :   }
     361                 :            : 
     362                 :            :   static constexpr uint8_t kZeroes[256] = {};
     363                 :            : 
     364         [ -  + ]:         12 :   while (size > sizeof(kZeroes)) {
     365         [ #  # ]:          0 :     if VUNLIKELY (!writer.append(kZeroes, sizeof(kZeroes))) {
     366                 :          0 :       return false;
     367                 :            :     }
     368                 :            : 
     369                 :          0 :     size -= sizeof(kZeroes);
     370                 :            :   }
     371                 :            : 
     372                 :         12 :   return writer.append(kZeroes, size);
     373                 :            : }
     374                 :            : 
     375                 :        104 : static bool write_utf8_body(Writer& writer, const std::string& value, size_t maximum, bool strip_leading_bom) noexcept {
     376                 :        104 :   const auto* data = reinterpret_cast<const uint8_t*>(value.data());
     377                 :            :   const size_t offset =
     378   [ +  +  +  + ]:         88 :       strip_leading_bom && value.size() >= sizeof(kUtf8Bom) && std::memcmp(data, kUtf8Bom, sizeof(kUtf8Bom)) == 0
     379         [ +  + ]:        192 :           ? sizeof(kUtf8Bom)
     380                 :        104 :           : 0U;
     381                 :            : 
     382         [ +  + ]:        104 :   if VUNLIKELY (!is_valid_utf8(data + offset, value.size() - offset, maximum)) {
     383                 :         13 :     return false;
     384                 :            :   }
     385                 :            : 
     386                 :         91 :   const uint8_t terminator = 0U;
     387                 :            : 
     388   [ +  -  +  -  :        182 :   return writer.append(kUtf8Bom, sizeof(kUtf8Bom)) && writer.append(data + offset, value.size() - offset) &&
                   +  - ]
     389                 :        182 :          writer.append(&terminator, sizeof(terminator));
     390                 :            : }
     391                 :            : 
     392                 :         28 : static bool write_utf16_body(Writer& writer, const std::u16string& value, Endian encoding, size_t maximum,
     393                 :            :                              bool strip_leading_bom) noexcept {
     394   [ +  +  +  -  :         28 :   const size_t offset = strip_leading_bom && !value.empty() && value.front() == u'\uFEFF' ? 1U : 0U;
                   +  + ]
     395                 :            : 
     396         [ +  + ]:         28 :   if VUNLIKELY (!is_valid_utf16(value.data() + offset, value.size() - offset, maximum)) {
     397                 :          2 :     return false;
     398                 :            :   }
     399                 :            : 
     400         [ +  + ]:         26 :   if (writer.is_size_only()) {
     401   [ +  -  +  -  :         28 :     return writer.append(nullptr, kUtf16UnitSize) && writer.append(nullptr, (value.size() - offset) * kUtf16UnitSize) &&
                   +  - ]
     402                 :         28 :            writer.append(nullptr, kUtf16UnitSize);
     403                 :            :   }
     404                 :            : 
     405         [ +  + ]:         12 :   const uint8_t* bom = encoding == Endian::kBig ? kUtf16BomBig : kUtf16BomLittle;
     406                 :            : 
     407         [ -  + ]:         12 :   if VUNLIKELY (!writer.append(bom, kUtf16UnitSize)) {
     408                 :          0 :     return false;
     409                 :            :   }
     410                 :            : 
     411                 :            :   uint8_t chunk[256];
     412                 :         12 :   size_t filled = 0U;
     413                 :            : 
     414         [ +  + ]:         30 :   for (size_t index = offset; index < value.size(); ++index) {
     415                 :         18 :     const auto bits = static_cast<uint16_t>(value[index]);
     416                 :            : 
     417         [ +  + ]:         18 :     chunk[filled] = static_cast<uint8_t>(encoding == Endian::kBig ? bits >> 8U : bits & 0xFFU);
     418         [ +  + ]:         18 :     chunk[filled + 1U] = static_cast<uint8_t>(encoding == Endian::kBig ? bits & 0xFFU : bits >> 8U);
     419                 :         18 :     filled += kUtf16UnitSize;
     420                 :            : 
     421         [ -  + ]:         18 :     if (filled == sizeof(chunk)) {
     422         [ #  # ]:          0 :       if VUNLIKELY (!writer.append(chunk, filled)) {
     423                 :          0 :         return false;
     424                 :            :       }
     425                 :            : 
     426                 :          0 :       filled = 0U;
     427                 :            :     }
     428                 :            :   }
     429                 :            : 
     430                 :         12 :   chunk[filled] = 0U;
     431                 :         12 :   chunk[filled + 1U] = 0U;
     432                 :            : 
     433                 :         12 :   return writer.append(chunk, filled + kUtf16UnitSize);
     434                 :            : }
     435                 :            : 
     436                 :         25 : bool write_value(Writer& writer, bool value) noexcept {
     437         [ +  + ]:         25 :   return writer.append_unsigned(value ? 1U : 0U, sizeof(uint8_t));
     438                 :            : }
     439                 :            : 
     440                 :     394887 : bool write_value(Writer& writer, uint8_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
     441                 :            : 
     442                 :        136 : bool write_value(Writer& writer, uint16_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
     443                 :            : 
     444                 :         38 : bool write_value(Writer& writer, uint32_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
     445                 :            : 
     446                 :          2 : bool write_value(Writer& writer, uint64_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
     447                 :            : 
     448                 :          2 : bool write_value(Writer& writer, int8_t value) noexcept {
     449                 :          2 :   return writer.append_unsigned(static_cast<uint8_t>(value), sizeof(value));
     450                 :            : }
     451                 :            : 
     452                 :         33 : bool write_value(Writer& writer, int16_t value) noexcept {
     453                 :         33 :   return writer.append_unsigned(static_cast<uint16_t>(value), sizeof(value));
     454                 :            : }
     455                 :            : 
     456                 :         36 : bool write_value(Writer& writer, int32_t value) noexcept {
     457                 :         36 :   return writer.append_unsigned(static_cast<uint32_t>(value), sizeof(value));
     458                 :            : }
     459                 :            : 
     460                 :          2 : bool write_value(Writer& writer, int64_t value) noexcept {
     461                 :          2 :   return writer.append_unsigned(static_cast<uint64_t>(value), sizeof(value));
     462                 :            : }
     463                 :            : 
     464                 :         18 : bool write_value(Writer& writer, float value) noexcept {
     465                 :            :   static_assert(sizeof(float) == sizeof(uint32_t), "SOME/IP float must use IEEE 754 binary32 storage.");
     466                 :            :   static_assert(std::numeric_limits<float>::is_iec559, "SOME/IP float requires IEEE 754 semantics.");
     467                 :            : 
     468                 :         18 :   uint32_t bits = 0;
     469                 :         18 :   std::memcpy(&bits, &value, sizeof(bits));
     470                 :            : 
     471                 :         18 :   return writer.append_unsigned(bits, sizeof(bits));
     472                 :            : }
     473                 :            : 
     474                 :          2 : bool write_value(Writer& writer, double value) noexcept {
     475                 :            :   static_assert(sizeof(double) == sizeof(uint64_t), "SOME/IP double must use IEEE 754 binary64 storage.");
     476                 :            :   static_assert(std::numeric_limits<double>::is_iec559, "SOME/IP double requires IEEE 754 semantics.");
     477                 :            : 
     478                 :          2 :   uint64_t bits = 0;
     479                 :          2 :   std::memcpy(&bits, &value, sizeof(bits));
     480                 :            : 
     481                 :          2 :   return writer.append_unsigned(bits, sizeof(bits));
     482                 :            : }
     483                 :            : 
     484                 :         83 : bool write_value(Writer& writer, const std::string& value, size_t len, size_t maximum) noexcept {
     485                 :         83 :   size_t length_position = 0;
     486                 :         83 :   size_t data_position = 0;
     487                 :            : 
     488         [ +  + ]:        166 :   return writer.begin_length_delimited(length_position, data_position, len) &&
     489   [ +  -  +  - ]:        166 :          write_value_body(writer, value, maximum) && writer.end_length_delimited(length_position, data_position, len);
     490                 :            : }
     491                 :            : 
     492                 :         16 : bool write_value(Writer& writer, const Bytes& value, size_t len, size_t maximum) noexcept {
     493                 :         16 :   size_t length_position = 0;
     494                 :         16 :   size_t data_position = 0;
     495                 :            : 
     496         [ +  - ]:         32 :   return writer.begin_length_delimited(length_position, data_position, len) &&
     497   [ +  -  +  - ]:         32 :          write_value_body(writer, value, maximum) && writer.end_length_delimited(length_position, data_position, len);
     498                 :            : }
     499                 :            : 
     500                 :         16 : bool write_value(Writer& writer, const std::u16string& value, size_t len, Endian encoding, size_t maximum) noexcept {
     501                 :         16 :   size_t length_position = 0;
     502                 :         16 :   size_t data_position = 0;
     503                 :            : 
     504         [ +  + ]:         32 :   return writer.begin_length_delimited(length_position, data_position, len) &&
     505   [ +  -  +  - ]:         32 :          write_value_body(writer, value, encoding, maximum) &&
     506                 :         30 :          writer.end_length_delimited(length_position, data_position, len);
     507                 :            : }
     508                 :            : 
     509                 :         17 : bool write_fixed_value(Writer& writer, const std::string& value, size_t size, size_t len, size_t maximum) noexcept {
     510   [ +  -  +  +  :         17 :   if VUNLIKELY (size < sizeof(kUtf8Bom) + 1U || value.size() > size - sizeof(kUtf8Bom) - 1U) {
                   +  + ]
     511                 :          1 :     return false;
     512                 :            :   }
     513                 :            : 
     514                 :         16 :   size_t length_position = 0U;
     515                 :         16 :   size_t data_position = 0U;
     516                 :            : 
     517   [ +  +  -  +  :         16 :   if VUNLIKELY (len > 0U && !writer.begin_length_delimited(length_position, data_position, len)) {
                   -  + ]
     518                 :          0 :     return false;
     519                 :            :   }
     520                 :            : 
     521   [ +  +  -  +  :         16 :   if VUNLIKELY (!write_utf8_body(writer, value, maximum, false) ||
                   +  + ]
     522                 :            :                 !write_zeroes(writer, size - sizeof(kUtf8Bom) - value.size() - 1U)) {
     523                 :          3 :     return false;
     524                 :            :   }
     525                 :            : 
     526   [ +  +  +  - ]:         13 :   return len == 0U || writer.end_length_delimited(length_position, data_position, len);
     527                 :            : }
     528                 :            : 
     529                 :         14 : bool write_fixed_value(Writer& writer, const std::u16string& value, size_t size, size_t len, Endian encoding,
     530                 :            :                        size_t maximum) noexcept {
     531   [ +  -  -  +  :         14 :   if VUNLIKELY (size < kUtf16UnitSize * 2U || size % kUtf16UnitSize != 0U ||
          +  -  +  +  +  
                      + ]
     532                 :            :                 value.size() > size / kUtf16UnitSize - 2U) {
     533                 :          2 :     return false;
     534                 :            :   }
     535                 :            : 
     536                 :         12 :   size_t length_position = 0U;
     537                 :         12 :   size_t data_position = 0U;
     538                 :            : 
     539   [ +  +  -  +  :         12 :   if VUNLIKELY (len > 0U && !writer.begin_length_delimited(length_position, data_position, len)) {
                   -  + ]
     540                 :          0 :     return false;
     541                 :            :   }
     542                 :            : 
     543                 :         12 :   const size_t encoded_size = (value.size() + 2U) * kUtf16UnitSize;
     544                 :            : 
     545   [ +  -  -  +  :         12 :   if VUNLIKELY (!write_utf16_body(writer, value, encoding, maximum, false) ||
                   -  + ]
     546                 :            :                 !write_zeroes(writer, size - encoded_size)) {
     547                 :          0 :     return false;
     548                 :            :   }
     549                 :            : 
     550   [ +  +  +  - ]:         12 :   return len == 0U || writer.end_length_delimited(length_position, data_position, len);
     551                 :            : }
     552                 :            : 
     553                 :         15 : bool read_value(Reader& reader, bool& value, size_t end) noexcept {
     554                 :         15 :   uint64_t raw = 0;
     555                 :            : 
     556         [ -  + ]:         15 :   if VUNLIKELY (!reader.read_unsigned(raw, sizeof(uint8_t), end)) {
     557                 :          0 :     return false;
     558                 :            :   }
     559                 :            : 
     560                 :         15 :   value = (raw & 0x01U) != 0U;
     561                 :            : 
     562                 :         15 :   return true;
     563                 :            : }
     564                 :            : 
     565                 :      65608 : bool read_value(Reader& reader, uint8_t& value, size_t end) noexcept {
     566                 :      65608 :   uint64_t raw = 0;
     567                 :            : 
     568         [ +  + ]:      65608 :   if VUNLIKELY (!reader.read_unsigned(raw, sizeof(value), end)) {
     569                 :          1 :     return false;
     570                 :            :   }
     571                 :            : 
     572                 :      65607 :   value = static_cast<uint8_t>(raw);
     573                 :            : 
     574                 :      65607 :   return true;
     575                 :            : }
     576                 :            : 
     577                 :        104 : bool read_value(Reader& reader, uint16_t& value, size_t end) noexcept {
     578                 :        104 :   uint64_t raw = 0;
     579                 :            : 
     580         [ +  + ]:        104 :   if VUNLIKELY (!reader.read_unsigned(raw, sizeof(value), end)) {
     581                 :          1 :     return false;
     582                 :            :   }
     583                 :            : 
     584                 :        103 :   value = static_cast<uint16_t>(raw);
     585                 :            : 
     586                 :        103 :   return true;
     587                 :            : }
     588                 :            : 
     589                 :         50 : bool read_value(Reader& reader, uint32_t& value, size_t end) noexcept {
     590                 :         50 :   uint64_t raw = 0;
     591                 :            : 
     592         [ +  + ]:         50 :   if VUNLIKELY (!reader.read_unsigned(raw, sizeof(value), end)) {
     593                 :          1 :     return false;
     594                 :            :   }
     595                 :            : 
     596                 :         49 :   value = static_cast<uint32_t>(raw);
     597                 :            : 
     598                 :         49 :   return true;
     599                 :            : }
     600                 :            : 
     601                 :          3 : bool read_value(Reader& reader, uint64_t& value, size_t end) noexcept {
     602                 :          3 :   return reader.read_unsigned(value, sizeof(value), end);
     603                 :            : }
     604                 :            : 
     605                 :          1 : bool read_value(Reader& reader, int8_t& value, size_t end) noexcept {
     606                 :          1 :   uint8_t raw = 0;
     607                 :            : 
     608         [ -  + ]:          1 :   if VUNLIKELY (!read_value(reader, raw, end)) {
     609                 :          0 :     return false;
     610                 :            :   }
     611                 :            : 
     612                 :          1 :   std::memcpy(&value, &raw, sizeof(value));
     613                 :            : 
     614                 :          1 :   return true;
     615                 :            : }
     616                 :            : 
     617                 :         17 : bool read_value(Reader& reader, int16_t& value, size_t end) noexcept {
     618                 :         17 :   uint16_t raw = 0;
     619                 :            : 
     620         [ -  + ]:         17 :   if VUNLIKELY (!read_value(reader, raw, end)) {
     621                 :          0 :     return false;
     622                 :            :   }
     623                 :            : 
     624                 :         17 :   std::memcpy(&value, &raw, sizeof(value));
     625                 :            : 
     626                 :         17 :   return true;
     627                 :            : }
     628                 :            : 
     629                 :         22 : bool read_value(Reader& reader, int32_t& value, size_t end) noexcept {
     630                 :         22 :   uint32_t raw = 0;
     631                 :            : 
     632         [ -  + ]:         22 :   if VUNLIKELY (!read_value(reader, raw, end)) {
     633                 :          0 :     return false;
     634                 :            :   }
     635                 :            : 
     636                 :         22 :   std::memcpy(&value, &raw, sizeof(value));
     637                 :            : 
     638                 :         22 :   return true;
     639                 :            : }
     640                 :            : 
     641                 :          1 : bool read_value(Reader& reader, int64_t& value, size_t end) noexcept {
     642                 :          1 :   uint64_t raw = 0;
     643                 :            : 
     644         [ -  + ]:          1 :   if VUNLIKELY (!read_value(reader, raw, end)) {
     645                 :          0 :     return false;
     646                 :            :   }
     647                 :            : 
     648                 :          1 :   std::memcpy(&value, &raw, sizeof(value));
     649                 :            : 
     650                 :          1 :   return true;
     651                 :            : }
     652                 :            : 
     653                 :          8 : bool read_value(Reader& reader, float& value, size_t end) noexcept {
     654                 :          8 :   uint32_t bits = 0;
     655                 :            : 
     656         [ -  + ]:          8 :   if VUNLIKELY (!read_value(reader, bits, end)) {
     657                 :          0 :     return false;
     658                 :            :   }
     659                 :            : 
     660                 :          8 :   std::memcpy(&value, &bits, sizeof(value));
     661                 :            : 
     662                 :          8 :   return true;
     663                 :            : }
     664                 :            : 
     665                 :          1 : bool read_value(Reader& reader, double& value, size_t end) noexcept {
     666                 :          1 :   uint64_t bits = 0;
     667                 :            : 
     668         [ -  + ]:          1 :   if VUNLIKELY (!read_value(reader, bits, end)) {
     669                 :          0 :     return false;
     670                 :            :   }
     671                 :            : 
     672                 :          1 :   std::memcpy(&value, &bits, sizeof(value));
     673                 :            : 
     674                 :          1 :   return true;
     675                 :            : }
     676                 :            : 
     677                 :         46 : bool read_value(Reader& reader, std::string& value, size_t end, size_t len, size_t maximum) noexcept {
     678                 :         46 :   size_t value_end = 0;
     679                 :            : 
     680   [ +  +  +  + ]:         46 :   return reader.begin_length_delimited(end, value_end, len) && read_value_body(reader, value, value_end, maximum);
     681                 :            : }
     682                 :            : 
     683                 :          8 : bool read_value(Reader& reader, Bytes& value, size_t end, size_t len, size_t maximum) noexcept {
     684                 :          8 :   size_t value_end = 0;
     685                 :            : 
     686   [ +  -  +  - ]:          8 :   return reader.begin_length_delimited(end, value_end, len) && read_value_body(reader, value, value_end, maximum);
     687                 :            : }
     688                 :            : 
     689                 :          8 : bool read_value(Reader& reader, std::u16string& value, size_t end, size_t len, Endian encoding,
     690                 :            :                 size_t maximum) noexcept {
     691                 :          8 :   size_t value_end = 0;
     692                 :            : 
     693   [ +  -  +  + ]:         16 :   return reader.begin_length_delimited(end, value_end, len) &&
     694                 :         16 :          read_value_body(reader, value, value_end, encoding, maximum);
     695                 :            : }
     696                 :            : 
     697                 :          9 : bool read_fixed_value(Reader& reader, std::string& value, size_t end, size_t size, size_t len,
     698                 :            :                       size_t maximum) noexcept {
     699                 :          9 :   size_t value_end = 0U;
     700                 :            : 
     701         [ +  + ]:          9 :   if (len == 0U) {
     702   [ +  -  +  +  :          7 :     if VUNLIKELY (reader.position() > end || size > end - reader.position()) {
                   +  + ]
     703                 :          1 :       return false;
     704                 :            :     }
     705                 :            : 
     706                 :          6 :     value_end = reader.position() + size;
     707   [ +  -  -  +  :          2 :   } else if VUNLIKELY (!reader.begin_length_delimited(end, value_end, len) || value_end - reader.position() > size) {
                   -  + ]
     708                 :          0 :     return false;
     709                 :            :   }
     710                 :            : 
     711         [ -  + ]:          8 :   if VUNLIKELY (!read_value_body(reader, value, value_end)) {
     712                 :          0 :     return false;
     713                 :            :   }
     714                 :            : 
     715   [ +  -  +  +  :         39 :   while (!value.empty() && value.back() == '\0') {
                   +  + ]
     716                 :         31 :     value.pop_back();
     717                 :            :   }
     718                 :            : 
     719   [ +  +  +  + ]:         13 :   return maximum == std::numeric_limits<size_t>::max() ||
     720                 :         13 :          is_valid_utf8(reinterpret_cast<const uint8_t*>(value.data()), value.size(), maximum);
     721                 :            : }
     722                 :            : 
     723                 :          6 : bool read_fixed_value(Reader& reader, std::u16string& value, size_t end, size_t size, size_t len, Endian encoding,
     724                 :            :                       size_t maximum) noexcept {
     725                 :          6 :   size_t value_end = 0U;
     726                 :            : 
     727         [ +  + ]:          6 :   if (len == 0U) {
     728   [ +  -  -  +  :          3 :     if VUNLIKELY (reader.position() > end || size > end - reader.position()) {
                   -  + ]
     729                 :          0 :       return false;
     730                 :            :     }
     731                 :            : 
     732                 :          3 :     value_end = reader.position() + size;
     733   [ +  -  -  +  :          3 :   } else if VUNLIKELY (!reader.begin_length_delimited(end, value_end, len) || value_end - reader.position() > size) {
                   -  + ]
     734                 :          0 :     return false;
     735                 :            :   }
     736                 :            : 
     737         [ -  + ]:          6 :   if VUNLIKELY (!read_value_body(reader, value, value_end, encoding)) {
     738                 :          0 :     return false;
     739                 :            :   }
     740                 :            : 
     741   [ +  -  +  +  :         13 :   while (!value.empty() && value.back() == u'\0') {
                   +  + ]
     742                 :          7 :     value.pop_back();
     743                 :            :   }
     744                 :            : 
     745   [ +  +  +  - ]:          6 :   return maximum == std::numeric_limits<size_t>::max() || is_valid_utf16(value.data(), value.size(), maximum);
     746                 :            : }
     747                 :            : 
     748                 :         55 : bool read_value_body(Reader& reader, std::string& value, size_t end, size_t maximum) noexcept {
     749                 :         55 :   const size_t length = end - reader.position();
     750                 :            : 
     751         [ -  + ]:         55 :   if VUNLIKELY (length < sizeof(kUtf8Bom) + 1U) {
     752                 :          0 :     return false;
     753                 :            :   }
     754                 :            : 
     755                 :         55 :   const auto* data = reader.current_data();
     756                 :         55 :   const size_t value_size = length - sizeof(kUtf8Bom) - 1U;
     757                 :            : 
     758   [ +  -  +  +  :         55 :   if VUNLIKELY (!data || std::memcmp(data, kUtf8Bom, sizeof(kUtf8Bom)) != 0 || data[length - 1U] != 0U ||
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     759                 :            :                 !is_valid_utf8(data + sizeof(kUtf8Bom), value_size, maximum)) {
     760                 :         10 :     return false;
     761                 :            :   }
     762                 :            : 
     763                 :         45 :   value.assign(reinterpret_cast<const char*>(data + sizeof(kUtf8Bom)), value_size);
     764                 :            : 
     765                 :         45 :   return reader.skip(length, end);
     766                 :            : }
     767                 :            : 
     768                 :         14 : bool read_value_body(Reader& reader, std::u16string& value, size_t end, Endian encoding, size_t maximum) noexcept {
     769                 :         14 :   const size_t length = end - reader.position();
     770                 :         14 :   const size_t encoded_length = length & ~size_t{1U};
     771                 :            : 
     772   [ +  -  -  +  :         14 :   if VUNLIKELY (encoded_length < kUtf16UnitSize * 2U || encoded_length > kMaxPayloadSize) {
                   -  + ]
     773                 :          0 :     return false;
     774                 :            :   }
     775                 :            : 
     776                 :         14 :   const auto* data = reader.current_data();
     777         [ +  + ]:         14 :   const uint8_t* bom = encoding == Endian::kBig ? kUtf16BomBig : kUtf16BomLittle;
     778                 :            : 
     779   [ +  -  +  +  :         14 :   if VUNLIKELY (!data || std::memcmp(data, bom, kUtf16UnitSize) != 0 || data[encoded_length - 2U] != 0U ||
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     780                 :            :                 data[encoded_length - 1U] != 0U) {
     781                 :          3 :     return false;
     782                 :            :   }
     783                 :            : 
     784                 :         11 :   const uint8_t* units = data + kUtf16UnitSize;
     785                 :         11 :   const size_t unit_count = encoded_length / kUtf16UnitSize - 2U;
     786                 :         11 :   size_t code_point_count = 0U;
     787                 :            : 
     788         [ +  + ]:         30 :   for (size_t index = 0U; index < unit_count; ++index) {
     789                 :         19 :     const uint8_t first = units[index * kUtf16UnitSize];
     790                 :         19 :     const uint8_t second = units[index * kUtf16UnitSize + 1U];
     791         [ +  + ]:         19 :     const auto high = static_cast<uint16_t>(encoding == Endian::kBig ? first : second);
     792         [ +  + ]:         19 :     const auto low = static_cast<uint16_t>(encoding == Endian::kBig ? second : first);
     793                 :         19 :     const auto unit = static_cast<uint16_t>(static_cast<uint16_t>(high << 8U) | low);
     794                 :            : 
     795   [ +  +  +  - ]:         19 :     if (unit >= 0xD800U && unit <= 0xDFFFU) {
     796   [ +  -  -  +  :          1 :       if VUNLIKELY (unit > 0xDBFFU || index + 1U == unit_count) {
                   -  + ]
     797                 :          0 :         return false;
     798                 :            :       }
     799                 :            : 
     800                 :          1 :       const uint8_t next_first = units[(index + 1U) * kUtf16UnitSize];
     801                 :          1 :       const uint8_t next_second = units[(index + 1U) * kUtf16UnitSize + 1U];
     802         [ +  - ]:          1 :       const auto next_high = static_cast<uint16_t>(encoding == Endian::kBig ? next_first : next_second);
     803         [ +  - ]:          1 :       const auto next_low = static_cast<uint16_t>(encoding == Endian::kBig ? next_second : next_first);
     804                 :          1 :       const auto next = static_cast<uint16_t>(static_cast<uint16_t>(next_high << 8U) | next_low);
     805                 :            : 
     806   [ +  -  -  +  :          1 :       if VUNLIKELY (next < 0xDC00U || next > 0xDFFFU) {
                   -  + ]
     807                 :          0 :         return false;
     808                 :            :       }
     809                 :            : 
     810                 :          1 :       ++index;
     811                 :            :     }
     812                 :            : 
     813         [ +  + ]:         19 :     if (maximum != std::numeric_limits<size_t>::max()) {
     814                 :          3 :       ++code_point_count;
     815         [ -  + ]:          3 :       if VUNLIKELY (code_point_count > maximum) {
     816                 :          0 :         return false;
     817                 :            :       }
     818                 :            :     }
     819                 :            :   }
     820                 :            : 
     821                 :         11 :   value.clear();
     822                 :         11 :   value.resize(unit_count);
     823                 :            : 
     824         [ +  + ]:         31 :   for (size_t index = 0U; index < unit_count; ++index) {
     825                 :         20 :     const uint8_t first = units[index * kUtf16UnitSize];
     826                 :         20 :     const uint8_t second = units[index * kUtf16UnitSize + 1U];
     827         [ +  + ]:         20 :     const auto high = static_cast<uint16_t>(encoding == Endian::kBig ? first : second);
     828         [ +  + ]:         20 :     const auto low = static_cast<uint16_t>(encoding == Endian::kBig ? second : first);
     829                 :            : 
     830                 :         20 :     value[index] = static_cast<char16_t>(static_cast<uint16_t>(high << 8U) | low);
     831                 :            :   }
     832                 :            : 
     833                 :         11 :   return reader.skip(length, end);
     834                 :            : }
     835                 :            : 
     836                 :          8 : bool read_value_body(Reader& reader, Bytes& value, size_t end, size_t maximum) noexcept {
     837                 :          8 :   const size_t length = end - reader.position();
     838         [ +  + ]:          8 :   const size_t kept = length < maximum ? length : maximum;
     839                 :            : 
     840         [ +  + ]:          8 :   if (kept == 0U) {
     841                 :          1 :     value.clear();
     842                 :            : 
     843                 :          1 :     return reader.skip(length, end);
     844                 :            :   }
     845                 :            : 
     846   [ +  +  +  -  :          7 :   if (value.is_owner() && value.offset() == 0U && kept <= value.capacity()) {
             +  -  +  + ]
     847   [ +  -  -  +  :          5 :     if VUNLIKELY (!value.resize(kept) || !reader.read(value.data(), kept, end)) {
                   -  + ]
     848                 :          0 :       return false;
     849                 :            :     }
     850                 :            : 
     851                 :          5 :     return reader.skip(length - kept, end);
     852                 :            :   }
     853                 :            : 
     854                 :          2 :   Bytes target = Bytes::create(kept);
     855                 :            : 
     856         [ -  + ]:          2 :   if VUNLIKELY (target.empty()) {
     857                 :          0 :     return false;
     858                 :            :   }
     859                 :            : 
     860         [ -  + ]:          2 :   if VUNLIKELY (!reader.read(target.data(), kept, end)) {
     861                 :          0 :     return false;
     862                 :            :   }
     863                 :            : 
     864                 :          2 :   value = std::move(target);
     865                 :            : 
     866                 :          2 :   return reader.skip(length - kept, end);
     867                 :          2 : }
     868                 :            : 
     869                 :         46 : bool read_tag(Reader& reader, uint8_t& wire_type, uint16_t& data_id, size_t end) noexcept {
     870                 :         46 :   uint64_t raw = 0;
     871                 :            : 
     872   [ +  -  +  +  :         46 :   if VUNLIKELY (!reader.read_unsigned(raw, sizeof(uint16_t), Endian::kBig, end) || (raw & 0x8000U) != 0U) {
                   +  + ]
     873                 :          1 :     return false;
     874                 :            :   }
     875                 :            : 
     876                 :         45 :   wire_type = static_cast<uint8_t>((raw >> 12U) & 0x07U);
     877                 :         45 :   data_id = static_cast<uint16_t>(raw & 0x0FFFU);
     878                 :            : 
     879                 :         45 :   return true;
     880                 :            : }
     881                 :            : 
     882                 :         10 : bool read_union_frame(Reader& reader, size_t len, size_t type_width, size_t end, uint64_t& selector,
     883                 :            :                       size_t& data_end) noexcept {
     884   [ +  -  +  +  :         10 :   if VUNLIKELY ((len != 1U && len != 2U && len != 4U) || (type_width != 1U && type_width != 2U && type_width != 4U)) {
          +  +  -  +  +  
          -  +  +  +  +  
          +  +  -  +  -  
                +  -  + ]
     885                 :          0 :     return false;
     886                 :            :   }
     887                 :            : 
     888                 :         10 :   uint64_t byte_length = 0;
     889                 :            : 
     890   [ +  -  -  +  :         10 :   if VUNLIKELY (!reader.read_unsigned(byte_length, len, Endian::kBig, end) ||
          +  -  -  +  -  
                      + ]
     891                 :            :                 !reader.read_unsigned(selector, type_width, Endian::kBig, end) ||
     892                 :            :                 byte_length > end - reader.position()) {
     893                 :          0 :     return false;
     894                 :            :   }
     895                 :            : 
     896                 :         10 :   data_end = reader.position() + static_cast<size_t>(byte_length);
     897                 :            : 
     898                 :         10 :   return true;
     899                 :            : }
     900                 :            : 
     901                 :         88 : bool write_value_body(Writer& writer, const std::string& value, size_t maximum) noexcept {
     902                 :         88 :   return write_utf8_body(writer, value, maximum, true);
     903                 :            : }
     904                 :            : 
     905                 :         16 : bool write_value_body(Writer& writer, const std::u16string& value, Endian encoding, size_t maximum) noexcept {
     906                 :         16 :   return write_utf16_body(writer, value, encoding, maximum, true);
     907                 :            : }
     908                 :            : 
     909                 :         16 : bool write_value_body(Writer& writer, const Bytes& value, size_t maximum) noexcept {
     910   [ +  -  +  - ]:         16 :   return value.size() <= maximum && writer.append(value.data(), value.size());
     911                 :            : }
     912                 :            : 
     913                 :         64 : bool write_tag(Writer& writer, uint8_t wire_type, uint16_t data_id) noexcept {
     914                 :         64 :   const auto tag = static_cast<uint16_t>((static_cast<uint16_t>(wire_type) << 12U) | data_id);
     915                 :            : 
     916                 :         64 :   return writer.append_unsigned(tag, sizeof(uint16_t), Endian::kBig);
     917                 :            : }
     918                 :            : 
     919                 :         15 : bool write_union_frame(Writer& writer, uint64_t selector, size_t len, size_t type_width, size_t& length_position,
     920                 :            :                        size_t& content_position) noexcept {
     921   [ +  +  +  +  :         15 :   if VUNLIKELY (type_width != 1U && type_width != 2U && type_width != 4U) {
          +  +  -  +  -  
                      + ]
     922                 :          0 :     return false;
     923                 :            :   }
     924                 :            : 
     925         [ -  + ]:         15 :   if VUNLIKELY (selector > (uint64_t{1U} << (type_width * 8U)) - 1U) {
     926                 :          0 :     return false;
     927                 :            :   }
     928                 :            : 
     929                 :         15 :   size_t data_position = 0;
     930                 :            : 
     931   [ +  -  -  +  :         15 :   if VUNLIKELY (!writer.begin_length_delimited(length_position, data_position, len) ||
                   -  + ]
     932                 :            :                 !writer.append_unsigned(selector, type_width, Endian::kBig)) {
     933                 :          0 :     return false;
     934                 :            :   }
     935                 :            : 
     936                 :         15 :   content_position = writer.position();
     937                 :            : 
     938                 :         15 :   return true;
     939                 :            : }
     940                 :            : 
     941                 :         24 : bool begin_tlv_body(Reader& reader, uint8_t wire_type, size_t configured_len, size_t end, size_t& body_end) noexcept {
     942                 :         24 :   size_t width = 0;
     943                 :            : 
     944         [ +  + ]:         24 :   if (wire_type == 4U) {
     945                 :          6 :     width = configured_len;
     946   [ +  -  +  - ]:         18 :   } else if (wire_type >= 5U && wire_type <= 7U) {
     947                 :         18 :     width = size_t{1U} << (wire_type - 5U);
     948                 :            :   } else {
     949                 :          0 :     return false;
     950                 :            :   }
     951                 :            : 
     952                 :         24 :   return reader.begin_length_delimited(end, body_end, width);
     953                 :            : }
     954                 :            : 
     955                 :         45 : bool begin_tlv_complex(Writer& writer, uint16_t data_id, size_t len, bool dynamic, size_t& length_position,
     956                 :            :                        size_t& data_position) noexcept {
     957                 :         45 :   uint8_t wire_type = 7U;
     958                 :            : 
     959         [ +  + ]:         45 :   if (!dynamic) {
     960                 :         10 :     wire_type = 4U;
     961         [ +  + ]:         35 :   } else if (len == 1U) {
     962                 :         29 :     wire_type = 5U;
     963         [ +  + ]:          6 :   } else if (len == 2U) {
     964                 :          4 :     wire_type = 6U;
     965                 :            :   }
     966                 :            : 
     967   [ +  -  +  - ]:         45 :   return write_tag(writer, wire_type, data_id) && writer.begin_length_delimited(length_position, data_position, len);
     968                 :            : }
     969                 :            : 
     970                 :          5 : bool skip_tlv_value(Reader& reader, uint8_t wire_type, size_t configured_len, size_t end) noexcept {
     971   [ +  -  -  -  :          5 :   switch (wire_type) {
                +  +  - ]
     972                 :          1 :     case 0U:
     973                 :          1 :       return reader.skip(sizeof(uint8_t), end);
     974                 :          0 :     case 1U:
     975                 :          0 :       return reader.skip(sizeof(uint16_t), end);
     976                 :          0 :     case 2U:
     977                 :          0 :       return reader.skip(sizeof(uint32_t), end);
     978                 :          0 :     case 3U:
     979                 :          0 :       return reader.skip(sizeof(uint64_t), end);
     980                 :          3 :     case 4U: {
     981                 :          3 :       size_t value_end = 0U;
     982                 :            : 
     983   [ +  -  +  - ]:          6 :       return reader.begin_length_delimited(end, value_end, configured_len) &&
     984                 :          6 :              reader.skip(value_end - reader.position(), value_end);
     985                 :            :     }
     986                 :          1 :     case 5U:
     987                 :            :     case 6U:
     988                 :            :     case 7U: {
     989                 :          1 :       const size_t width = size_t{1U} << (wire_type - 5U);
     990                 :            : 
     991                 :          1 :       size_t value_end = 0;
     992                 :            : 
     993   [ +  -  +  - ]:          2 :       return reader.begin_length_delimited(end, value_end, width) &&
     994                 :          2 :              reader.skip(value_end - reader.position(), value_end);
     995                 :            :     }
     996                 :          0 :     default:
     997                 :          0 :       return false;
     998                 :            :   }
     999                 :            : }
    1000                 :            : 
    1001                 :          4 : void report_check_available_failure() noexcept {
    1002                 :          4 :   std::cerr << "SOME/IP serialization rejected by check_available().\n";
    1003                 :          4 : }
    1004                 :            : 
    1005                 :         67 : bool prepare_destination(Bytes& des, size_t size, uint8_t offset) noexcept {
    1006   [ +  +  +  -  :         67 :   if (des.is_owner() && des.offset() == offset && size <= des.capacity()) {
             +  +  +  + ]
    1007         [ -  + ]:          7 :     if VUNLIKELY (!des.resize(size)) {
    1008                 :          0 :       return false;
    1009                 :            :     }
    1010                 :            :   } else {
    1011                 :         60 :     des = Bytes::create(size, offset);
    1012                 :            :   }
    1013                 :            : 
    1014   [ +  -  +  - ]:         67 :   return size == 0U || des.data() != nullptr;
    1015                 :            : }
    1016                 :            : 
    1017                 :            : }  // namespace detail
    1018                 :            : 
    1019                 :            : }  // namespace SomeipSerializer
    1020                 :            : 
    1021                 :            : }  // namespace vlink

Generated by: LCOV version 1.14