v2 / vlib / v / util / surrounder.v
138 lines · 128 sloc · 3.48 KB · c51d30bf5309653c6b573ec815268e69a78ea8cc
Raw
1module util
2
3import strings
4
5// Surrounder is an utility to help you manage a stack of additions, that
6// should be done *both* _before_ and _after_ a given piece of generated
7// code, in a synchronised way. It does so by forcing you to put the
8// creation/destruction samples next to each other, so that it is easier to
9// keep them in sync and spot errors.
10// Note: Surrounder writes the creation samples (`befores`) in the _same_ order
11// they were added, and the destruction samples (`afters`) in _reverse_ order.
12//
13// Usage:
14// ```v
15// mut sr := new_surrounder(2) // just a rough initial guess; it can grow
16// sr.add('string tmp1 = ...;', 'string_free(&tmp1);')
17// sr.add('string tmp2 = ...;', 'string_free(&tmp2);')
18// ..
19// sr.builder_write_befores(mut some_string_builder)
20// some_string_builder.writeln('MIDDLE_that_uses_tmp1_and_tmp2')
21// sr.builder_write_afters(mut some_string_builder)
22// ```
23// ... will produce this in `some_string_builder`:
24// ```
25// string tmp1 = ...;
26// string tmp2 = ...;
27// MIDDLE_that_uses_tmp1_and_tmp2
28// string_free(&tmp2);
29// string_free(&tmp1);
30// ```
31
32@[noinit]
33pub struct Surrounder {
34mut:
35 befores []string
36 afters []string
37}
38
39// new_surrounder creates a new Surrounder instance.
40// The expected_length is a hint for the initial capacity for the
41// befores/afters stacks.
42pub fn new_surrounder(expected_length int) Surrounder {
43 return Surrounder{
44 befores: []string{cap: expected_length}
45 afters: []string{cap: expected_length}
46 }
47}
48
49// add appends a `before`/`after` pair to the surrounder
50// When you call .after() or .builder_write_afters(),
51// all `before` parts will be in order, while all `after`
52// parts, will be in reverse order.
53pub fn (mut s Surrounder) add(before string, after string) {
54 s.befores << before
55 s.afters << after
56}
57
58// before returns all the `before` parts that were accumulated so far
59@[manualfree]
60pub fn (s &Surrounder) before() string {
61 len := s.befores.len
62 if len > 0 {
63 mut res := strings.new_builder(len * 100)
64 defer {
65 unsafe { res.free() }
66 }
67 for i := 0; i < len; i++ {
68 x := s.befores[i]
69 if x.len > 0 {
70 res.writeln(x)
71 }
72 }
73 ret := res.str()
74 return ret
75 }
76 return ''
77}
78
79// after returns all the `after` parts that were accumulated so far,
80// in reverse order of their addition.
81@[manualfree]
82pub fn (s &Surrounder) after() string {
83 len := s.afters.len
84 if len > 0 {
85 mut res := strings.new_builder(len * 100)
86 defer {
87 unsafe { res.free() }
88 }
89 for i := len - 1; i >= 0; i-- {
90 x := s.afters[i]
91 if x.len > 0 {
92 res.writeln(x)
93 }
94 }
95 ret := res.str()
96 return ret
97 }
98 return ''
99}
100
101// builder_write_befores writeln-es all the `before` parts into the given
102// string builder `sb`.
103pub fn (s &Surrounder) builder_write_befores(mut sb strings.Builder) {
104 len := s.befores.len
105 if len > 0 {
106 for i := 0; i < len; i++ {
107 x := s.befores[i]
108 if x.len > 0 {
109 sb.writeln(x)
110 }
111 }
112 }
113}
114
115// builder_write_afters writeln-es all the `after` parts into the given
116// string builder `sb`. They will be written there in reverse order, compared
117// to how/when they were added.
118pub fn (s &Surrounder) builder_write_afters(mut sb strings.Builder) {
119 len := s.afters.len
120 if len > 0 {
121 for i := len - 1; i >= 0; i-- {
122 x := s.afters[i]
123 if x.len > 0 {
124 sb.writeln(x)
125 }
126 }
127 }
128}
129
130// free frees the private resources associated with the surrounder instance
131// Called automatically by `-autofree`, or in `@[manualfree]` tagged functions.
132@[unsafe]
133pub fn (mut s Surrounder) free() {
134 unsafe {
135 s.befores.free()
136 s.afters.free()
137 }
138}
139