Skip to content

Commit 738d934

Browse files
committed
Merge branch 'master' of https://github.com/get200/v
2 parents bb610bb + d1d43ab commit 738d934

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2608
-2003
lines changed

.github/workflows/v_apps_and_modules_compile_ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ jobs:
4646
v retry brew install sassc libgit2
4747
fi
4848
49+
- name: Build docs generator
50+
run: |
51+
v retry -- v install markdown
52+
v retry -- git clone https://github.com/vlang/docs --branch generator --depth 1
53+
cd docs
54+
v .
55+
4956
- name: Test vtcc
5057
if: runner.os == 'Linux'
5158
run: .github/workflows/compile_v_with_vtcc.sh
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env -S v -raw-vsh-tmp-prefix tmp
2+
3+
module main
4+
5+
import os
6+
import log
7+
8+
fn write_chunk(n int, min_size int, original string, start int, end int) {
9+
size := end - start
10+
if size < min_size {
11+
return
12+
}
13+
frame_file := 'frame_${n:06}.bin'
14+
log.warn('writing ${frame_file}, from start: ${start:9}, to end: ${end:9} | size: ${size:9} >= ${min_size:9}, memuse: ${gc_memory_use()}')
15+
os.write_file(frame_file, original#[start..end]) or { log.error(err.str()) }
16+
}
17+
18+
fn main() {
19+
log.info('Start.')
20+
fpath := os.args[2] or { 'memdump.bin' }
21+
separator := os.args[3] or { '@@ gg_memory_trace_frame' }
22+
min_size := os.args[1] or { '${separator.len}' }.int()
23+
log.info('Splitting chunk min_size (arg 1): ${min_size}, file (arg 2): ${fpath}, by string separator (arg 3): `${separator}` ...')
24+
log.info('Memory use before reading: ${gc_memory_use()}')
25+
original := os.read_file(fpath)!
26+
log.info('file size: ${original.len}')
27+
log.info('Memory use after reading: ${gc_memory_use()}')
28+
mut n := 0
29+
for start := 0; start < original.len; {
30+
gc_collect()
31+
idx := original.index_after_(separator, start + separator.len) // ensure that we advance each time
32+
if idx < 0 {
33+
write_chunk(n, min_size, original, start, original.len)
34+
break
35+
}
36+
write_chunk(n, min_size, original, start, idx)
37+
start = idx
38+
n++
39+
}
40+
log.info('Memory use after processing: ${gc_memory_use()}')
41+
log.info('Done.')
42+
}

doc/docs.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ by using any of the following commands in a terminal:
120120
* [Mutable arguments](#mutable-arguments)
121121
* [Variable number of arguments](#variable-number-of-arguments)
122122
* [Anonymous & higher-order functions](#anonymous--higher-order-functions)
123+
* [Lambda expressions](#lambda-expressions)
123124
* [Closures](#closures)
124125
* [Parameter evaluation order](#parameter-evaluation-order)
125126
* [References](#references)
@@ -3021,6 +3022,28 @@ fn main() {
30213022
}
30223023
```
30233024

3025+
### Lambda expressions
3026+
3027+
Lambda expressions in V are small anonymous functions, defined using
3028+
the `|variables| expression` syntax. Note: this syntax is valid only inside calls to higher
3029+
order functions.
3030+
3031+
Here are some examples:
3032+
```v
3033+
mut a := [1, 2, 3]
3034+
a.sort(|x, y| x > y) // sorts the array, defining the comparator with a lambda expression
3035+
println(a.map(|x| x * 10)) // prints [30, 20, 10]
3036+
```
3037+
3038+
```v
3039+
// Lambda function can be used as callback
3040+
fn f(cb fn (a int) int) int {
3041+
return cb(10)
3042+
}
3043+
3044+
println(f(|x| x + 4)) // prints 14
3045+
```
3046+
30243047
### Closures
30253048

30263049
V supports closures too.
@@ -8331,4 +8354,4 @@ This is the place to be, to discuss the V language, learn about latest
83318354
developments, quickly get help with issues, witness/participate in
83328355
~~epic flame wars~~ constructive criticism exchanges and design decisions.
83338356
Join it, and learn more about languages, games, editors, people, Klingons,
8334-
Conway's law and the universe.
8357+
Conway's law and the universe.

examples/database/mysql.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ fn main() {
1313
for row in res.rows() {
1414
println(row.vals.join(', '))
1515
}
16-
conn.close()
16+
conn.close()!
1717
}

examples/database/mysql_pool.v

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// vtest build: !(macos || windows)
2+
import db.mysql
3+
import pool
4+
import time
5+
6+
// Define your connection factory function
7+
fn create_conn() !&pool.ConnectionPoolable {
8+
config := mysql.Config{
9+
host: '127.0.0.1'
10+
port: 3306
11+
username: 'root'
12+
password: '12345678'
13+
dbname: 'mysql'
14+
}
15+
db := mysql.connect(config)!
16+
return &db
17+
}
18+
19+
fn main() {
20+
// Configure pool parameters
21+
config := pool.ConnectionPoolConfig{
22+
max_conns: 50
23+
min_idle_conns: 5
24+
max_lifetime: 2 * time.hour
25+
idle_timeout: 30 * time.minute
26+
get_timeout: 5 * time.second
27+
}
28+
29+
// Create connection pool
30+
mut my_pool := pool.new_connection_pool(create_conn, config)!
31+
defer {
32+
// When application exits
33+
my_pool.close()
34+
}
35+
36+
// Acquire connection
37+
mut conn := my_pool.get()!
38+
defer {
39+
// Return connection to pool
40+
my_pool.put(conn) or { println(err) }
41+
}
42+
43+
// Convert `conn` to a `mysql.DB` object
44+
mut db := conn as mysql.DB
45+
46+
assert db.validate()!
47+
48+
mut response := db.exec('drop table if exists users')!
49+
assert response == []mysql.Row{}
50+
51+
response = db.exec('create table if not exists users (
52+
id INT PRIMARY KEY AUTO_INCREMENT,
53+
username TEXT,
54+
last_name TEXT NULL DEFAULT NULL
55+
)')!
56+
assert response == []mysql.Row{}
57+
58+
mut result_code := db.exec_none('insert into users (username) values ("jackson")')
59+
assert result_code == 0
60+
result_code = db.exec_none('insert into users (username) values ("shannon")')
61+
assert result_code == 0
62+
result_code = db.exec_none('insert into users (username) values ("bailey")')
63+
assert result_code == 0
64+
result_code = db.exec_none('insert into users (username) values ("blaze")')
65+
assert result_code == 0
66+
rows := db.exec_param('insert into users (username) values (?)', 'Hi')!
67+
assert rows == []mysql.Row{}
68+
69+
// Regression testing to ensure the query and exec return the same values
70+
res := db.query('select * from users')!
71+
response = res.rows()
72+
assert response[0].vals[1] == 'jackson'
73+
response = db.exec('select * from users')!
74+
assert response[0].vals[1] == 'jackson'
75+
76+
response = db.exec('select * from users where id = 400')!
77+
assert response.len == 0
78+
79+
single_row := db.exec_one('select * from users')!
80+
assert single_row.vals[1] == 'jackson'
81+
82+
response = db.exec_param_many('select * from users where username = ?', [
83+
'jackson',
84+
])!
85+
assert response[0] == mysql.Row{
86+
vals: ['1', 'jackson', '']
87+
}
88+
89+
response = db.exec_param_many('select * from users where username = ? and id = ?',
90+
['bailey', '3'])!
91+
assert response[0] == mysql.Row{
92+
vals: ['3', 'bailey', '']
93+
}
94+
95+
response = db.exec_param_many('select * from users', [''])!
96+
assert response == [
97+
mysql.Row{
98+
vals: ['1', 'jackson', '']
99+
},
100+
mysql.Row{
101+
vals: ['2', 'shannon', '']
102+
},
103+
mysql.Row{
104+
vals: ['3', 'bailey', '']
105+
},
106+
mysql.Row{
107+
vals: ['4', 'blaze', '']
108+
},
109+
mysql.Row{
110+
vals: ['5', 'Hi', '']
111+
},
112+
]
113+
114+
response = db.exec_param('select * from users where username = ?', 'blaze')!
115+
assert response[0] == mysql.Row{
116+
vals: ['4', 'blaze', '']
117+
}
118+
119+
// transaction test
120+
// turn off `autocommit` first
121+
db.autocommit(false)!
122+
// begin a new transaction
123+
db.begin()!
124+
result_code = db.exec_none('insert into users (username) values ("tom")')
125+
assert result_code == 0
126+
// make a savepoint
127+
db.savepoint('savepoint1')!
128+
result_code = db.exec_none('insert into users (username) values ("kitty")')
129+
assert result_code == 0
130+
// rollback to `savepoint1`
131+
db.rollback_to('savepoint1')!
132+
result_code = db.exec_none('insert into users (username) values ("mars")')
133+
assert result_code == 0
134+
db.commit()!
135+
response = db.exec_param_many('select * from users', [''])!
136+
assert response == [
137+
mysql.Row{
138+
vals: ['1', 'jackson', '']
139+
},
140+
mysql.Row{
141+
vals: ['2', 'shannon', '']
142+
},
143+
mysql.Row{
144+
vals: ['3', 'bailey', '']
145+
},
146+
mysql.Row{
147+
vals: ['4', 'blaze', '']
148+
},
149+
mysql.Row{
150+
vals: ['5', 'Hi', '']
151+
},
152+
mysql.Row{
153+
vals: ['6', 'tom', '']
154+
},
155+
mysql.Row{
156+
vals: ['8', 'mars', '']
157+
},
158+
]
159+
}

examples/database/orm.v

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ fn msql_array() ! {
110110
sql db {
111111
drop table Parent
112112
} or {}
113-
db.close()
113+
db.close() or {}
114114
}
115115

116116
db.query('drop table if exists Parent')!
@@ -144,7 +144,7 @@ fn psql_array() ! {
144144
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
145145
defer {
146146
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
147-
db.close()
147+
db.close() or {}
148148
}
149149
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
150150

@@ -219,7 +219,7 @@ fn msql() ! {
219219
defer {
220220
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
221221
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
222-
conn.close()
222+
conn.close() or {}
223223
}
224224
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
225225
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
@@ -253,7 +253,7 @@ fn psql() ! {
253253
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
254254
defer {
255255
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
256-
db.close()
256+
db.close() or {}
257257
}
258258
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
259259
sql db {

thirdparty/stdatomic/nix/atomic_cpp.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ using std::memory_order_consume;
120120
using std::memory_order_relaxed;
121121
using std::memory_order_release;
122122
using std::memory_order_seq_cst;
123+
124+
#define memory_order_relaxed std::memory_order_relaxed
125+
#define memory_order_consume std::memory_order_consume
126+
#define memory_order_acquire std::memory_order_acquire
127+
#define memory_order_release std::memory_order_release
128+
#define memory_order_acq_rel std::memory_order_acq_rel
129+
#define memory_order_seq_cst std::memory_order_seq_cst
130+
123131
#else /* <atomic> unavailable, possibly because this is C, not C++ */
124132
#include <sys/types.h>
125133
#include <stdbool.h>
@@ -266,6 +274,7 @@ typedef enum
266274
memory_order_acq_rel = __ATOMIC_ACQ_REL,
267275
memory_order_seq_cst = __ATOMIC_SEQ_CST
268276
} memory_order;
277+
269278
/*
270279
* 7.17.4 Fences.
271280
*/

vlib/builtin/reuse.v

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
module builtin
2+
3+
// reuse_data_as_string provides a way to treat the memory of a []u8 `buffer` as a string value.
4+
// It does not allocate or copy the memory block for the `buffer`, but instead creates a string descriptor,
5+
// that will point to the same memory as the input.
6+
// The intended use of that function, is to allow calling string search methods (defined on string),
7+
// on []u8 values too, without having to copy/allocate by calling .bytestr() (that can be too slow and unnecessary in loops).
8+
// Note: unlike normal V strings, the return value *is not* guaranteed to have a terminating `0` byte,
9+
// since this function does not allocate or modify the input in any way. This is not a problem usually,
10+
// since V methods and functions do not require it, but be careful, if you want to pass that string to call a C. function,
11+
// that expects 0 termination. If you have to do it, make a `tmp := s.clone()` beforehand, and free the cloned `tmp` string
12+
// after you have called the C. function with it.
13+
// The .len field of the result value, will be the same as the buffer.len.
14+
// Note: avoid storing or returning that resulting string,
15+
// and avoid calling the fn with a complex expression (prefer using a temporary variable as an argument).
16+
@[unsafe]
17+
pub fn reuse_data_as_string(buffer []u8) string {
18+
return string{
19+
str: buffer.data
20+
len: buffer.len
21+
is_lit: 1 // prevent freeing the string, since its memory is owned by the input buffer
22+
}
23+
}
24+
25+
// reuse_string_as_data provides a way to treat the memory of a string `s`, as a []u8 buffer.
26+
// It does not allocate or copy the memory block for the string `s`, but instead creates an array descriptor,
27+
// that will point to the same memory as the input.
28+
// The intended use of that function, is to allow calling array methods (defined on []u8),
29+
// on string values too, without having to copy/allocate by calling .bytes() (that can be too slow and unnecessary in loops).
30+
// Note: since there are no allocations, the buffer *will not* contain the terminating `0` byte, that V strings have usually.
31+
// The .len field of the result value, will be the same as s.len .
32+
// Note: avoid storing or returning that resulting byte buffer,
33+
// and avoid calling the fn with a complex expression (prefer using a temporary variable as an argument).
34+
@[unsafe]
35+
pub fn reuse_string_as_data(s string) []u8 {
36+
mut res := unsafe {
37+
array{
38+
data: s.str
39+
len: s.len
40+
element_size: 1
41+
flags: .nogrow | .noshrink | .nofree // prevent freeing/resizing the array, since its memory is owned by the input string
42+
}
43+
}
44+
return res
45+
}

vlib/builtin/reuse_test.v

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fn test_buf_to_str() {
2+
s := 'abc'
3+
aview := unsafe { reuse_string_as_data(s) }
4+
dump(aview)
5+
assert aview == [u8(97), 98, 99]
6+
assert voidptr(aview.data) == voidptr(s.str)
7+
assert aview.len == s.len
8+
}
9+
10+
fn test_str_to_buf() {
11+
a := [u8(88), 55, 77]
12+
sview := unsafe { reuse_data_as_string(a) }
13+
dump(sview)
14+
assert sview == 'X7M'
15+
assert voidptr(sview.str) == voidptr(a.data)
16+
assert sview.len == a.len
17+
}

0 commit comments

Comments
 (0)