diff --git a/varfmt/README.md b/varfmt/README.md new file mode 100644 index 0000000..bbf38e0 --- /dev/null +++ b/varfmt/README.md @@ -0,0 +1,17 @@ +# varfmt + +Реализуйте функцию `varfmt.Sprintf`. Функция принимает формат строку и переменное число аргументов. + +Синтаксис формат-строки похож формат-строки питона: + - `{}` - задаёт ссылку на аргумент + - `{number}` - ссылается на агрумент с индексом `number` + - `{}` ссылается на аргумент с индексом равным позиции `{}` внутри паттерна + +Например, `varfmt.Sprintf("{1} {0}", "Hello", "World)` должен вернуть строку `Hello World`. + +Аргументы функции могут быть произвольными типами. Вам нужно форматировать их так же, как это +делает функция `fmt.Sprint`. Вызывать `fmt.Sprint` для форматирования отдельного аргумента +не запрещается. + +Ваше решение будет сравниваться с baseline-решением на бенчмарке. Ваш код должен +быть не более чем в два раза хуже чем baseline. \ No newline at end of file diff --git a/varfmt/fmt.go b/varfmt/fmt.go new file mode 100644 index 0000000..073224f --- /dev/null +++ b/varfmt/fmt.go @@ -0,0 +1,7 @@ +// +build !solution + +package varfmt + +func Sprintf(format string, args ...interface{}) string { + return "" +} diff --git a/varfmt/fmt_test.go b/varfmt/fmt_test.go new file mode 100644 index 0000000..fb137be --- /dev/null +++ b/varfmt/fmt_test.go @@ -0,0 +1,113 @@ +package varfmt + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFormat(t *testing.T) { + for _, tc := range []struct { + format string + args []interface{} + result string + }{ + { + format: "{}", + args: []interface{}{0}, + result: "0", + }, + { + format: "{0} {0}", + args: []interface{}{1}, + result: "1 1", + }, + { + format: "{1} {5}", + args: []interface{}{0, 1, 2, 3, 4, 5, 6}, + result: "1 5", + }, + { + format: "{} {} {} {} {}", + args: []interface{}{0, 1, 2, 3, 4}, + result: "0 1 2 3 4", + }, + { + format: "{} {0} {0} {0} {}", + args: []interface{}{0, 1, 2, 3, 4}, + result: "0 0 0 0 4", + }, + { + format: "Hello, {2}", + args: []interface{}{0, 1, "World"}, + result: "Hello, World", + }, + } { + t.Run(tc.result, func(t *testing.T) { + require.Equal(t, tc.result, Sprintf(tc.format, tc.args...)) + }) + } +} + +func BenchmarkFormat(b *testing.B) { + for _, tc := range []struct { + name string + format string + args []interface{} + }{ + { + name: "small int", + format: "{}", + args: []interface{}{42}, + }, + { + name: "small string", + format: "{} {}", + args: []interface{}{"Hello", "World"}, + }, + { + name: "big", + format: strings.Repeat("{0}{1}", 1000), + args: []interface{}{42, 43}, + }, + } { + b.Run(tc.name, func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _ = Sprintf(tc.format, tc.args...) + } + }) + } +} + +func BenchmarkSprintf(b *testing.B) { + for _, tc := range []struct { + name string + format string + args []interface{} + }{ + { + name: "small", + format: "%d", + args: []interface{}{42}, + }, + { + name: "small string", + format: "%v %v", + args: []interface{}{"Hello", "World"}, + }, { + name: "big", + format: strings.Repeat("%[0]v%[1]v", 1000), + args: []interface{}{42, 43}, + }, + } { + b.Run(tc.name, func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + _ = Sprintf(tc.format, tc.args...) + } + }) + } +}