32sdds::Layout makeLayout(sdds::DataMode mode = sdds::DataMode::Binary,
33 sdds::MajorOrder major = sdds::MajorOrder::Row,
34 sdds::RowCountMode rowCounts = sdds::RowCountMode::Variable) {
35 sdds::DataOptions data;
37 data.majorOrder = major;
38 data.rowCountMode = rowCounts;
39 sdds::LayoutBuilder builder;
40 builder.setDataOptions(data)
41 .addParameter({{
"p", std::nullopt,
"count", std::nullopt, std::nullopt,
42 sdds::Type::Int64}, std::nullopt})
43 .addArray({{
"a", std::nullopt,
"m", std::nullopt, std::nullopt,
44 sdds::Type::Double}, 0, 1, std::nullopt})
45 .addColumn({{
"x", std::nullopt, std::nullopt, std::nullopt, std::nullopt,
46 sdds::Type::Int32}, 0})
47 .addColumn({{
"y", std::nullopt,
"m", std::nullopt, std::nullopt,
48 sdds::Type::Double}, 0})
49 .addColumn({{
"label", std::nullopt, std::nullopt, std::nullopt, std::nullopt,
50 sdds::Type::String}, 0});
51 return builder.build();
54sdds::Page makePage(
const std::shared_ptr<const sdds::Layout> &layout) {
55 sdds::Page page(layout);
56 page.setParameter(
"p", std::int64_t{7});
57 page.setArray(
"a", {{3}, std::vector<double>{1.0, 2.0, 3.0}});
58 page.setColumn(
"x", std::vector<std::int32_t>{1, 2, 3, 4, 5});
59 page.setColumn(
"y", std::vector<double>{0.5, 1.5, 2.5, 3.5, 4.5});
60 page.setColumn(
"label", std::vector<std::string>{
"one",
"two",
"three",
"four",
"five"});
64void writeOnePage(
const std::filesystem::path &path,
const sdds::Layout &layout,
65 sdds::WriterOptions options = {}) {
66 auto shared = std::make_shared<const sdds::Layout>(layout);
67 auto writer = sdds::Writer::create(path, layout, options);
68 writer.write(makePage(shared));
72void selectiveIoAndIndex(
const std::filesystem::path &path,
73 const std::filesystem::path &asciiPath) {
74 writeOnePage(path, makeLayout());
75 auto reader = sdds::Reader::open(path);
76 sdds::ReadRequest request;
77 request.parameters = sdds::FieldSelection::only({
"p"});
78 request.arrays = sdds::FieldSelection::noFields();
79 request.columns = sdds::FieldSelection::only({
"y"});
80 request.rows.first = 1;
81 request.rows.count = 2;
82 request.rows.stride = 2;
83 auto page = reader.next(request);
84 assert(page && page->rowCount() == 2);
85 assert(page->parameterLoaded(
"p"));
86 assert(!page->arrayLoaded(
"a"));
87 assert(!page->columnLoaded(
"x"));
88 assert(page->columnLoaded(
"y"));
89 assert((page->columnAs<
double>(
"y") == std::vector<double>{1.5, 3.5}));
92 (void)page->column(
"x");
93 }
catch (
const sdds::StateError &) {
99 auto layout = makeLayout(sdds::DataMode::Ascii, sdds::MajorOrder::Row,
100 sdds::RowCountMode::None);
101 writeOnePage(asciiPath, layout);
102 reader = sdds::Reader::open(asciiPath);
104 request.parameters = sdds::FieldSelection::noFields();
105 request.arrays = sdds::FieldSelection::noFields();
106 request.columns = sdds::FieldSelection::only({
"x"});
107 request.rows.last = 2;
108 page = reader.next(request);
109 assert(page && (page->columnAs<std::int32_t>(
"x") ==
110 std::vector<std::int32_t>{4, 5}));
113 auto twoPageWriter = sdds::Writer::append(path);
114 twoPageWriter.write(makePage(std::make_shared<const sdds::Layout>(makeLayout())));
115 twoPageWriter.close();
116 reader = sdds::Reader::open(path);
117 reader.buildPageIndex();
118 assert(reader.indexedPageCount() == 2);
120 page = reader.next();
121 assert(page && page->number() == 2);
125void memoryAndStreamIo() {
126 const auto layout = makeLayout();
127 auto shared = std::make_shared<const sdds::Layout>(layout);
128 for (
const auto compression : {sdds::Compression::None, sdds::Compression::Gzip,
129 sdds::Compression::Xz, sdds::Compression::Lzma}) {
130 std::vector<std::uint8_t> bytes;
131 sdds::WriterOptions writerOptions;
132 writerOptions.compression = compression;
133 writerOptions.gzipLevel = 1;
134 writerOptions.lzmaPreset = 1;
135 auto writer = sdds::Writer::toSink(sdds::outputToMemory(bytes), layout,
"memory",
137 writer.write(makePage(shared));
139 assert(!bytes.empty());
141 sdds::ReaderOptions readerOptions;
142 readerOptions.compression = compression;
143 auto reader = sdds::Reader::fromSource(sdds::inputFromMemory(bytes.data(), bytes.size()),
144 "memory", readerOptions);
145 auto page = reader.next();
146 assert(page && page->columnAs<std::int32_t>(
"x")[4] == 5);
150 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
151 auto writer = sdds::Writer::toSink(sdds::outputToStream(stream), layout,
"stringstream");
152 writer.write(makePage(shared));
155 auto reader = sdds::Reader::fromSource(sdds::inputFromStream(stream),
"stringstream");
156 assert(reader.next());
160void sourceCapabilities(
const std::filesystem::path &inputPath,
161 const std::filesystem::path &outputPath) {
162 auto source = sdds::inputFromPath(inputPath);
163 const auto inputCapabilities = source->capabilities();
164 assert(inputCapabilities.read && inputCapabilities.seek && inputCapabilities.reopen);
165 std::uint8_t bytes[4]{};
166 assert(source->read(bytes,
sizeof(bytes)) ==
sizeof(bytes));
169 assert(source->tell() ==
sizeof(bytes));
172 FILE *borrowedInput = std::fopen(inputPath.string().c_str(),
"rb");
173 assert(borrowedInput);
174 auto fileSource = sdds::inputFromFile(borrowedInput);
175 assert(fileSource->read(bytes,
sizeof(bytes)) ==
sizeof(bytes));
177 assert(std::fseek(borrowedInput, 0, SEEK_SET) == 0);
178 std::fclose(borrowedInput);
180 auto sink = sdds::outputToPath(outputPath);
181 const auto outputCapabilities = sink->capabilities();
182 assert(outputCapabilities.write && outputCapabilities.seek && outputCapabilities.truncate &&
183 outputCapabilities.flush && outputCapabilities.sync && outputCapabilities.reopen);
184 const char first[] =
"abc";
185 sink->write(first,
sizeof(first) - 1);
188 const char second[] =
"def";
189 sink->write(second,
sizeof(second) - 1);
191 assert(std::filesystem::file_size(outputPath) == 6);
193 FILE *borrowedOutput = std::fopen(outputPath.string().c_str(),
"wb+");
194 assert(borrowedOutput);
195 const auto layout = makeLayout();
196 auto writer = sdds::Writer::toSink(sdds::outputToFile(borrowedOutput), layout,
198 writer.write(makePage(std::make_shared<const sdds::Layout>(layout)));
200 assert(std::fseek(borrowedOutput, 0, SEEK_SET) == 0);
202 assert(std::fread(header, 1, 5, borrowedOutput) == 5);
203 assert(std::string(header, 5) ==
"SDDS5");
204 std::fclose(borrowedOutput);
207void headerlessIo(
const std::filesystem::path &path) {
208 sdds::DataOptions data;
209 data.mode = sdds::DataMode::Ascii;
210 sdds::LayoutBuilder builder;
211 builder.setDataOptions(data)
212 .addColumn({{
"x", std::nullopt, std::nullopt, std::nullopt, std::nullopt,
213 sdds::Type::Int32}, 0});
214 const auto layout = builder.build();
216 std::ofstream output(path, std::ios::binary);
217 output <<
"3\n1\n2\n3\n";
219 auto reader = sdds::Reader::openHeaderless(path, layout);
220 auto page = reader.next();
221 assert(page && (page->columnAs<std::int32_t>(
"x") ==
222 std::vector<std::int32_t>{1, 2, 3}));
226void disconnectReconnectAndLocks(
const std::filesystem::path &path,
227 const std::filesystem::path &replacement,
228 const std::filesystem::path &lockPath,
229 const std::filesystem::path &saved) {
230 writeOnePage(path, makeLayout());
231 auto reader = sdds::Reader::open(path);
234 assert(reader.next());
237 auto writer = sdds::Writer::create(replacement, makeLayout());
240 writer.write(makePage(std::make_shared<const sdds::Layout>(makeLayout())));
243 writer = sdds::Writer::create(lockPath, makeLayout());
246 auto conflicting = sdds::Writer::append(lockPath);
248 }
catch (
const sdds::IoError &) {
254 reader = sdds::Reader::open(path);
256 std::filesystem::rename(path, saved);
257 std::filesystem::rename(replacement, path);
261 }
catch (
const sdds::StateError &) {
268sdds::Layout liveLayout(sdds::MajorOrder major = sdds::MajorOrder::Row) {
269 sdds::DataOptions data;
270 data.mode = sdds::DataMode::Binary;
271 data.majorOrder = major;
272 sdds::LayoutBuilder builder;
273 builder.setDataOptions(data)
274 .addColumn({{
"x", std::nullopt, std::nullopt, std::nullopt, std::nullopt,
275 sdds::Type::Int32}, 0});
276 return builder.build();
279void liveRowsAndUpdateStrategies(
const std::filesystem::path &path,
280 const std::filesystem::path &columnMajorPath,
281 const std::filesystem::path &compressedPath) {
282 auto layout = liveLayout();
283 auto writer = sdds::Writer::create(path, layout);
285 writer.setColumn(
"x", std::vector<std::int32_t>{1, 2});
289 auto follower = sdds::Reader::open(path);
290 assert(follower.next());
291 assert(!follower.next());
292 writer = sdds::Writer::appendToLastPage(path, 1);
293 writer.setColumn(
"x", std::vector<std::int32_t>{3, 4}, 2);
294 writer.updatePage(
true);
296 auto delta = follower.readNewRows();
297 assert(delta && delta->pageNumber == 1 && delta->firstRow == 2);
298 assert((delta->page.columnAs<std::int32_t>(
"x") == std::vector<std::int32_t>{3, 4}));
299 assert(!follower.readNewRows());
302 layout = liveLayout(sdds::MajorOrder::Column);
303 writer = sdds::Writer::create(columnMajorPath, layout);
305 writer.setColumn(
"x", std::vector<std::int32_t>{1, 2});
308 sdds::WriterOptions options;
309 options.updateStrategy = sdds::UpdateStrategy::InPlaceOnly;
312 writer = sdds::Writer::appendToLastPage(columnMajorPath, 1, options);
313 }
catch (
const sdds::StateError &) {
317 options.updateStrategy = sdds::UpdateStrategy::AtomicRewrite;
318 writer = sdds::Writer::appendToLastPage(columnMajorPath, 1, options);
319 writer.setColumn(
"x", std::vector<std::int32_t>{3}, 2);
320 writer.updatePage(
true);
322 auto reader = sdds::Reader::open(columnMajorPath);
323 auto page = reader.next();
324 assert(page && (page->columnAs<std::int32_t>(
"x") ==
325 std::vector<std::int32_t>{1, 2, 3}));
328 layout = liveLayout();
329 writer = sdds::Writer::create(compressedPath, layout);
331 writer.setColumn(
"x", std::vector<std::int32_t>{1, 2});
334 writer = sdds::Writer::appendToLastPage(compressedPath, 1);
335 writer.setColumn(
"x", std::vector<std::int32_t>{3}, 2);
336 writer.updatePage(
true);
338 reader = sdds::Reader::open(compressedPath);
339 page = reader.next();
340 assert(page && (page->columnAs<std::int32_t>(
"x") ==
341 std::vector<std::int32_t>{1, 2, 3}));
345void transformations(
const std::filesystem::path &input,
346 const std::filesystem::path &output) {
347 writeOnePage(input, makeLayout());
348 auto reader = sdds::Reader::open(input);
349 auto page = reader.next();
351 assert(page->row(2).get<std::int32_t>(
"x") == 3);
352 auto high = page->matchRows(
"x", [](
const sdds::Scalar &value) {
353 return std::get<std::int32_t>(value) >= 3;
355 auto odd = page->matchRows<std::int32_t>(
"x", [](std::int32_t value) {
356 return value % 2 != 0;
358 auto filtered = page->filtered(high & odd);
359 assert((filtered.columnAs<std::int32_t>(
"x") == std::vector<std::int32_t>{3, 5}));
360 auto matrix = page->matrix<
double>({
"x",
"y"}, sdds::ConversionMode::Checked);
361 assert(matrix.rows == 5 && matrix.columns == 2);
362 assert(matrix(3, 0) == 4.0 && matrix(3, 1) == 3.5);
363 auto converted = sdds::convertUnits(*page, sdds::FieldKind::Column,
"y",
"cm", 100.0L);
364 assert(converted.layout().columns[1].units == std::optional<std::string>(
"cm"));
365 assert(converted.columnAs<
double>(
"y")[1] == 150.0);
369 (void)sdds::convertScalar(std::numeric_limits<std::uint64_t>::max(), sdds::Type::Int32);
370 }
catch (
const sdds::TypeError &) {
376 (void)sdds::convertScalar(1.5, sdds::Type::Int32);
377 }
catch (
const sdds::TypeError &) {
381 assert(std::get<std::int32_t>(sdds::convertScalar(
382 1.5, sdds::Type::Int32, sdds::RoundingMode::Nearest)) == 2);
384 sdds::LayoutEditor editor(makeLayout());
385 const auto edited = editor.renameColumn(
"y",
"distance").dropColumn(
"label").build();
386 assert(edited.columns.size() == 2 && edited.columns[1].name ==
"distance");
389 reader = sdds::Reader::open(input);
390 sdds::CopyOptions copy;
391 copy.transformLayout = [](
const sdds::Layout &layout) {
392 return sdds::LayoutEditor(layout).renameColumn(
"y",
"distance").build();
394 sdds::copyDataset(reader, output, copy);
396 reader = sdds::Reader::open(output);
397 page = reader.next();
398 assert(page && page->columnAs<
double>(
"distance")[4] == 4.5);
402void limitsAndMalformedProjection(
const std::filesystem::path &path,
403 const std::filesystem::path &truncated) {
404 writeOnePage(path, makeLayout());
405 sdds::ReaderOptions options;
406 options.limits.maxProjectedFields = 1;
409 auto reader = sdds::Reader::open(path, options);
411 }
catch (
const sdds::LimitError &) {
417 options.limits.maxTransformationElements = 4;
418 auto reader = sdds::Reader::open(path, options);
419 auto page = reader.next();
422 (void)page->matrix<
double>({
"x"}, sdds::ConversionMode::Checked);
423 }
catch (
const sdds::LimitError &) {
429 std::filesystem::copy_file(path, truncated,
430 std::filesystem::copy_options::overwrite_existing);
431 std::filesystem::resize_file(truncated, std::filesystem::file_size(truncated) - 1);
432 reader = sdds::Reader::open(truncated);
433 sdds::ReadRequest request;
434 request.parameters = sdds::FieldSelection::noFields();
435 request.arrays = sdds::FieldSelection::noFields();
436 request.columns = sdds::FieldSelection::noFields();
439 (void)reader.next(request);
440 }
catch (
const sdds::FormatError &error) {
442 assert(error.path() == truncated);
443 assert(error.page() == 1);
444 assert(error.offset().has_value());
445 assert(error.row().has_value());
446 assert(error.field() == std::optional<std::string>(
"label"));
454int main(
int argc,
char **argv) {
455 assert(sdds::cppApiVersion == 2);
456 if (argc != 2)
return 2;
457 const std::filesystem::path directory(argv[1]);
458 std::filesystem::create_directories(directory);
459 selectiveIoAndIndex(directory /
"selective.sdds", directory /
"last-rows.sdds");
461 sourceCapabilities(directory /
"selective.sdds", directory /
"raw-output.bin");
462 headerlessIo(directory /
"headerless.dat");
463 disconnectReconnectAndLocks(directory /
"reconnect.sdds",
464 directory /
"replacement.sdds",
465 directory /
"locked.sdds",
466 directory /
"saved.sdds");
467 liveRowsAndUpdateStrategies(directory /
"live.sdds", directory /
"column-update.sdds",
468 directory /
"compressed-update.sdds.gz");
469 transformations(directory /
"transform-input.sdds", directory /
"transform-output.sdds");
470 limitsAndMalformedProjection(directory /
"limits.sdds", directory /
"truncated.sdds");