-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.cpp
More file actions
235 lines (196 loc) · 8.09 KB
/
Copy pathexample.cpp
File metadata and controls
235 lines (196 loc) · 8.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
* Copyright (c) 2025-2026 Tobias Weber <weber.tobias.md@gmail.com>
*
* This file is part of the BCSV library.
*
* Licensed under the MIT License. See LICENSE file in the project root
* for full license information.
*/
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <bcsv/bcsv.h>
/**
* BCSV Flexible Interface Example
*
* This example demonstrates the runtime flexible Layout and Row interface
* for writing and reading BCSV files. The flexible interface allows you to
* define column layouts at runtime and is ideal when you don't know the
* data structure at compile time.
*/
struct SampleData {
int32_t id;
std::string name;
float score;
bool active;
};
std::vector<SampleData> generateTestData() {
return {
{1, "Alice Johnson", 95.5f, true},
{2, "Bob Smith", 87.2f, true},
{3, "Carol Williams", 92.8f, false},
{4, "David Brown", 78.9f, true},
{5, "Eve Davis", 88.1f, false}
};
}
void writeFlexibleBCSV(const std::vector<SampleData>& testData) {
std::cout << "=== Writing with Flexible Interface ===\n\n";
// Step 1: Create a flexible layout
// The Layout class allows you to define columns at runtime
bcsv::Layout layout;
// Add columns with name and data type
layout.addColumn({"id", bcsv::ColumnType::INT32});
layout.addColumn({"name", bcsv::ColumnType::STRING});
layout.addColumn({"score", bcsv::ColumnType::FLOAT});
layout.addColumn({"active", bcsv::ColumnType::BOOL});
std::cout << "Created layout with " << layout.columnCount() << " columns\n";
// Step 2: Create a writer
const std::string filename = "example_flexible.bcsv";
bcsv::Writer<bcsv::Layout> writer(layout);
if(!writer.open(filename, true)) {
std::cerr << "Failed to open file for writing: " << filename << "\n";
return;
}
// Step 3: Write data rows
for (const auto& data : testData) {
auto& row = writer.row();
row.set(0, data.id);
row.set(1, data.name);
row.set(2, data.score);
row.set(3, data.active);
writer.writeRow();
}
writer.flush();
std::cout << "Successfully wrote " << testData.size() << " rows to " << filename << "\n\n";
}
bool validateWriteSuccess(const std::string& filename) {
std::ifstream file_check(filename, std::ios::binary | std::ios::ate);
if (!file_check) {
std::cerr << "VALIDATION ERROR: File does not exist: " << filename << "\n";
return false;
}
size_t file_size = file_check.tellg();
file_check.close();
std::cout << "Write validation: File exists with size " << file_size << " bytes\n";
if (file_size < 100) {
std::cerr << "VALIDATION ERROR: File size too small (" << file_size << " bytes)\n";
return false;
}
return true;
}
std::vector<SampleData> readFlexibleBCSV() {
std::cout << "=== Reading with Flexible Interface ===\n\n";
std::vector<SampleData> readData;
// Step 1: Create matching layout for reading
// Must match the layout used for writing
bcsv::Layout layoutExpected;
layoutExpected.addColumn({"id", bcsv::ColumnType::INT32});
layoutExpected.addColumn({"name", bcsv::ColumnType::STRING});
layoutExpected.addColumn({"score", bcsv::ColumnType::FLOAT});
layoutExpected.addColumn({"active", bcsv::ColumnType::BOOL});
// Step 2: Create a reader
const std::string filename = "example_flexible.bcsv";
bcsv::Reader<bcsv::Layout> reader;
if (!reader.open(filename)) {
std::cerr << "Failed to open file: " << filename << "\n";
return readData;
}
// Validate layout compatibility (column count, types)
if (!reader.layout().isCompatible(layoutExpected)) {
std::cerr << "Error: File layout is not compatible with expected layout\n";
reader.close();
return readData;
}
//Optional: Compare column names
for (size_t i = 0; i < layoutExpected.columnCount(); i++) {
if (layoutExpected.columnName(i) != reader.layout().columnName(i)) {
std::cerr << "Warning: Column name mismatch at index " << i
<< " (expected: " << layoutExpected.columnName(i)
<< ", found: " << reader.layout().columnName(i) << ")\n";
}
}
std::cout << "Reading data:\n\n";
// Table header
std::cout << "ID | Name | Score | Active\n";
std::cout << "---|----------------|-------|-------\n";
// Step 3: Read rows
while (reader.readNext()) {
auto& row = reader.row();
SampleData data;
bool ok = true;
ok &= row.get(0, data.id);
ok &= row.get(1, data.name);
ok &= row.get(2, data.score);
ok &= row.get(3, data.active);
if (!ok) {
std::cerr << "Warning: Failed to read row values, skipping row.\n";
continue;
}
readData.push_back(data);
std::cout << std::setw(2) << data.id << " | "
<< std::setw(14) << std::left << data.name << " | "
<< std::setw(5) << std::right << std::fixed << std::setprecision(1) << data.score << " | "
<< (data.active ? "Yes" : "No") << "\n";
}
reader.close();
std::cout << "\nSuccessfully read " << readData.size() << " rows from " << filename << "\n\n";
return readData;
}
bool validateReadSuccess(const std::vector<SampleData>& expectedData, const std::vector<SampleData>& readData) {
std::cout << "=== Validating Read Data ===\n\n";
if (readData.size() != expectedData.size()) {
std::cerr << "❌ VALIDATION FAILED: Expected " << expectedData.size()
<< " rows, but read " << readData.size() << " rows!\n\n";
return false;
}
bool validationError = false;
for (size_t i = 0; i < expectedData.size(); i++) {
const auto& expected = expectedData[i];
const auto& actual = readData[i];
if (actual.id != expected.id || actual.name != expected.name ||
std::abs(actual.score - expected.score) > 0.01f || actual.active != expected.active) {
std::cerr << "ERROR: Data mismatch at row " << i << "\n";
std::cerr << " Expected: id=" << expected.id << ", name=\"" << expected.name
<< "\", score=" << expected.score << ", active=" << expected.active << "\n";
std::cerr << " Got: id=" << actual.id << ", name=\"" << actual.name
<< "\", score=" << actual.score << ", active=" << actual.active << "\n";
validationError = true;
}
}
if (validationError) {
std::cerr << "\n❌ VALIDATION FAILED: Read data does not match expected data!\n\n";
return false;
}
std::cout << "✓ VALIDATION PASSED: All " << readData.size() << " rows verified successfully!\n\n";
return true;
}
int main() {
std::cout << "BCSV Flexible Interface Example\n";
std::cout << "===============================\n\n";
std::cout << "This example demonstrates reading and writing BCSV files\n";
std::cout << "using the flexible Layout/Row interface for runtime-defined schemas.\n\n";
try {
// Generate test data once
auto testData = generateTestData();
// Write data using flexible interface
writeFlexibleBCSV(testData);
// Validate write success (test code)
if (!validateWriteSuccess("example_flexible.bcsv")) {
return 1;
}
// Read data back using flexible interface
auto readData = readFlexibleBCSV();
// Validate read data matches expected data (test code)
if (!validateReadSuccess(testData, readData)) {
return 1;
}
std::cout << "✓ Example completed successfully!\n";
std::cout << "The flexible interface is ideal when you need to define\n";
std::cout << "data structures at runtime or work with varying schemas.\n";
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}