In the previous article, I initially analyzed some usage of redis tool files, including two random algorithms and Cyclic Redundancy verification algorithms. Today, continue to learn the usage of some other auxiliary tools in redis. It includes the size-end conversion algorithm, Sha Algorithm Implementation in redis, and general tool-class algorithm util. C.
Let's take a look at the size-end conversion algorithm. People who have learned about the operating system on the size-end must know what it means. In different operating systems, the storage of high numbers exists, and the former is high, after the low position, or after the high position, the low position is before, so conversion is involved here. There are different conversion methods based on different operating systems, so redis opened such a batch of APIs in this respect;
/* For 16-bit, 32-bit, 64-bit conversion */void memrev16 (void * P); void memrev32 (void * P ); void memrev64 (void * P); uint16_t intrev16 (uint16_t V); uint32_t intrev32 (uint32_t V); uint64_t intrev64 (uint64_t V );
Pick out the implementation of one of the APIS:
/* Toggle the 32 bit unsigned integer pointed by * P from little endian to * big endian * // * 32 bits require 4 bytes, 0th and 3rd bits, exchange 1st and 2nd bytes */void memrev32 (void * P) {unsigned char * x = P, T; t = x [0]; X [0] = x [3]; X [3] = T; t = x [1]; X [1] = x [2]; X [2] = T ;}
In short, it is to exchange the head and tail.
The following implementation of the encryption algorithm in redis uses the Sha algorithm,/Sha: Secure Hash Algorithm Security Hash algorithm. Similar to the MD5 algorithm, it is also a one-way encryption algorithm, the encryption length is greatly extended, and the security is also higher. The length of a string or binary stream cannot exceed 2 ^ 64 bits or less. After SHA-1 encoding, generates a 160-bit binary string. C language calls in redis:
Intmain (INT argc, char ** argv) {sha1_ctx; unsigned char hash [20], Buf [bufsize]; int I; for (I = 0; I <bufsize; I ++) BUF [I] = I;/* Sha algorithm calling method in redis Code */sha1init (& CTX); for (I = 0; I <1000; I ++) sha1update (& CTX, Buf, bufsize); sha1final (hash, & CTX); printf ("sha1 ="); for (I = 0; I <20; I ++) printf ("% 02x", hash [I]); printf ("\ n"); Return 0 ;}
Finally, let's talk about the Algorithm Implementation of the util. c generic tool class. There are many highlights in it. First, let's look at the specific API, which mainly involves the conversion between numbers and strings:
Int stringmatchlen (const char * P, int Plen, const char * s, int slen, int nocase);/* supports the wildcard format of Glob-style, for example, * indicates any one or more characters ,? Represents any character, and [ABC] represents any letter in square brackets. */INT stringmatch (const char * P, const char * s, int nocase);/* supports the Glob-style wildcard format, and the length calculation is placed inside the method, directly input the mode and the original string */long memtoll (const char * P, int * ERR ); /* the memory size is converted to a byte value, indicating */INT ll2string (char * s, size_t Len, long value ); /* convert the long type to the string type */INT string2ll (const char * s, size_t slen, long * value ); /* convert the string type to the long type */INT string2l (const char * s, size_t slen, long * value);/* convert the string type to the long type, the core call method is the string2ll () method */INT d2string (char * Buf, size_t Len, double value ); /* convert the double type to the string type */SDS getabsolutepath (char * filename);/* obtain the absolute path of the input file name */INT pathisbasename (char * path ); /* determine whether a path is a pure file name, not a relative or absolute path */
Looking at the first method, the implementation of the regular expression matching principle, we usually only know how to call the system's regular expression to match the string, but do not know the principle. Today we always understand:
/* Glob-style pattern matching. * // * supports the Glob-style wildcard format. For example, * indicates any one or more characters ,? Represents any character, and [ABC] represents any letter in square brackets. */INT stringmatchlen (const char * pattern, int patternlen, const char * string, int stringlen, int nocase) {While (patternlen) {Switch (pattern [0]) {Case '*': While (pattern [1] = '*') {// If ** appears, it indicates that it must match pattern ++; patternlen --;} if (patternlen = 1) return 1;/* match */while (stringlen) {If (stringmatchlen (Pattern + 1, patternLen-1, String, stringlen, nocase) return 1; /* match */string ++; strin Glen --;} return 0;/* No match */break; case '? ': If (stringlen = 0) return 0;/* No match * // * because? It can represent any character. Therefore, move the matched character back to another character */string ++; stringlen --; break; Case '[': {int not, match; pattern ++; patternlen --; not = pattern [0] = '^'; If (not) {pattern ++; patternlen --;} match = 0; while (1) {If (pattern [0] = '\') {// if an escape character is encountered, the pattern character is moved back to the position pattern ++; patternlen --; if (pattern [0] = string [0]) match = 1;} else if (pattern [0] = ']') {// stop break until another brackets exist.} else if (patternlen = 0) {pat Tern --; patternlen ++; break;} else if (pattern [1] = '-' & patternlen> = 3) {int start = pattern [0]; int end = pattern [2]; int c = string [0]; If (Start> end) {int T = start; Start = end; end = T ;} if (nocase) {start = tolower (start); End = tolower (end); C = tolower (c);} Pattern + = 2; patternlen-= 2; if (C> = Start & C <= END) match = 1;} else {If (! Nocase) {If (pattern [0] = string [0]) match = 1;} else {If (tolower (INT) pattern [0]) = tolower (INT) string [0]) match = 1 ;}} pattern ++; patternlen --;} If (not) match =! Match; If (! Match) return 0;/* No match */string ++; stringlen --; break;} case '\': If (patternlen> = 2) {pattern ++; patternlen --;}/* fall through */Default:/* if no key character of the regular expression exists, directly compare */If (! Nocase) {If (pattern [0]! = String [0]) // The return 0 is not matched directly./* No match */} else {If (tolower (INT) pattern [0])! = Tolower (INT) string [0]) return 0;/* No match */} string ++; stringlen --; break;} pattern ++; patternlen --; if (stringlen = 0) {While (* pattern = '*') {pattern ++; patternlen --;} break ;}} if (patternlen = 0 & stringlen = 0) // if the length of the matched character and pattern character is reduced to 0, return 1; return 0;} is successful ;}
The code is amazing. I never wanted to implement the regular expression principle in the past. Another method is the ll2string method, which converts numbers to characters. If it is our common practice, it is to add the corresponding numeric characters in addition to 10, but what we want to convert is the LL type. The length is very long and the efficiency will lead to a relatively low level. Therefore, in redis, the author directly assigns a value based on the division of 100, two bits and two bits, it also uses numbers, numbers, and numbers for processing, and directly assigns values by subscript to avoid multiple judgments on the remainder:
/* Convert a long into a string. returns the number of * characters needed to represent the number. * If the buffer is not big enough to store the string, 0 is returned. ** based on the following article (that apparently does not provide a * novel approach but only publicizes an already used technique): ** https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/1015 1361643253920 ** modified in order to handle signed integers since the original code was * designed for unsigned integers. * // * convert the long type to the string type */INT ll2string (char * DST, size_t dstlen, long svalue) {static const char digits [201] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" "606162636465666768697071 7273747576777879 "" 8081828384858687888990919293949596979899 "; int negative; unsigned long value;/* The main loop works with 64bit unsigned integers for simplicity, so * we convert the number here and remember if it is negative. * // * determine the positive and negative numbers here */If (svalue <0) {If (svalue! = Llong_min) {value =-svalue;} else {value = (unsigned long) llong_max) + 1;} negative = 1;} else {value = svalue; negative = 0;}/* Check Length. */uint32_t const length = digits10 (value) + negative; If (length> = dstlen) return 0;/* null term. */uint32_t next = length; DST [next] = '\ 0'; next --; while (value >=100) {// convert the value to int const I = (Value % 100) * 2; value/= 100; // The remainder value represented by I replaces DST [next] = digits [I + 1] with the corresponding number in the digits character array; DST [next-1] = digits [I]; next-= 2;}/* handle last 1-2 digits. */If (value <10) {DST [next] = '0' + (uint32_t) value;} else {int I = (uint32_t) value * 2; DST [next] = digits [I + 1]; DST [next-1] = digits [I];}/* add sign. */If (negative) DST [0] = '-'; return length ;}
Digit [201] is a numeric character from to 99. The assignment of the remainder is based on this array, which is efficient and convenient and greatly improves the speed. Some highlights of redis Code are also found.
Redis source code analysis (24) --- tool (2)