E-MailRelay
ghashstate.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file ghashstate.h
19///
20
21#ifndef G_HASH_STATE_H
22#define G_HASH_STATE_H
23
24#include "gdef.h"
25#include <string>
26#include <array>
27
28namespace G
29{
30 class HashStateImp ;
31 template <unsigned int N, typename U, typename S> class HashState ;
32}
33
34//| \class G::HashStateImp
35/// The non-template part of G::HashState.
36///
37class G::HashStateImp
38{
39public:
40 template <typename U> static std::string extension( U n ) ;
41 ///< Returns the given data size as a four-character
42 ///< string.
43
44protected:
45 template <typename U> static void convert_( U n , std::string::iterator p ) ;
46 ///< Encodes the given value into four characters.
47
48public:
49 HashStateImp() = delete ;
50} ;
51
52//| \class G::HashState
53/// Functions for representing the intermediate state of a hash function
54/// as a non-printable string. The input is an array of 'N/4' 32-bit
55/// values. The output is a string of N non-printable characters, or N+4
56/// characters if also including the data size. The 'U' type can be more
57/// than 32 bits wide but it should hold values of no more than 32 bits
58/// significance.
59/// \see G::Hash::printable
60///
61template <unsigned int N, typename U, typename S>
62class G::HashState : public HashStateImp
63{
64public:
65 using uint_type = U ;
66 using size_type = S ;
67 static_assert( N != 0 && (N%4) == 0 , "hash state size must be a multiple of four" ) ;
68
69 static std::string encode( const uint_type * ) ;
70 ///< Returns the hash state as an N-character string of
71 ///< non-printing characters.
72
73 static std::string encode( const uint_type * , size_type n ) ;
74 ///< Returns the hash state as a string that also
75 ///< has the original data size as a four-character
76 ///< extension().
77
78 static std::string encode( uint_type hi , uint_type low , const uint_type * ) ;
79 ///< An overload with a hi/low bit count.
80
81 static std::string encode( uint_type hi , uint_type low , uint_type v0 , uint_type v1 ,
82 uint_type v2 , uint_type v3 , uint_type v4 = 0 ) ;
83 ///< An overload for N=16 or N=20 with broken-out
84 ///< values and a hi/low bit count.
85
86 static void decode( const std::string & s , uint_type * values_out , size_type & size_out ) ;
87 ///< Converts an encode()d string back into a hash
88 ///< state of N/4 integers and a data size returned
89 ///< by reference. The data size is returned as zero
90 ///< if the input string is only N characters long.
91
92 static void decode( const std::string & , uint_type & size_hi_out , uint_type & size_low_out ,
93 uint_type * value_0 , uint_type * value_1 , uint_type * value_2 , uint_type * value_3 ,
94 uint_type * value_4 = nullptr ) ;
95 ///< An overload for N=16 or N=20 with broken-out
96 ///< values and hi/low bit count.
97
98 static void decode( const std::string & , uint_type & size_hi_out , uint_type & size_low_out ,
99 uint_type * values_out ) ;
100 ///< An overload for a hi/low bit count.
101
102public:
103 HashState() = delete ;
104
105private:
106 static void convert( char hi , char himid , char lomid , char lo , uint_type & n ) ;
107 static void convert( const std::string & str , uint_type & n ) ;
108 static void convert( const std::string & s , uint_type * state ) ;
109 static void convert( const std::string & s , uint_type * state , size_type & ) ;
110} ;
111
112template <unsigned int N, typename U, typename S>
113std::string G::HashState<N,U,S>::encode( const uint_type * values )
114{
115 std::string result( N , '\0' ) ;
116 for( std::size_t i = 0U ; i < N/4 ; i++ )
117 {
118 convert_( values[i] , result.begin() + (i*4U) ) ; // NOLINT narrowing
119 }
120 return result ;
121}
122
123template <unsigned int N, typename U, typename S>
124std::string G::HashState<N,U,S>::encode( const uint_type * values , size_type n )
125{
126 std::string result( N+4U , '\0' ) ;
127 for( std::size_t i = 0U ; i < N/4 ; i++ )
128 {
129 convert_( values[i] , result.begin() + (i*4U) ) ; // NOLINT narrowing
130 }
131 convert_( n , result.begin() + N ) ;
132 return result ;
133}
134
135template <unsigned int N, typename U, typename S>
136std::string G::HashState<N,U,S>::encode( uint_type hi , uint_type low , const uint_type * values )
137{
138 uint_type n = hi ;
139 n <<= 29 ;
140 n |= ( low >> 3 ) ;
141 return encode( values , n ) ;
142}
143
144template <unsigned int N, typename U, typename S>
145std::string G::HashState<N,U,S>::encode( uint_type hi , uint_type low , uint_type v0 ,
146 uint_type v1 , uint_type v2 , uint_type v3 , uint_type v4 )
147{
148 unsigned int NN = N ; // workround for msvc C4127
149 uint_type n = hi ;
150 n <<= 29 ;
151 n |= ( low >> 3 ) ;
152 std::array<uint_type,N/4> values {} ;
153 if( NN > 0 ) values[0] = v0 ;
154 if( NN > 4 ) values[1] = v1 ;
155 if( NN > 8 ) values[2] = v2 ;
156 if( NN > 12 ) values[3] = v3 ;
157 if( NN > 16 ) values[4] = v4 ;
158 return encode( values.data() , n ) ;
159}
160
161template <typename U>
162std::string G::HashStateImp::extension( U n )
163{
164 std::string result( 4U , '\0' ) ;
165 convert_( n , result.begin() ) ;
166 return result ;
167}
168
169template <unsigned int N, typename U, typename S>
170void G::HashState<N,U,S>::decode( const std::string & str , uint_type * values_out , size_type & size_out )
171{
172 if( str.length() < (N+4U) )
173 return decode( str+std::string(N+4U,'\0') , values_out , size_out ) ; // call ourselves again if too short // NOLINT recursion
174 convert( str , values_out , size_out ) ;
175}
176
177template <unsigned int N, typename U, typename S>
178void G::HashState<N,U,S>::decode( const std::string & str , uint_type & hi , uint_type & low ,
179 uint_type * v0 , uint_type * v1 , uint_type * v2 , uint_type * v3 , uint_type * v4 )
180{
181 if( str.length() < (N+4U) )
182 return decode( str+std::string(N+4U,'\0') , hi , low , v0 , v1 , v2 , v3 , v4 ) ; // call ourselves again if too short // NOLINT recursion
183 std::array<uint_type,N/4> values {} ;
184 uint_type n ;
185 convert( str , values.data() , n ) ;
186 if( v0 && N > 0 ) *v0 = values[0] ;
187 if( v1 && N > 4 ) *v1 = values[1] ;
188 if( v2 && N > 8 ) *v2 = values[2] ;
189 if( v3 && N > 12 ) *v3 = values[3] ;
190 if( v4 && N > 16 ) *v4 = values[4] ;
191 hi = ( n >> 29 ) ;
192 low = ( n << 3 ) & 0xffffffffUL ;
193}
194
195template <unsigned int N, typename U, typename S>
196void G::HashState<N,U,S>::decode( const std::string & str , uint_type & hi , uint_type & low ,
197 uint_type * values_out )
198{
199 if( str.length() < (N+4U) )
200 return decode( str+std::string(N+4U,'\0') , hi , low , values_out ) ; // call ourselves again if too short // NOLINT recursion
201 uint_type n ;
202 convert( str , values_out , n ) ;
203 hi = ( n >> 29 ) ;
204 low = ( n << 3 ) & 0xffffffffUL ;
205}
206
207template <typename U>
208void G::HashStateImp::convert_( U n , std::string::iterator p_out )
209{
210 *p_out++ = static_cast<char>(n&0xffU) ; n >>= 8U ;
211 *p_out++ = static_cast<char>(n&0xffU) ; n >>= 8U ;
212 *p_out++ = static_cast<char>(n&0xffU) ; n >>= 8U ;
213 *p_out++ = static_cast<char>(n&0xffU) ;
214}
215
216template <unsigned int N, typename U, typename S>
217void G::HashState<N,U,S>::convert( char hi , char himid , char lomid , char lo , uint_type & n_out )
218{
219 n_out = 0U ;
220 n_out |= static_cast<unsigned char>(hi) ; n_out <<= 8 ;
221 n_out |= static_cast<unsigned char>(himid) ; n_out <<= 8 ;
222 n_out |= static_cast<unsigned char>(lomid) ; n_out <<= 8 ;
223 n_out |= static_cast<unsigned char>(lo) ;
224}
225
226template <unsigned int N, typename U, typename S>
227void G::HashState<N,U,S>::convert( const std::string & str , uint_type & n_out )
228{
229 convert( str.at(3) , str.at(2) , str.at(1) , str.at(0) , n_out ) ;
230}
231
232template <unsigned int N, typename U, typename S>
233void G::HashState<N,U,S>::convert( const std::string & str , uint_type * state_out )
234{
235 for( std::size_t i = 0U ; i < (N/4U) ; i++ )
236 {
237 convert( str.at(i*4U+3U) , str.at(i*4U+2U) , str.at(i*4U+1U) , str.at(i*4U+0U) , state_out[i] ) ;
238 }
239}
240
241template <unsigned int N, typename U, typename S>
242void G::HashState<N,U,S>::convert( const std::string & str , uint_type * state_out , size_type & n_out )
243{
244 convert( str , state_out ) ;
245 uint_type nn = 0 ;
246 convert( str.at(N+3U) , str.at(N+2U) , str.at(N+1U) , str.at(N) , nn ) ;
247 n_out = static_cast<size_type>(nn) ;
248}
249
250#endif
Functions for representing the intermediate state of a hash function as a non-printable string.
Definition: ghashstate.h:63
static std::string encode(const uint_type *)
Returns the hash state as an N-character string of non-printing characters.
Definition: ghashstate.h:113
static void decode(const std::string &s, uint_type *values_out, size_type &size_out)
Converts an encode()d string back into a hash state of N/4 integers and a data size returned by refer...
Definition: ghashstate.h:170
Low-level classes.
Definition: garg.h:36