preface

In business development, we often deal with states, and we often see less efficient ways of dealing with them, such as storing various state values as strings. The processing efficiency of strings is far less efficient than that of numbers. Therefore, a better method for performance is to define the status value as an integer number, and then map it to the specific meaning in business.

Defining state values with integers would have been a best practice. But I came across an article on Android state management best practices if you don’t have to plant potatoes on Mars, and I was impressed by the hexadecimal state management approach. This article will again illustrate the representation of hexadecimal state, why it is used, and what the benefits are.

At the same time, the multi-state management reminds me of the previous development, the processing of multi-label fields made us suffer a lot, to be convenient and inefficient, to be efficient is not convenient. Before and after comparison, multi-label management and state management have the same wonderful, can also use the hexadecimal way to express. Examples will also be given in this paper.

Hexadecimal state

The hexadecimal state indicates the use of bit operations. In computer processing, bit operations are always faster than addition, subtraction, multiplication and division. Therefore, the representation of states in base has a unique efficiency advantage.

Example of base representation

If there is a state variable, there are three kinds of initial state, intermediate state and final state, and each state has two subdivided internal states respectively, these three large states can be called state group. Use hexadecimal to define these six states:

const (
    STATUS_1 = 0x0001 // Initial state 1
    STATUS_2 = 0x0002 // Initial state 2
    STATUS_3 = 0x0004 // Intermediate state 1
    STATUS_4 = 0x0008 // Intermediate state 2
    STATUS_5 = 0x0010 // Final state 1
    STATUS_6 = 0x0020 // Final state 2
)
Copy the code

Add state

When you need to add a certain state, use or operation | :

/ / state groups: when you need to add state, use or operation |
const (
    INIT_STATUS   = STATUS_1 | STATUS_2 // Initial state
    MIDDLE_STATUS = STATUS_3 | STATUS_4 // Intermediate state
    FINAL_STATUS  = STATUS_5 | STATUS_6 // Final state
)
Copy the code

Contains the status

When you need to determine whether a state is included or not, use the and operation &. A result of 0 indicates that the specified state is not included

// Use & when you want to check whether a state is included or not. If the result is 0, the state is not included
const( CONTAINS_STATUS_1 = (INIT_STATUS&STATUS_1 ! =0) CONTAINS_STATUS_3 = (INIT_STATUS&STATUS_3 ! =0))Copy the code
func main(a) {
	fmt.Println("Initial state contains state 1:", CONTAINS_STATUS_1)
	fmt.Println("Initial state contains state 3:", CONTAINS_STATUS_3)
}
// The initial state contains state 1: true
// The initial state contains state 3: false
Copy the code

Out of state

When you want to exclude states, use the and operation and the inverse operation &^

