E-MailRelay
geightbit.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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 geightbit.h
19///
20
21#ifndef G_EIGHTBIT_H
22#define G_EIGHTBIT_H
23
24#include "gdef.h"
25#include "galign.h"
26#include <memory>
27#include <algorithm>
28
29namespace G
30{
31 namespace EightBitImp /// An implementation namespace for G::eightbit().
32 {
33 template <typename T, T t, unsigned int N>
34 struct extend /// Evaluates a type 'T' bitmask comprising N copies of byte 't'.
35 {
36 // eg. 0x80808080
37 static constexpr T value = ( extend<T,t,N-1U>::value << 8U ) | t ;
38 } ;
39
40 template <typename T, T t>
41 struct extend<T,t,1U> /// Terminal specialisation of extend<>.
42 {
43 static constexpr T value = t ;
44 } ;
45
46 template <typename T>
47 struct is8bit_fn /// Functor returning true if 't' AND-ed with an extend mask based on 0x80 is non-zero.
48 {
49 inline constexpr bool operator()( T t ) const noexcept { return ( t & extend<T,0x80,sizeof(T)>::value ) != 0 ; }
50 } ;
51
52 template <typename T>
53 inline
54 bool is8bit_imp_int( const unsigned char * p , std::size_t n )
55 {
56 is8bit_fn<T> fn ;
57 std::size_t j = 0U ;
58 for( std::size_t i = 0U ; i < n ; i++ , j += sizeof(T) )
59 {
60 T t = 0 ;
61 std::memcpy( &t , &p[j] , sizeof(T) ) ; // strict-aliasing shenanigans, gets optimised out
62 if( fn(t) )
63 return true ;
64 }
65 return false ;
66 }
67
68 inline bool is8bit_imp_uchar( const unsigned char * p0 , std::size_t n )
69 {
70 const unsigned char * end = p0 + n ;
71 return std::find_if( p0 , end , [](char c){return (c & 0x80U)!=0U ;} ) != end ;
72 }
73
74 inline bool is8bit_slow( const unsigned char * p0 , std::size_t n )
75 {
76 return is8bit_imp_uchar( p0 , n ) ;
77 }
78
79 inline bool is8bit_faster( const unsigned char * p0 , std::size_t n )
80 {
81 using byte_t = unsigned char ;
82 using int_t = unsigned long ; // or uint if faster
83 const void * vp1 = G::align<int_t>( p0 , n ) ;
84 if( vp1 == nullptr )
85 {
86 return is8bit_slow( p0 , n ) ;
87 }
88 else
89 {
90 // split into three ranges, with a big aligned range in the middle
91 const byte_t * p1 = static_cast<const byte_t*>(vp1) ;
92 const std::size_t n0 = std::distance( p0 , p1 ) ;
93 const std::size_t n1 = G::align_mask<int_t>( n - n0 ) ;
94 const std::size_t ni1 = G::align_shift<int_t>( n - n0 ) ;
95 const std::size_t n2 = n - n0 - n1 ;
96 const byte_t * p2 = p0 + n0 + n1 ;
97 return
98 is8bit_imp_uchar(p0,n0) ||
99 is8bit_imp_int<int_t>(p1,ni1) ||
100 is8bit_imp_uchar(p2,n2) ;
101 }
102 }
103 }
104
105 /// Returns true if the given data buffer contains a byte greater than 127.
106 /// An overload for an unsigned char buffer.
107 ///
108 inline bool eightbit( const unsigned char * p , std::size_t n )
109 {
110 namespace imp = EightBitImp ;
111 return imp::is8bit_faster( p , n ) ;
112 }
113
114 /// Returns true if the given data buffer contains a character greater than 127.
115 /// An overload for a char buffer.
116 ///
117 inline bool eightbit( const char * p , std::size_t n )
118 {
119 namespace imp = EightBitImp ;
120 return imp::is8bit_faster( reinterpret_cast<const unsigned char *>(p) , n ) ;
121 }
122
123 /// Returns true if the given data buffer contains a byte greater than 127.
124 /// An overload for an unsigned char buffer, with no optimisation.
125 ///
126 inline bool eightbit( const unsigned char * p , std::size_t n , int )
127 {
128 namespace imp = EightBitImp ;
129 return imp::is8bit_slow( p , n ) ;
130 }
131
132 /// Returns true if the given data buffer contains a character greater than 127.
133 /// An overload for a char buffer, with no optimisation.
134 ///
135 inline bool eightbit( const char * p , std::size_t n , int )
136 {
137 namespace imp = EightBitImp ;
138 return imp::is8bit_slow( reinterpret_cast<const unsigned char *>(p) , n ) ;
139 }
140}
141
142#endif
Low-level classes.
Definition: galign.h:28
bool eightbit(const unsigned char *p, std::size_t n)
Returns true if the given data buffer contains a byte greater than 127.
Definition: geightbit.h:108
Evaluates a type 'T' bitmask comprising N copies of byte 't'.
Definition: geightbit.h:35
Functor returning true if 't' AND-ed with an extend mask based on 0x80 is non-zero.
Definition: geightbit.h:48