xref: /aosp_15_r20/external/pigweed/pw_checksum/public/pw_checksum/crc32.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // CRC-32 (CRC32) implementation with initial value 0xFFFFFFFF. This provides C
16 // functions and a C++ class. Use of the C API is discouraged; use the Crc32
17 // class whevener possible.
18 #pragma once
19 
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #include "pw_checksum/internal/config.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif  // __cplusplus
28 
29 // Value of an empty CRC32. May be serve as the starting CRC32 value for
30 // pw_checksum_Crc32Append.
31 #define PW_CHECKSUM_EMPTY_CRC32 ~_PW_CHECKSUM_CRC32_INITIAL_STATE
32 
33 // The initial state for internal CRC32 calculations. Do not use this value
34 // directly.
35 #define _PW_CHECKSUM_CRC32_INITIAL_STATE 0xFFFFFFFFu
36 
37 // Internal implementation function for CRC32. Do not call it directly.
38 uint32_t _pw_checksum_InternalCrc32EightBit(const void* data,
39                                             size_t size_bytes,
40                                             uint32_t state);
41 
42 uint32_t _pw_checksum_InternalCrc32FourBit(const void* data,
43                                            size_t size_bytes,
44                                            uint32_t state);
45 uint32_t _pw_checksum_InternalCrc32OneBit(const void* data,
46                                           size_t size_bytes,
47                                           uint32_t state);
48 
49 #if PW_CHECKSUM_CRC32_DEFAULT_IMPL == PW_CHECKSUM_CRC32_8BITS
50 #define _pw_checksum_InternalCrc32 _pw_checksum_InternalCrc32EightBit
51 #elif PW_CHECKSUM_CRC32_DEFAULT_IMPL == PW_CHECKSUM_CRC32_4BITS
52 #define _pw_checksum_InternalCrc32 _pw_checksum_InternalCrc32FourBit
53 #elif PW_CHECKSUM_CRC32_DEFAULT_IMPL == PW_CHECKSUM_CRC32_1BITS
54 #define _pw_checksum_InternalCrc32 _pw_checksum_InternalCrc32OneBit
55 #endif
56 
57 // Calculates the CRC32 for the provided data.
pw_checksum_Crc32(const void * data,size_t size_bytes)58 static inline uint32_t pw_checksum_Crc32(const void* data, size_t size_bytes) {
59   return ~_pw_checksum_InternalCrc32(
60       data, size_bytes, _PW_CHECKSUM_CRC32_INITIAL_STATE);
61 }
62 
63 // Updates an existing CRC value. The previous_result must have been returned
64 // from a previous CRC32 call.
pw_checksum_Crc32Append(const void * data,size_t size_bytes,uint32_t previous_result)65 static inline uint32_t pw_checksum_Crc32Append(const void* data,
66                                                size_t size_bytes,
67                                                uint32_t previous_result) {
68   // CRC32 values are finalized by inverting the bits. The finalization step
69   // must be undone before appending to a prior CRC32 value, then redone so this
70   // function returns a usable value after each call.
71   return ~_pw_checksum_InternalCrc32(data, size_bytes, ~previous_result);
72 }
73 
74 #ifdef __cplusplus
75 }  // extern "C"
76 
77 #include "pw_span/span.h"
78 
79 namespace pw::checksum {
80 
81 // Calculates the CRC32 for all data passed to Update.
82 //
83 // This class is more efficient than the CRC32 C functions since it doesn't
84 // finalize the value each time it is appended to.
85 template <uint32_t (*kChecksumFunction)(const void*, size_t, uint32_t)>
86 class Crc32Impl {
87  public:
88   // Calculates the CRC32 for the provided data and returns it as a uint32_t.
89   // To update a CRC in multiple pieces, use an instance of the Crc32 class.
Calculate(span<const std::byte> data)90   static uint32_t Calculate(span<const std::byte> data) {
91     return ~kChecksumFunction(
92         data.data(), data.size_bytes(), _PW_CHECKSUM_CRC32_INITIAL_STATE);
93   }
94 
Crc32Impl()95   constexpr Crc32Impl() : state_(kInitialValue) {}
96 
Update(span<const std::byte> data)97   void Update(span<const std::byte> data) {
98     state_ = kChecksumFunction(data.data(), data.size(), state_);
99   }
100 
Update(std::byte data)101   void Update(std::byte data) { Update(span(&data, 1)); }
102 
103   // Returns the value of the CRC32 for all data passed to Update.
value()104   uint32_t value() const { return ~state_; }
105 
106   // Resets the CRC to the initial value.
clear()107   void clear() { state_ = kInitialValue; }
108 
109  private:
110   static constexpr uint32_t kInitialValue = _PW_CHECKSUM_CRC32_INITIAL_STATE;
111 
112   uint32_t state_;
113 };
114 
115 using Crc32 = Crc32Impl<_pw_checksum_InternalCrc32>;
116 using Crc32EightBit = Crc32Impl<_pw_checksum_InternalCrc32EightBit>;
117 using Crc32FourBit = Crc32Impl<_pw_checksum_InternalCrc32FourBit>;
118 using Crc32OneBit = Crc32Impl<_pw_checksum_InternalCrc32OneBit>;
119 
120 }  // namespace pw::checksum
121 
122 #endif  // __cplusplus
123