1
- /* stringlib: locale related helpers implementation */
2
-
3
- #include <locale.h>
4
-
5
- #if !STRINGLIB_IS_UNICODE
6
- # error "localeutil.h is specific to Unicode"
7
- #endif
1
+ /* _PyUnicode_InsertThousandsGrouping() helper functions */
8
2
9
3
typedef struct {
10
4
const char * grouping ;
11
5
char previous ;
12
6
Py_ssize_t i ; /* Where we're currently pointing in grouping. */
13
- } STRINGLIB (GroupGenerator );
7
+ } GroupGenerator ;
8
+
14
9
15
10
static void
16
- STRINGLIB ( GroupGenerator_init )( STRINGLIB ( GroupGenerator ) * self , const char * grouping )
11
+ GroupGenerator_init ( GroupGenerator * self , const char * grouping )
17
12
{
18
13
self -> grouping = grouping ;
19
14
self -> i = 0 ;
20
15
self -> previous = 0 ;
21
16
}
22
17
18
+
23
19
/* Returns the next grouping, or 0 to signify end. */
24
20
static Py_ssize_t
25
- STRINGLIB ( GroupGenerator_next )( STRINGLIB ( GroupGenerator ) * self )
21
+ GroupGenerator_next ( GroupGenerator * self )
26
22
{
27
23
/* Note that we don't really do much error checking here. If a
28
24
grouping string contains just CHAR_MAX, for example, then just
@@ -43,138 +39,44 @@ STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
43
39
}
44
40
}
45
41
42
+
46
43
/* Fill in some digits, leading zeros, and thousands separator. All
47
44
are optional, depending on when we're called. */
48
45
static void
49
- STRINGLIB (fill )(STRINGLIB_CHAR * * digits_end , STRINGLIB_CHAR * * buffer_end ,
50
- Py_ssize_t n_chars , Py_ssize_t n_zeros , STRINGLIB_CHAR * thousands_sep ,
51
- Py_ssize_t thousands_sep_len )
46
+ InsertThousandsGrouping_fill (_PyUnicodeWriter * writer , Py_ssize_t * buffer_pos ,
47
+ PyObject * digits , Py_ssize_t * digits_pos ,
48
+ Py_ssize_t n_chars , Py_ssize_t n_zeros ,
49
+ PyObject * thousands_sep , Py_ssize_t thousands_sep_len ,
50
+ Py_UCS4 * maxchar )
52
51
{
53
- Py_ssize_t i ;
52
+ if (!writer ) {
53
+ /* if maxchar > 127, maxchar is already set */
54
+ if (* maxchar == 127 && thousands_sep ) {
55
+ Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE (thousands_sep );
56
+ * maxchar = Py_MAX (* maxchar , maxchar2 );
57
+ }
58
+ return ;
59
+ }
54
60
55
61
if (thousands_sep ) {
56
- * buffer_end -= thousands_sep_len ;
62
+ * buffer_pos -= thousands_sep_len ;
57
63
58
64
/* Copy the thousands_sep chars into the buffer. */
59
- memcpy (* buffer_end , thousands_sep ,
60
- thousands_sep_len * STRINGLIB_SIZEOF_CHAR );
61
- }
62
-
63
- * buffer_end -= n_chars ;
64
- * digits_end -= n_chars ;
65
- memcpy (* buffer_end , * digits_end , n_chars * sizeof (STRINGLIB_CHAR ));
66
-
67
- * buffer_end -= n_zeros ;
68
- for (i = 0 ; i < n_zeros ; i ++ )
69
- (* buffer_end )[i ] = '0' ;
70
- }
71
-
72
- /**
73
- * InsertThousandsGrouping:
74
- * @buffer: A pointer to the start of a string.
75
- * @n_buffer: Number of characters in @buffer.
76
- * @digits: A pointer to the digits we're reading from. If count
77
- * is non-NULL, this is unused.
78
- * @n_digits: The number of digits in the string, in which we want
79
- * to put the grouping chars.
80
- * @min_width: The minimum width of the digits in the output string.
81
- * Output will be zero-padded on the left to fill.
82
- * @grouping: see definition in localeconv().
83
- * @thousands_sep: see definition in localeconv().
84
- *
85
- * There are 2 modes: counting and filling. If @buffer is NULL,
86
- * we are in counting mode, else filling mode.
87
- * If counting, the required buffer size is returned.
88
- * If filling, we know the buffer will be large enough, so we don't
89
- * need to pass in the buffer size.
90
- * Inserts thousand grouping characters (as defined by grouping and
91
- * thousands_sep) into the string between buffer and buffer+n_digits.
92
- *
93
- * Return value: 0 on error, else 1. Note that no error can occur if
94
- * count is non-NULL.
95
- *
96
- * This name won't be used, the includer of this file should define
97
- * it to be the actual function name, based on unicode or string.
98
- *
99
- * As closely as possible, this code mimics the logic in decimal.py's
100
- _insert_thousands_sep().
101
- **/
102
- static Py_ssize_t
103
- STRINGLIB (InsertThousandsGrouping )(
104
- STRINGLIB_CHAR * buffer ,
105
- Py_ssize_t n_buffer ,
106
- STRINGLIB_CHAR * digits ,
107
- Py_ssize_t n_digits ,
108
- Py_ssize_t min_width ,
109
- const char * grouping ,
110
- STRINGLIB_CHAR * thousands_sep ,
111
- Py_ssize_t thousands_sep_len )
112
- {
113
- Py_ssize_t count = 0 ;
114
- Py_ssize_t n_zeros ;
115
- int loop_broken = 0 ;
116
- int use_separator = 0 ; /* First time through, don't append the
117
- separator. They only go between
118
- groups. */
119
- STRINGLIB_CHAR * buffer_end = NULL ;
120
- STRINGLIB_CHAR * digits_end = NULL ;
121
- Py_ssize_t l ;
122
- Py_ssize_t n_chars ;
123
- Py_ssize_t remaining = n_digits ; /* Number of chars remaining to
124
- be looked at */
125
- /* A generator that returns all of the grouping widths, until it
126
- returns 0. */
127
- STRINGLIB (GroupGenerator ) groupgen ;
128
- STRINGLIB (GroupGenerator_init )(& groupgen , grouping );
129
-
130
- if (buffer ) {
131
- buffer_end = buffer + n_buffer ;
132
- digits_end = digits + n_digits ;
133
- }
134
-
135
- while ((l = STRINGLIB (GroupGenerator_next )(& groupgen )) > 0 ) {
136
- l = Py_MIN (l , Py_MAX (Py_MAX (remaining , min_width ), 1 ));
137
- n_zeros = Py_MAX (0 , l - remaining );
138
- n_chars = Py_MAX (0 , Py_MIN (remaining , l ));
139
-
140
- /* Use n_zero zero's and n_chars chars */
141
-
142
- /* Count only, don't do anything. */
143
- count += (use_separator ? thousands_sep_len : 0 ) + n_zeros + n_chars ;
144
-
145
- if (buffer ) {
146
- /* Copy into the output buffer. */
147
- STRINGLIB (fill )(& digits_end , & buffer_end , n_chars , n_zeros ,
148
- use_separator ? thousands_sep : NULL , thousands_sep_len );
149
- }
150
-
151
- /* Use a separator next time. */
152
- use_separator = 1 ;
153
-
154
- remaining -= n_chars ;
155
- min_width -= l ;
156
-
157
- if (remaining <= 0 && min_width <= 0 ) {
158
- loop_broken = 1 ;
159
- break ;
160
- }
161
- min_width -= thousands_sep_len ;
65
+ _PyUnicode_FastCopyCharacters (writer -> buffer , * buffer_pos ,
66
+ thousands_sep , 0 ,
67
+ thousands_sep_len );
162
68
}
163
- if (!loop_broken ) {
164
- /* We left the loop without using a break statement. */
165
69
166
- l = Py_MAX ( Py_MAX ( remaining , min_width ), 1 ) ;
167
- n_zeros = Py_MAX ( 0 , l - remaining ) ;
168
- n_chars = Py_MAX ( 0 , Py_MIN ( remaining , l ));
169
-
170
- /* Use n_zero zero's and n_chars chars */
171
- count += ( use_separator ? thousands_sep_len : 0 ) + n_zeros + n_chars ;
172
- if (buffer ) {
173
- /* Copy into the output buffer. */
174
- STRINGLIB ( fill )( & digits_end , & buffer_end , n_chars , n_zeros ,
175
- use_separator ? thousands_sep : NULL , thousands_sep_len );
176
- }
70
+ * buffer_pos -= n_chars ;
71
+ * digits_pos -= n_chars ;
72
+ _PyUnicode_FastCopyCharacters ( writer -> buffer , * buffer_pos ,
73
+ digits , * digits_pos ,
74
+ n_chars );
75
+
76
+ if (n_zeros ) {
77
+ * buffer_pos -= n_zeros ;
78
+ enum PyUnicode_Kind kind = PyUnicode_KIND ( writer -> buffer );
79
+ void * data = PyUnicode_DATA ( writer -> buffer );
80
+ FILL ( kind , data , '0' , * buffer_pos , n_zeros );
177
81
}
178
- return count ;
179
82
}
180
-
0 commit comments