Improve dump_integer performance by implementing a more efficient int2ascii
This commits implements a faster int2ascii inspired by "Fastware" talk given by Andrei Alexandrescu. See: https://www.youtube.com/watch?v=o4-CwDo2zpg
This commit is contained in:
		
							parent
							
								
									676c847c55
								
							
						
					
					
						commit
						6503e83e74
					
				
					 2 changed files with 190 additions and 30 deletions
				
			
		| 
						 | 
				
			
			@ -11410,6 +11410,40 @@ class serializer
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief count digits
 | 
			
		||||
 | 
			
		||||
    Count the number of decimal (base 10) digits for an input unsigned integer.
 | 
			
		||||
 | 
			
		||||
    @param[in] x  unsigned integer number to count its digits
 | 
			
		||||
    @return    number of decimal digits
 | 
			
		||||
    */
 | 
			
		||||
    inline unsigned int count_digits(number_unsigned_t x) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        unsigned int n_digits = 1;
 | 
			
		||||
        for (;;)
 | 
			
		||||
        {
 | 
			
		||||
            if (x < 10)
 | 
			
		||||
            {
 | 
			
		||||
                return n_digits;
 | 
			
		||||
            }
 | 
			
		||||
            if (x < 100)
 | 
			
		||||
            {
 | 
			
		||||
                return n_digits + 1;
 | 
			
		||||
            }
 | 
			
		||||
            if (x < 1000)
 | 
			
		||||
            {
 | 
			
		||||
                return n_digits + 2;
 | 
			
		||||
            }
 | 
			
		||||
            if (x < 10000)
 | 
			
		||||
            {
 | 
			
		||||
                return n_digits + 3;
 | 
			
		||||
            }
 | 
			
		||||
            x = x / 10000u;
 | 
			
		||||
            n_digits += 4;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief dump an integer
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11425,6 +11459,22 @@ class serializer
 | 
			
		|||
                 int> = 0>
 | 
			
		||||
    void dump_integer(NumberType x)
 | 
			
		||||
    {
 | 
			
		||||
        static constexpr std::array<std::array<char, 2>, 100> digits_to_99
 | 
			
		||||
        {
 | 
			
		||||
            {
 | 
			
		||||
                {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'},
 | 
			
		||||
                {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'},
 | 
			
		||||
                {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
 | 
			
		||||
                {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'},
 | 
			
		||||
                {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'},
 | 
			
		||||
                {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
 | 
			
		||||
                {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'},
 | 
			
		||||
                {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'},
 | 
			
		||||
                {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
 | 
			
		||||
                {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'},
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // special case for "0"
 | 
			
		||||
        if (x == 0)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -11432,28 +11482,58 @@ class serializer
 | 
			
		|||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not (x >= 0);  // see issue #755
 | 
			
		||||
        std::size_t i = 0;
 | 
			
		||||
        // use a pointer to fill the buffer
 | 
			
		||||
        auto buffer_ptr = begin(number_buffer);
 | 
			
		||||
 | 
			
		||||
        while (x != 0)
 | 
			
		||||
        {
 | 
			
		||||
            // spare 1 byte for '\0'
 | 
			
		||||
            assert(i < number_buffer.size() - 1);
 | 
			
		||||
        const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755
 | 
			
		||||
        number_unsigned_t abs_value;
 | 
			
		||||
 | 
			
		||||
            const auto digit = std::labs(static_cast<long>(x % 10));
 | 
			
		||||
            number_buffer[i++] = static_cast<char>('0' + digit);
 | 
			
		||||
            x /= 10;
 | 
			
		||||
        }
 | 
			
		||||
        unsigned int n_chars;
 | 
			
		||||
 | 
			
		||||
        if (is_negative)
 | 
			
		||||
        {
 | 
			
		||||
            // make sure there is capacity for the '-'
 | 
			
		||||
            assert(i < number_buffer.size() - 2);
 | 
			
		||||
            number_buffer[i++] = '-';
 | 
			
		||||
            *buffer_ptr = '-';
 | 
			
		||||
            abs_value = static_cast<number_unsigned_t>(0 - x);
 | 
			
		||||
 | 
			
		||||
            // account one more byte for the minus sign
 | 
			
		||||
            n_chars = 1 + count_digits(abs_value);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            abs_value = static_cast<number_unsigned_t>(x);
 | 
			
		||||
            n_chars = count_digits(abs_value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
 | 
			
		||||
        o->write_characters(number_buffer.data(), i);
 | 
			
		||||
        // spare 1 byte for '\0'
 | 
			
		||||
        assert(n_chars < number_buffer.size() - 1);
 | 
			
		||||
 | 
			
		||||
        // jump to the end to generate the string from backward
 | 
			
		||||
        // so we later avoid reversing the result
 | 
			
		||||
        buffer_ptr += n_chars;
 | 
			
		||||
 | 
			
		||||
        // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
 | 
			
		||||
        // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
 | 
			
		||||
        const auto buffer_end = buffer_ptr;
 | 
			
		||||
        while (abs_value >= 100)
 | 
			
		||||
        {
 | 
			
		||||
            const auto digits_index = static_cast<unsigned>((abs_value % 100));
 | 
			
		||||
            abs_value /= 100;
 | 
			
		||||
            *(--buffer_ptr) = digits_to_99[digits_index][1];
 | 
			
		||||
            *(--buffer_ptr) = digits_to_99[digits_index][0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (abs_value >= 10)
 | 
			
		||||
        {
 | 
			
		||||
            const auto digits_index = static_cast<unsigned>(abs_value);
 | 
			
		||||
            *(--buffer_ptr) = digits_to_99[digits_index][1];
 | 
			
		||||
            *(--buffer_ptr) = digits_to_99[digits_index][0];
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            *(--buffer_ptr) = static_cast<char>('0' + abs_value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        o->write_characters(number_buffer.data(), n_chars);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue