Skip to content

Commit 2f53e2d

Browse files
authored
x.encoding.asn1: improve performance (#22948)
1 parent f89cffa commit 2f53e2d

File tree

5 files changed

+43
-61
lines changed

5 files changed

+43
-61
lines changed

vlib/x/encoding/asn1/bench/bench.v

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import x.encoding.asn1
99
// type [1] EXPLICIT OBJECT IDENTIFIER
1010
// }
1111
// ```
12-
1312
struct Example {
1413
greeting asn1.Utf8String
1514
answer asn1.Integer
@@ -28,6 +27,7 @@ fn (ex Example) tag() asn1.Tag {
2827
fn (ex Example) payload() ![]u8 {
2928
kd := asn1.KeyDefault(map[string]asn1.Element{})
3029
payload := asn1.make_payload[Example](ex, kd)!
30+
3131
return payload
3232
}
3333

@@ -69,7 +69,7 @@ fn main() {
6969
ex := Example{
7070
greeting: asn1.Utf8String.new('Hello')!
7171
answer: asn1.Integer.from_int(42)
72-
tipe: asn1.ObjectIdentifier.new('1.3.6.1.3')!
72+
tipe: asn1.ObjectIdentifier.from_ints([1, 3, 6, 1, 3])!
7373
}
7474
iterations := 1000
7575

@@ -84,7 +84,7 @@ fn main() {
8484
avg_enc_time := total_enc_time / iterations
8585
println('Average example encode time: ${avg_enc_time} µs')
8686

87-
println('Benchmarking ASN.1 decode (with asn.decode)...')
87+
println('Benchmarking ASN.1 decode (with asn1.decode)...')
8888
mut total_dec_time := i64(0)
8989
for _ in 0 .. iterations {
9090
sw := time.new_stopwatch()

vlib/x/encoding/asn1/common.v

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ fn parse_universal(tag Tag, content []u8) !Element {
3333
}
3434

3535
fn parse_universal_primitive(tag Tag, content []u8) !Element {
36-
if tag.class != .universal {
37-
return error('parse on non-universal type')
38-
}
3936
if tag.constructed {
4037
return error('parse on constructed type')
4138
}
@@ -93,10 +90,7 @@ fn parse_universal_primitive(tag Tag, content []u8) !Element {
9390
}
9491

9592
fn parse_universal_constructed(tag Tag, content []u8) !Element {
96-
if tag.tag_class() != .universal {
97-
return error('parse on non-universal class')
98-
}
99-
if !tag.is_constructed() {
93+
if !tag.constructed {
10094
return error('parse on non-constructed type')
10195
}
10296
match tag.tag_number() {

vlib/x/encoding/asn1/element_decode.v

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ module asn1
1919
// decoded_obj := asn1.decode(bytes_data)!
2020
// assert decoded_obj.equal(original_obj)
2121
// ```
22-
pub fn decode(src []u8) !Element {
23-
return decode_with_options(src, '')
22+
pub fn decode(bytes []u8) !Element {
23+
// call Element.decode_with_rule directly
24+
el, pos := Element.decode_with_rule(bytes, 0, .der)!
25+
if pos > bytes.len {
26+
return error('decode on data with trailing data')
27+
}
28+
return el
2429
}
2530

2631
// decode_with_options decodes single element from bytes with options support, its not allowing trailing data.
@@ -49,8 +54,9 @@ pub fn decode(src []u8) !Element {
4954
// dump(obj_3) // output: obj_3: asn1.Element(Utf8String: (hi))
5055
// ```
5156
pub fn decode_with_options(bytes []u8, opt string) !Element {
57+
// if null-option length, call Element.decode_with_rule directly
5258
if opt.len == 0 {
53-
el, pos := Element.decode(bytes)!
59+
el, pos := Element.decode_with_rule(bytes, 0, .der)!
5460
if pos > bytes.len {
5561
return error('decode on data with trailing data')
5662
}
@@ -136,7 +142,7 @@ pub fn (el Element) unwrap_with_field_options(fo FieldOptions) !Element {
136142
if el.tag().class == .universal {
137143
return error('you cant unwrap universal element')
138144
}
139-
// its also happens to fo.cls, should not universal class
145+
// its also happens to fo.cls, should not be an universal class
140146
if fo.cls == 'universal' {
141147
return error('you cant unwrap universal element')
142148
}
@@ -170,9 +176,8 @@ pub fn (el Element) unwrap_with_field_options(fo FieldOptions) !Element {
170176
return error('Element tag unequal with tag from options')
171177
}
172178

173-
inner_el := unwrap(el, mode, inner_tag)!
174-
175-
return inner_el
179+
// return unwrapped element
180+
return unwrap(el, mode, inner_tag)!
176181
}
177182

178183
// unwrap the provided element, turn into inner element.

vlib/x/encoding/asn1/element_encode.v

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,16 @@ pub fn encode_with_options(el Element, opt string) ![]u8 {
4444

4545
// `encode_with_field_options` serializes this element into bytes array with options defined in fo.
4646
pub fn encode_with_field_options(el Element, fo FieldOptions) ![]u8 {
47-
return el.encode_with_field_options(fo)
47+
return el.encode_with_field_options(fo)!
4848
}
4949

5050
fn (el Element) encode_with_options(opt string) ![]u8 {
5151
// treated as without option when nil
5252
if opt.len == 0 {
53-
out := encode_with_rule(el, .der)!
54-
return out
53+
return encode_with_rule(el, .der)!
5554
}
5655
fo := FieldOptions.from_string(opt)!
57-
out := el.encode_with_field_options(fo)!
58-
return out
56+
return el.encode_with_field_options(fo)!
5957
}
6058

6159
// encode_with_field_options serializes element into bytes arrays with supplied FieldOptions.
@@ -121,8 +119,7 @@ fn (el Element) into_optional(with_present bool) !Element {
121119
if el is Optional {
122120
return error('already optional element')
123121
}
124-
opt := Optional.new(el, with_present)!
125-
return opt
122+
return Optional.new(el, with_present)!
126123
}
127124

128125
// apply_field_options applies rules in field options into current element

vlib/x/encoding/asn1/field_options.v

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ pub fn FieldOptions.from_string(s string) !FieldOptions {
7676
}
7777
attrs := trimmed.split(';')
7878
opt := FieldOptions.from_attrs(attrs)!
79-
// checks
80-
opt.check_wrapper()!
79+
// no need to check, from_attrs already called it internally.
80+
// opt.check_wrapper()!
8181

8282
return opt
8383
}
@@ -113,8 +113,8 @@ pub fn FieldOptions.from_attrs(attrs []string) !FieldOptions {
113113
return error('max allowed filtered.len')
114114
}
115115

116-
for attr in filtered {
117-
item := attr.trim_space()
116+
// The item has space-trimmed
117+
for item in filtered {
118118
if !is_tag_marker(item) && !is_optional_marker(item) && !is_default_marker(item)
119119
&& !is_mode_marker(item) && !is_inner_tag_marker(item) {
120120
return error('unsupported keyword')
@@ -274,13 +274,13 @@ fn (fo FieldOptions) check_wrapper() ! {
274274
if fo.inner == '' {
275275
return error('You provides incorrect inner number')
276276
}
277-
inner := fo.inner.trim_space()
278-
if !valid_inner_universal_form(inner) && !valid_extended_inner_form(inner) {
277+
// inner := fo.inner.trim_space()
278+
if !valid_inner_universal_form(fo.inner) && !valid_extended_inner_form(fo.inner) {
279279
return error('invalid inner value format')
280280
}
281281
if valid_inner_universal_form(fo.inner) {
282-
val := fo.inner.trim_space()
283-
num := val.int()
282+
// val := fo.inner.trim_space()
283+
num := fo.inner.int()
284284
if num > max_universal_tagnumber {
285285
return error('Inner number exceed universal limit')
286286
}
@@ -355,8 +355,7 @@ fn valid_mode_value(s string) bool {
355355
// support two format:
356356
// - unviersal inner format in the form `inner:number`, where number is universal class number.
357357
// - extended inner format in the form 'inner:class,form,number' for more broad support of the inner class.
358-
fn parse_inner_tag_marker(attr string) !(string, string) {
359-
src := attr.trim_space()
358+
fn parse_inner_tag_marker(src string) !(string, string) {
360359
if is_inner_tag_marker(src) {
361360
item := src.split(':')
362361
if item.len != 2 {
@@ -414,46 +413,37 @@ fn valid_inner_tag_key(s string) bool {
414413
return s == 'inner'
415414
}
416415

417-
fn valid_inner_universal_form(s string) bool {
416+
fn valid_inner_universal_form(value string) bool {
418417
// 'inner: number' part
419-
value := s.trim_space()
420418
return valid_string_tag_number(value)
421419
}
422420

423-
fn valid_extended_inner_form(s string) bool {
424-
// 'inner:class,form,number' part
425-
value := s.trim_space()
426-
// comma separated value.
421+
fn valid_extended_inner_form(value string) bool {
422+
// 'inner:class,form,number' part in comma separated value.
427423
items := value.split(',')
428424
if items.len != 3 {
429425
return false
430426
}
431-
cls := items[0].trim_space()
432-
if !is_extended_inner_cls_marker(cls) {
427+
if !is_extended_inner_cls_marker(items[0].trim_space()) {
433428
return false
434429
}
435-
if !valid_extended_inner_cls_marker(cls) {
430+
if !valid_extended_inner_cls_marker(items[0].trim_space()) {
436431
return false
437432
}
438433
// second form should be 'true' or 'false'
439-
form := items[1].trim_space()
440-
if !valid_extended_inner_form_marker(form) {
434+
if !valid_extended_inner_form_marker(items[1].trim_space()) {
441435
return false
442436
}
443-
444437
// third item should be a number
445-
third := items[2].trim_space()
446-
if !valid_extended_inner_number_marker(third) {
438+
if !valid_extended_inner_number_marker(items[2].trim_space()) {
447439
return false
448440
}
449441
return true
450442
}
451443

452444
fn parse_inner_extended_form(s string) !(string, string, string) {
453-
// 'inner:class,form,number' part
454-
value := s.trim_space()
455-
// comma separated value.
456-
items := value.split(',')
445+
// 'inner:class,form,number' part in comma separated value.
446+
items := s.split(',')
457447
if items.len != 3 {
458448
return error('invalid extended form length')
459449
}
@@ -469,7 +459,6 @@ fn parse_inner_extended_form(s string) !(string, string, string) {
469459
if !valid_extended_inner_form_marker(form) {
470460
return error('Your ext inner form is invalid')
471461
}
472-
473462
// third item should be a number
474463
third := items[2].trim_space()
475464
if !valid_extended_inner_number_marker(third) {
@@ -487,13 +476,11 @@ fn valid_extended_inner_cls_marker(attr string) bool {
487476
return valid_tagclass_name(attr) || attr == 'universal'
488477
}
489478

490-
fn valid_extended_inner_form_marker(attr string) bool {
491-
s := attr.trim_space()
479+
fn valid_extended_inner_form_marker(s string) bool {
492480
return s == 'true' || s == 'false'
493481
}
494482

495-
fn valid_extended_inner_number_marker(attr string) bool {
496-
s := attr.trim_space()
483+
fn valid_extended_inner_number_marker(s string) bool {
497484
return valid_string_tag_number(s)
498485
}
499486

@@ -503,8 +490,7 @@ fn valid_extended_inner_number_marker(attr string) bool {
503490
// - the only optional key 'optional' marker, and
504491
// - extended bit of presence of optional, 'optional:present'
505492
fn parse_optional_marker(attr string) !(string, string) {
506-
opt := attr.trim_space()
507-
values := opt.split(':')
493+
values := attr.split(':')
508494
if values.len != 1 && values.len != 2 {
509495
return error('Bad optional length')
510496
}
@@ -576,8 +562,8 @@ fn valid_default_marker(attr string) bool {
576562
// UTILTIY
577563
//
578564
// is_asn1_options_marker checks if provided string is valid supported field options string.
579-
fn is_asn1_options_marker(s string) bool {
580-
item := s.trim_space()
565+
fn is_asn1_options_marker(item string) bool {
566+
// item := s.trim_space()
581567
// belowng to one of five supported marker.
582568
valid := is_tag_marker(item) || is_mode_marker(item) || is_inner_tag_marker(item)
583569
|| is_optional_marker(item) || is_default_marker(item)

0 commit comments

Comments
 (0)