diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2024-05-24 13:26:12 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2024-05-24 13:26:12 +0200 |
| commit | 3b739dc5ccf1ddb29b53a86155e5671b5be00c54 (patch) | |
| tree | c53e7ac13d7a42d261c532dbb7741982e683cb36 /core/encoding/csv | |
| parent | 7dc1f114b96b9e25dfc2537ab153fe655e65affc (diff) | |
Add iterator_next(&r) to CSV.
Diffstat (limited to 'core/encoding/csv')
| -rw-r--r-- | core/encoding/csv/example.odin | 89 | ||||
| -rw-r--r-- | core/encoding/csv/reader.odin | 25 |
2 files changed, 112 insertions, 2 deletions
diff --git a/core/encoding/csv/example.odin b/core/encoding/csv/example.odin new file mode 100644 index 000000000..1484dd940 --- /dev/null +++ b/core/encoding/csv/example.odin @@ -0,0 +1,89 @@ +//+build ignore +package encoding_csv + +import "core:fmt" +import "core:encoding/csv" +import "core:os" +import "core:mem" + +// Requires keeping the entire CSV file in memory at once +iterate_csv_from_string :: proc(filename: string) { + r: csv.Reader + r.trim_leading_space = true + r.reuse_record = true // Without it you have to delete(record) + r.reuse_record_buffer = true // Without it you have to each of the fields within it + defer csv.reader_destroy(&r) + + if csv_data, ok := os.read_entire_file(filename); ok { + csv.reader_init_with_string(&r, string(csv_data)) + defer delete(csv_data) + } else { + fmt.printfln("Unable to open file: %v", filename) + return + } + + for r, i, err in csv.iterator_next(&r) { + if err != nil { /* Do something with error */ } + for f, j in r { + fmt.printfln("Record %v, field %v: %q", i, j, f) + } + } +} + +// Reads the CSV as it's processed (with a small buffer) +iterate_csv_from_stream :: proc(filename: string) { + fmt.printfln("Hellope from %v", filename) + r: csv.Reader + r.trim_leading_space = true + r.reuse_record = true // Without it you have to delete(record) + r.reuse_record_buffer = true // Without it you have to each of the fields within it + defer csv.reader_destroy(&r) + + handle, errno := os.open(filename) + if errno != os.ERROR_NONE { + fmt.printfln("Error opening file: %v", filename) + return + } + defer os.close(handle) + csv.reader_init(&r, os.stream_from_handle(handle)) + + for r, i in csv.iterator_next(&r) { + for f, j in r { + fmt.printfln("Record %v, field %v: %q", i, j, f) + } + } + fmt.printfln("Error: %v", csv.iterator_last_error(r)) +} + +// Read all records at once +read_csv_from_string :: proc(filename: string) { + r: csv.Reader + r.trim_leading_space = true + r.reuse_record = true // Without it you have to delete(record) + r.reuse_record_buffer = true // Without it you have to each of the fields within it + defer csv.reader_destroy(&r) + + if csv_data, ok := os.read_entire_file(filename); ok { + csv.reader_init_with_string(&r, string(csv_data)) + defer delete(csv_data) + } else { + fmt.printfln("Unable to open file: %v", filename) + return + } + + records, err := csv.read_all(&r) + if err != nil { /* Do something with CSV parse error */ } + + defer { + for rec in records { + delete(rec) + } + delete(records) + } + + for r, i in records { + for f, j in r { + fmt.printfln("Record %v, field %v: %q", i, j, f) + } + } +}
\ No newline at end of file diff --git a/core/encoding/csv/reader.odin b/core/encoding/csv/reader.odin index f8c72c423..200bf43ea 100644 --- a/core/encoding/csv/reader.odin +++ b/core/encoding/csv/reader.odin @@ -57,6 +57,9 @@ Reader :: struct { field_indices: [dynamic]int, last_record: [dynamic]string, sr: strings.Reader, // used by reader_init_with_string + + // Set and used by the iterator. Query using `iterator_last_error` + last_iterator_error: Error, } @@ -121,6 +124,25 @@ reader_destroy :: proc(r: ^Reader) { bufio.reader_destroy(&r.r) } +/* + Returns a record at a time. + + for record, row_idx in csv.iterator_next(&r) { ... } + + TIP: If you process the results within the loop and don't need to own the results, + you can set the Reader's `reuse_record` and `reuse_record_reuse_record_buffer` to true; + you won't need to delete the record or its fields. +*/ +iterator_next :: proc(r: ^Reader) -> (record: []string, idx: int, err: Error, more: bool) { + record, r.last_iterator_error = read(r) + return record, r.line_count - 1, r.last_iterator_error, r.last_iterator_error == nil +} + +// Get last error if we the iterator +iterator_last_error :: proc(r: Reader) -> (err: Error) { + return r.last_iterator_error +} + // read reads a single record (a slice of fields) from r // // All \r\n sequences are normalized to \n, including multi-line field @@ -460,5 +482,4 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all r.fields_per_record = len(dst) } return dst[:], err - -} +}
\ No newline at end of file |