Blame itoa_ljust.c

Packit 4e8bc4
//=== itoa_ljust.cpp - Fast integer to ascii conversion           --*- C++ -*-//
Packit 4e8bc4
//
Packit 4e8bc4
// Substantially simplified (and slightly faster) version
Packit 4e8bc4
// based on the following functions in Google's protocol buffers:
Packit 4e8bc4
//
Packit 4e8bc4
//    FastInt32ToBufferLeft()
Packit 4e8bc4
//    FastUInt32ToBufferLeft()
Packit 4e8bc4
//    FastInt64ToBufferLeft()
Packit 4e8bc4
//    FastUInt64ToBufferLeft()
Packit 4e8bc4
//
Packit 4e8bc4
// Differences:
Packit 4e8bc4
//    1) Greatly simplified
Packit 4e8bc4
//    2) Avoids GOTO statements - uses "switch" instead and relies on
Packit 4e8bc4
//       compiler constant folding and propagation for high performance
Packit 4e8bc4
//    3) Avoids unary minus of signed types - undefined behavior if value
Packit 4e8bc4
//       is INT_MIN in platforms using two's complement representation
Packit 4e8bc4
//    4) Uses memcpy to store 2 digits at a time - lets the compiler
Packit 4e8bc4
//       generate a 2-byte load/store in platforms that support
Packit 4e8bc4
//       unaligned access, this is faster (and less code) than explicitly
Packit 4e8bc4
//       loading and storing each byte
Packit 4e8bc4
//
Packit 4e8bc4
// Copyright (c) 2016 Arturo Martin-de-Nicolas
Packit 4e8bc4
// arturomdn@gmail.com
Packit 4e8bc4
// https://github.com/amdn/itoa_ljust/
Packit 4e8bc4
//
Packit 4e8bc4
// Released under the BSD 3-Clause License, see Google's original copyright
Packit 4e8bc4
// and license below.
Packit 4e8bc4
//===----------------------------------------------------------------------===//
Packit 4e8bc4
Packit 4e8bc4
// Protocol Buffers - Google's data interchange format
Packit 4e8bc4
// Copyright 2008 Google Inc.  All rights reserved.
Packit 4e8bc4
// https://developers.google.com/protocol-buffers/
Packit 4e8bc4
//
Packit 4e8bc4
// Redistribution and use in source and binary forms, with or without
Packit 4e8bc4
// modification, are permitted provided that the following conditions are
Packit 4e8bc4
// met:
Packit 4e8bc4
//
Packit 4e8bc4
//     * Redistributions of source code must retain the above copyright
Packit 4e8bc4
// notice, this list of conditions and the following disclaimer.
Packit 4e8bc4
//     * Redistributions in binary form must reproduce the above
Packit 4e8bc4
// copyright notice, this list of conditions and the following disclaimer
Packit 4e8bc4
// in the documentation and/or other materials provided with the
Packit 4e8bc4
// distribution.
Packit 4e8bc4
//     * Neither the name of Google Inc. nor the names of its
Packit 4e8bc4
// contributors may be used to endorse or promote products derived from
Packit 4e8bc4
// this software without specific prior written permission.
Packit 4e8bc4
//
Packit 4e8bc4
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 4e8bc4
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 4e8bc4
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 4e8bc4
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 4e8bc4
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 4e8bc4
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 4e8bc4
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 4e8bc4
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 4e8bc4
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 4e8bc4
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 4e8bc4
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 4e8bc4
//===----------------------------------------------------------------------===//
Packit 4e8bc4
Packit 4e8bc4
#include "itoa_ljust.h"
Packit 4e8bc4
#include <string.h>
Packit 4e8bc4
Packit 4e8bc4
static const char lut[201] =
Packit 4e8bc4
    "0001020304050607080910111213141516171819"
Packit 4e8bc4
    "2021222324252627282930313233343536373839"
Packit 4e8bc4
    "4041424344454647484950515253545556575859"
Packit 4e8bc4
    "6061626364656667686970717273747576777879"
Packit 4e8bc4
    "8081828384858687888990919293949596979899";