// When the state needs to be excluded, use the and operation and take the inverse operation &^(note that the inverse operation is ^ in go and usually ~ in other languages)
const (
	INIT_STATUS_1   = INIT_STATUS & ^STATUS_2   // == STATUS_1
	MIDDLE_STATUS_3 = MIDDLE_STATUS & ^STATUS_4 // == STATUS_3
	FINAL_STATUS_5  = FINAL_STATUS & ^STATUS_6  // == STATUS_5
)
Copy the code
func main(a) {
	fmt.Println(
		INIT_STATUS_1 == STATUS_1, // When 2 is excluded, it equals 1
		MIDDLE_STATUS_3 == STATUS_3, // If you exclude 4, it equals 3
		FINAL_STATUS_5 == STATUS_5, // If 6 is excluded, it equals 5)}// true true true
Copy the code

Principle of base representation

In fact, it is not necessary to use hexadecimal state representation, binary, octal, decimal any kind of base can be. Essentially, it is to satisfy that the various state values are strictly different when the and or operation is performed. For example, the following two binary numbers:

0001
0011
Copy the code

You cannot represent two different state values. Because 0011 contains 0001. To make the state representations strictly different, each bit should be exclusive to 1:

0001 = 2^0 = 1 
0010 = 2^1 = 2
0100 = 2^2 = 4
1000 = 2^3 = 8
Copy the code

If the status is expressed in decimal, the value should be 20,21,22,23… , 2 n2 ^ 0, 2 ^ ^ 3 ^ 2, 2 1, 2,… , 2 ^ n20, 21,22,23,… ,2n

In code writing, on the one hand, for the convenience of representation, on the other hand, it needs to be distinguished from the usual decimal number calculation, in practice, hexadecimal is often used for representation (hexadecimal on the left, binary, decimal on the right):

0x0001 = 0000000000000001 = 2^0 = 1
0x0002 = 0000000000000010 = 2^1 = 2
0x0004 = 0000000000000100 = 2^2 = 4
0x0008 = 0000000000001000 = 2^3 = 8
0x0010 = 0000000000010000 = 2^4 = 16
0x0020 = 0000000000100000 = 2^5 = 32.Copy the code

In the code to begin with 0x can represent a hexadecimal number, by increasing the number can be very convenient to expand the range of representation, from right to left, in each bit in turn exhausted 1,2,4,8 can go to the left one, use up, very convenient.

Add state

0x0001 | 0x0002:

0000000000000001
0000000000000010-- -- -- -- -- -- -- --0000000000000011
=0x0003
Copy the code

Contains the status

0x0003 & 0x0001:

0000000000000011
0000000000000001-- -- -- -- -- -- -- --0000000000000001 
=0x0001! =0
Copy the code

Out of state

0x0003 & ^0x0001:

^0x0001= ^0000000000000001=1111111111111110

0000000000000011
1111111111111110-- -- -- -- -- -- -- --0000000000000010
=0x0002
Copy the code

The benefits of base representation

Hexadecimal status, especially suitable for the combination of multiple complex states.

If, under normal circumstances, there are initial states, intermediate states and final states; In exceptional cases there are only initial and final states.

On database storage, the usual processing requires two fields to indicate an exception and three different states. Use situation to indicate whether a situation is abnormal (1- normal, 2- abnormal) and status to indicate its state (1- initial state, 2- intermediate state, 3- final state).

If we were to query for a normal, initial or final record, the query would compare the values of two fields:

SELECT * FROM table WHERE situation=1 AND status IN (1.3);
Copy the code

With the base representation of status, multiple fields can be stored using status as a single field:

const (
  STATUS_NORMAL   = 0x0001
  STATUS_ABNORMAL = 0x0002
  STATUS_INIT     = 0x0004
  STATUS_MIDDLE   = 0x0008
  STATUS_FINAL    = 0x0010
)
Copy the code

Values in normal, initial, or final states are:

(STATUS_NORMAL | STATUS_INIT) and (STATUS_NORMAL | STATUS_FINAL)Copy the code

The query statement could be written as:

SELECT * FROM table WHERE status in (0x0001|0x0004.0x0001|0x0010);
Copy the code

The database only needs to compare the values of one field. The complexity is reduced from m * n to M + N, which improves efficiency and reduces storage.

Hexadecimal multi-label management

In a database, we often face the problem of “one to many” relationship multi-terminal processing. Either the multi – end independent storage table, each query more than one table association; Or, multiple ends are stored in a field in the same table (for example, as a String or JSON field), which brings many difficulties and inefficiency to the field query. For example, the field label can be any one or more of “gambling, pornography, or fraud”. When we want to query for violations that result in “gambling” and “fraud”, the value of the label field will be different:

SELECT * FROM table WHERE label IN(" gambling, fraud "," fraud, gambling ");Copy the code

Things get really bad when there are more tag results.

If we also want to query records containing “fraud” :

SELECT * FROM table WHERE label like"% % fraud";Copy the code

Even if an index is created, such a like query will invalidate the index, making the query very inefficient!!

If the three labels are represented in hexadecimal:

const (
  GAMBLE = 0x0001
  SEX    = 0x0002
  FRAUD  = 0x0004
)
Copy the code

Then the SQL that results in “gambling” and “fraud” records will become:

SELECT * FROM table WHERE label = 0x0001|0x0004;
Copy the code

At this point, the Label field only needs to be compared to one value.

The SQL for querying records that contain “fraud” becomes:

SELECT * FROM table WHERE label & 0x0004 ! =0;
Copy the code

Direct bit operations are much more efficient than like string matching.

conclusion

  • In the face of multi-state processing, multi-label processing, might as well try hexadecimal notation.

  • Hexadecimal notation, the use of bit operation, high operation efficiency, storage space is low.