Skip to content

Commit 481a6e6

Browse files
committed
Hand-rolled itoa and test
1 parent 7c7f7a4 commit 481a6e6

File tree

4 files changed

+189
-22
lines changed

4 files changed

+189
-22
lines changed

bson/_cbsonmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer,
10361036
if (list_type_byte == -1) {
10371037
return 0;
10381038
}
1039-
int10_to_str((int)i, name);
1039+
itoa((long int)i, name);
10401040
if (!buffer_write_bytes(buffer, name, (int)strlen(name) + 1)) {
10411041
return 0;
10421042
}

bson/_cbsonmodule.h

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,50 @@
3030
#endif
3131

3232
/* Converts integer to its string representation in decimal notation. */
33-
static char *int10_to_str(long int val, char *dst)
34-
{
35-
char buffer[65];
36-
char *p;
37-
long int new_val;
38-
unsigned long int uval = (unsigned long int) val;
39-
40-
p = &buffer[sizeof(buffer)-1];
41-
*p = '\0';
42-
new_val= (long) (uval / 10);
43-
*--p = '0'+ (char) (uval - (unsigned long) new_val * 10);
44-
val = new_val;
45-
46-
while (val != 0)
47-
{
48-
new_val=val/10;
49-
*--p = '0' + (char) (val-new_val*10);
50-
val= new_val;
33+
static void itoa(long int num, char* str) {
34+
int index = 0;
35+
int sign = 1;
36+
// Convert to unsigned to handle -LLONG_MIN overflow
37+
unsigned long int absNum;
38+
39+
// Handle the case of 0
40+
if (num == 0) {
41+
str[index++] = '0';
42+
str[index] = '\0';
43+
return;
44+
}
45+
46+
// Handle negative numbers
47+
if (num < 0) {
48+
sign = -1;
49+
absNum = -num;
50+
} else {
51+
absNum = num;
52+
}
53+
54+
// Convert the number to string
55+
int digit;
56+
while (absNum > 0) {
57+
digit = absNum % 10;
58+
str[index++] = digit + '0'; // Convert digit to character
59+
absNum /= 10;
60+
}
61+
62+
// Add minus sign if negative
63+
if (sign == -1) {
64+
str[index++] = '-';
65+
}
66+
67+
str[index] = '\0'; // Null terminator
68+
69+
// Reverse the string
70+
int start = 0;
71+
int end = index - 1;
72+
while (start < end) {
73+
char temp = str[start];
74+
str[start++] = str[end];
75+
str[end--] = temp;
5176
}
52-
while ((*dst++ = *p++) != 0) ;
53-
return dst-1;
5477
}
5578

5679
typedef struct type_registry_t {

bson/test_int2str.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#include <stdio.h>
2+
#include <time.h>
3+
#include <assert.h>
4+
#include <string.h>
5+
#include <limits.h>
6+
7+
static void itoa(long int num, char* str) {
8+
int index = 0;
9+
int sign = 1;
10+
// Convert to unsigned to handle -LLONG_MIN overflow
11+
unsigned long int absNum;
12+
13+
// Handle the case of 0
14+
if (num == 0) {
15+
str[index++] = '0';
16+
str[index] = '\0';
17+
return;
18+
}
19+
20+
// Handle negative numbers
21+
if (num < 0) {
22+
sign = -1;
23+
absNum = -num;
24+
} else {
25+
absNum = num;
26+
}
27+
28+
// Convert the number to string
29+
int digit;
30+
while (absNum > 0) {
31+
digit = absNum % 10;
32+
str[index++] = digit + '0'; // Convert digit to character
33+
absNum /= 10;
34+
}
35+
36+
// Add minus sign if negative
37+
if (sign == -1) {
38+
str[index++] = '-';
39+
}
40+
41+
str[index] = '\0'; // Null terminator
42+
43+
// Reverse the string
44+
int start = 0;
45+
int end = index - 1;
46+
while (start < end) {
47+
char temp = str[start];
48+
str[start++] = str[end];
49+
str[end--] = temp;
50+
}
51+
}
52+
53+
static void int10_to_str(long int val, char *dst)
54+
{
55+
char buffer[20];
56+
char *p;
57+
long int new_val;
58+
unsigned long int uval = (unsigned long int) val;
59+
60+
if (val < 0)
61+
{
62+
*dst++ = '-';
63+
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
64+
uval = (unsigned long int)0 - uval;
65+
}
66+
67+
p = &buffer[sizeof(buffer)-1];
68+
*p = '\0';
69+
new_val= (long) (uval / 10);
70+
*--p = '0'+ (char) (uval - (unsigned long) new_val * 10);
71+
val = new_val;
72+
73+
while (val != 0)
74+
{
75+
new_val=val/10;
76+
*--p = '0' + (char) (val-new_val*10);
77+
val= new_val;
78+
}
79+
while ((*dst++ = *p++) != 0) ;
80+
return;
81+
}
82+
83+
static void INT2STRING(long int i, char* buffer) {
84+
// Macro had access to allocated array but this function
85+
// only has the pointer, so we hardcode buffer size
86+
snprintf(buffer, 21, "%ld", i);
87+
return;
88+
}
89+
90+
void test(void (*f)(long int val, char* str), char* name) {
91+
// Time common values
92+
int reps = 10000;
93+
float startTime, endTime;
94+
startTime = (float)clock()/CLOCKS_PER_SEC;
95+
for (int i = 0; i < reps; i++) {
96+
for (long num = 0; num < 10000; num++) {
97+
char str[20];
98+
f(num, str);
99+
}
100+
}
101+
endTime = (float)clock()/CLOCKS_PER_SEC;
102+
printf("%s: %f\n", name, endTime - startTime);
103+
}
104+
105+
int main() {
106+
// Test extreme values
107+
long int maxNum = (((size_t) - 1)>>1);
108+
long int minNum = -maxNum-1;
109+
char str_1[21];
110+
char str_2[21];
111+
char str_3[21];
112+
itoa(maxNum, str_1);
113+
int10_to_str(maxNum, str_2);
114+
INT2STRING(maxNum, str_3);
115+
assert(strcmp(str_1, str_2) == 0);
116+
assert(strcmp(str_1, str_3) == 0);
117+
memset(str_1,0,strlen(str_1));
118+
memset(str_2,0,strlen(str_2));
119+
memset(str_3,0,strlen(str_3));
120+
itoa(minNum, str_1);
121+
int10_to_str(minNum, str_2);
122+
INT2STRING(minNum, str_3);
123+
assert(strcmp(str_1, str_2) == 0);
124+
assert(strcmp(str_1, str_3) == 0);
125+
126+
// Test common values
127+
for (long num = 0; num < 10000; num++) {
128+
char str_1[21];
129+
char str_2[21];
130+
char str_3[21];
131+
itoa(num, str_1);
132+
int10_to_str(num, str_2);
133+
INT2STRING(num, str_3);
134+
assert(strcmp(str_1, str_2) == 0);
135+
assert(strcmp(str_1, str_3) == 0);
136+
}
137+
138+
// Time common values
139+
test(itoa, "itoa");
140+
test(int10_to_str, "int10_to_str");
141+
test(INT2STRING, "INT2STRING");
142+
143+
return 0;
144+
}

pymongo/_cmessagemodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ _batched_write_command(
762762
int cur_size;
763763
int enough_data = 0;
764764
char key[16];
765-
int10_to_str(idx, key);
765+
itoa(idx, key);
766766
if (!buffer_write_bytes(buffer, "\x03", 1) ||
767767
!buffer_write_bytes(buffer, key, (int)strlen(key) + 1)) {
768768
goto fail;

0 commit comments

Comments
 (0)