From 39ef9b2a9ee20cfc47b179298ca966d551dc374e Mon Sep 17 00:00:00 2001 From: Hitalo Souza Date: Sun, 28 Dec 2025 16:55:35 +0000 Subject: [PATCH] time: implement faster and simpler `push_http_header` (#26155) --- vlib/builtin/js/array.js.v | 5 ++++ vlib/time/format.v | 55 +++++++++++++++++++++++++++--------- vlib/time/time_format_test.v | 7 +++++ 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/vlib/builtin/js/array.js.v b/vlib/builtin/js/array.js.v index ab91a4207..fd8a5ad42 100644 --- a/vlib/builtin/js/array.js.v +++ b/vlib/builtin/js/array.js.v @@ -414,6 +414,11 @@ pub fn (a array) to_number_array() JS.Array { return tmp } +// push_many - appends multiple values to the end of the array. +pub fn (mut a array) push_many(val voidptr, size int) { + a.insert_many(a.len, val, size) +} + type EveryFn = fn (JS.Number, JS.Number) JS.Boolean type BigEveryFn = fn (JS.BigInt, JS.Number) JS.Boolean diff --git a/vlib/time/format.v b/vlib/time/format.v index e6a4606f7..e94b1aee9 100644 --- a/vlib/time/format.v +++ b/vlib/time/format.v @@ -35,6 +35,28 @@ fn int_to_byte_array_no_pad(value int, mut arr []u8, size int) { } } +// int_to_byte_array_no_pad fulfill buffer by part +// it doesn't pad with leading zeros for performance reasons +@[direct_array_access; unsafe] +fn int_to_ptr_byte_array_no_pad(value int, arr_prt &u8, arr_len int) { + mut num := value + if arr_len <= 0 || num < 0 { + return + } + + // Start from the end of the array + mut i := arr_len - 1 + + // Convert each digit to a character and store it in the array + for num > 0 && i >= 0 { + unsafe { + *(arr_prt + i) = (num % 10) + `0` + } + num /= 10 + i-- + } +} + // format returns a date string in "YYYY-MM-DD HH:mm" format (24h). @[manualfree] pub fn (t Time) format() string { @@ -698,26 +720,31 @@ pub fn (t Time) utc_string() string { // e.g. "Sun, 06 Nov 1994 08:49:37 GMT" @[manualfree] pub fn (t Time) http_header_string() string { + mut buf := []u8{cap: 29} + t.push_to_http_header(mut buf) + + return buf.bytestr() +} + +// push_to_http_header returns a date string in the format used in HTTP headers, as defined in RFC 2616. +// e.g. "Sun, 06 Nov 1994 08:49:37 GMT" +pub fn (t Time) push_to_http_header(mut buffer []u8) { day_str := t.weekday_str() month_str := t.smonth() mut buf := [day_str[0], day_str[1], day_str[2], `,`, ` `, `0`, `0`, ` `, month_str[0], month_str[1], month_str[2], ` `, `0`, `0`, `0`, `0`, ` `, `0`, `0`, `:`, `0`, `0`, `:`, `0`, `0`, ` `, - `G`, `M`, `T`] - - defer { - unsafe { buf.free() } + `G`, `M`, `T`]! + unsafe { + int_to_ptr_byte_array_no_pad(t.day, &buf[5], 2) + int_to_ptr_byte_array_no_pad(t.year, &buf[12], 4) + int_to_ptr_byte_array_no_pad(t.hour, &buf[17], 2) + int_to_ptr_byte_array_no_pad(t.minute, &buf[20], 2) + int_to_ptr_byte_array_no_pad(t.second, &buf[23], 2) + } + unsafe { + buffer.push_many(&buf[0], buf.len) } - - int_to_byte_array_no_pad(t.day, mut buf, 7) - int_to_byte_array_no_pad(t.year, mut buf, 16) - int_to_byte_array_no_pad(t.hour, mut buf, 19) - int_to_byte_array_no_pad(t.minute, mut buf, 22) - int_to_byte_array_no_pad(t.second, mut buf, 25) - - http_header_string := buf.bytestr() - - return http_header_string } // mceil returns the least integer value greater than or equal to x. diff --git a/vlib/time/time_format_test.v b/vlib/time/time_format_test.v index f21be4061..97414bfb1 100644 --- a/vlib/time/time_format_test.v +++ b/vlib/time/time_format_test.v @@ -89,3 +89,10 @@ fn test_utc_string() { fn test_http_header_string() { assert 'Fri, 11 Jul 1980 21:23:42 GMT' == time_to_test.http_header_string() } + +fn test_push_to_http_header() { + mut http1_1_buffer := 'HTTP/1.1 200 OK\r\nDate: '.bytes() + time_to_test.push_to_http_header(mut http1_1_buffer) + + assert http1_1_buffer.bytestr() == 'HTTP/1.1 200 OK\r\nDate: Fri, 11 Jul 1980 21:23:42 GMT' +} -- 2.39.5