Packit 4e8bc4
Packit 4e8bc4
#define dd(u) ((const uint16_t)(lut[u]))
Packit 4e8bc4
Packit 4e8bc4
static inline char* out2(const int d, char* p) {
Packit 4e8bc4
    memcpy(p, &((uint16_t *)lut)[d], 2);
Packit 4e8bc4
    return p + 2;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
static inline char* out1(const char in, char* p) {
Packit 4e8bc4
    memcpy(p, &in, 1);
Packit 4e8bc4
    return p + 1;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
static inline int digits( uint32_t u, unsigned k, int* d, char** p, int n ) {
Packit 4e8bc4
    if (u < k*10) {
Packit 4e8bc4
        *d = u / k;
Packit 4e8bc4
        *p = out1('0'+*d, *p);
Packit 4e8bc4
        --n;
Packit 4e8bc4
    }
Packit 4e8bc4
    return n;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
static inline char* itoa(uint32_t u, char* p, int d, int n) {
Packit 4e8bc4
    switch(n) {
Packit 4e8bc4
    case 10: d  = u / 100000000; p = out2( d, p );
Packit 4e8bc4
    case  9: u -= d * 100000000;
Packit 4e8bc4
    case  8: d  = u /   1000000; p = out2( d, p );
Packit 4e8bc4
    case  7: u -= d *   1000000;
Packit 4e8bc4
    case  6: d  = u /     10000; p = out2( d, p );
Packit 4e8bc4
    case  5: u -= d *     10000;
Packit 4e8bc4
    case  4: d  = u /       100; p = out2( d, p );
Packit 4e8bc4
    case  3: u -= d *       100;
Packit 4e8bc4
    case  2: d  = u /         1; p = out2( d, p );
Packit 4e8bc4
    case  1: ;
Packit 4e8bc4
    }
Packit 4e8bc4
    *p = '\0';
Packit 4e8bc4
    return p;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
char* itoa_u32(uint32_t u, char* p) {
Packit 4e8bc4
    int d = 0,n;
Packit 4e8bc4
         if (u >=100000000) n = digits(u, 100000000, &d, &p, 10);
Packit 4e8bc4
    else if (u <       100) n = digits(u,         1, &d, &p,  2);
Packit 4e8bc4
    else if (u <     10000) n = digits(u,       100, &d, &p,  4);
Packit 4e8bc4
    else if (u <   1000000) n = digits(u,     10000, &d, &p,  6);
Packit 4e8bc4
    else                    n = digits(u,   1000000, &d, &p,  8);
Packit 4e8bc4
    return itoa( u, p, d, n );
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
char* itoa_32(int32_t i, char* p) {
Packit 4e8bc4
    uint32_t u = i;
Packit 4e8bc4
    if (i < 0) {
Packit 4e8bc4
        *p++ = '-';
Packit 4e8bc4
        u = -u;
Packit 4e8bc4
    }
Packit 4e8bc4
    return itoa_u32(u, p);
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
char* itoa_u64(uint64_t u, char* p) {
Packit 4e8bc4
    int d;
Packit 4e8bc4
Packit 4e8bc4
    uint32_t lower = (uint32_t)u;
Packit 4e8bc4
    if (lower == u) return itoa_u32(lower, p);
Packit 4e8bc4
Packit 4e8bc4
    uint64_t upper = u / 1000000000;
Packit 4e8bc4
    p = itoa_u64(upper, p);
Packit 4e8bc4
    lower = u - (upper * 1000000000);
Packit 4e8bc4
    d = lower / 100000000;
Packit 4e8bc4
    p = out1('0'+d,p);
Packit 4e8bc4
    return itoa( lower, p, d, 9 );
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
char* itoa_64(int64_t i, char* p) {
Packit 4e8bc4
    uint64_t u = i;
Packit 4e8bc4
    if (i < 0) {
Packit 4e8bc4
        *p++ = '-';
Packit 4e8bc4
        u = -u;
Packit 4e8bc4
    }
Packit 4e8bc4
    return itoa_u64(u, p);
Packit 4e8bc4
}