From 63c4d91b0b210fb978f186c0a756b686a1ed9c63 Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Tue, 20 Aug 2024 14:13:04 +0200 Subject: [PATCH 1/2] STYLE: Declare component type conversion functions constexpr Following Scott Meyers, Effective Modern C++, 2014, "Use `constexpr` whenever possible". --- src/itkOMEZarrNGFFImageIO.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/itkOMEZarrNGFFImageIO.cxx b/src/itkOMEZarrNGFFImageIO.cxx index 8dc9167..65198a6 100644 --- a/src/itkOMEZarrNGFFImageIO.cxx +++ b/src/itkOMEZarrNGFFImageIO.cxx @@ -135,7 +135,7 @@ OMEZarrNGFFImageIO::PrintSelf(std::ostream & os, Indent indent) const os << indent << "ChannelIndex: " << m_ChannelIndex << std::endl; } -IOComponentEnum +constexpr IOComponentEnum tensorstoreToITKComponentType(const tensorstore::DataType dtype) { switch (dtype.id()) @@ -177,7 +177,7 @@ tensorstoreToITKComponentType(const tensorstore::DataType dtype) } } -tensorstore::DataType +constexpr tensorstore::DataType itkToTensorstoreComponentType(const IOComponentEnum itkComponentType) { switch (itkComponentType) From 6678cc4d6e9bc321a21b550ce011b7941ee1fe0c Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Tue, 20 Aug 2024 15:43:09 +0200 Subject: [PATCH 2/2] PERF: Call tensorstoreToITKComponentType at compile-time, by constexpr Ensures that `tensorstoreToITKComponentType` is evaluated at compile-time, by introducing a constexpr variable template, `toITKComponentType`. --- src/itkOMEZarrNGFFImageIO.cxx | 103 +++++++++++++++++----------------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/src/itkOMEZarrNGFFImageIO.cxx b/src/itkOMEZarrNGFFImageIO.cxx index 65198a6..c7b00fd 100644 --- a/src/itkOMEZarrNGFFImageIO.cxx +++ b/src/itkOMEZarrNGFFImageIO.cxx @@ -246,6 +246,10 @@ itkToTensorstoreComponentType(const IOComponentEnum itkComponentType) } } +// Variable template, ensuring that tensorstoreToITKComponentType is evaluated at compile-time. +template +static constexpr IOComponentEnum toITKComponentType = tensorstoreToITKComponentType(tensorstore::dtype_v); + // Returns TensorStore KvStore driver name appropriate for this path. // Options are file, zip. TODO: http, gcs (GoogleCouldStorage), etc. std::string @@ -602,11 +606,10 @@ OMEZarrNGFFImageIO::ReadImageInformation() } // We call tensorstoreToITKComponentType for each type. -// Hopefully compiler will optimize it away via constant propagation and inlining. -#define READ_ELEMENT_IF(typeName) \ - else if (tensorstoreToITKComponentType(tensorstore::dtype_v) == this->GetComponentType()) \ - { \ - ReadFromStore(store, storeIORegion, reinterpret_cast(buffer)); \ +#define READ_ELEMENT_IF(typeName) \ + else if (toITKComponentType == this->GetComponentType()) \ + { \ + ReadFromStore(store, storeIORegion, reinterpret_cast(buffer)); \ } void @@ -708,51 +711,51 @@ OMEZarrNGFFImageIO::WriteImageInformation() // We need to specify dtype for opening. As dtype is dependent on component type, this macro is long. -#define ELEMENT_WRITE(typeName) \ - else if (tensorstoreToITKComponentType(tensorstore::dtype_v) == this->GetComponentType()) \ - { \ - if (sizeof(typeName) == 1) \ - { \ - dtype = "|"; \ - } \ - if (std::numeric_limits::is_integer) \ - { \ - if (std::numeric_limits::is_signed) \ - { \ - dtype += 'i'; \ - } \ - else \ - { \ - dtype += 'u'; \ - } \ - } \ - else \ - { \ - dtype += 'f'; \ - } \ - dtype += std::to_string(sizeof(typeName)); \ - \ - auto openFuture = tensorstore::Open( \ - { \ - { "driver", "zarr" }, \ - { "kvstore", { { "driver", driver }, { "path", this->m_FileName + "/" + path } } }, \ - { "metadata", \ - { \ - { "compressor", { { "id", "blosc" } } }, \ - { "dtype", dtype }, \ - { "shape", shape }, \ - } }, \ - }, \ - tsContext, \ - tensorstore::OpenMode::create | tensorstore::OpenMode::delete_existing, \ - tensorstore::ReadWriteMode::read_write); \ - TS_EVAL_CHECK(openFuture); \ - \ - auto writeStore = openFuture.value(); \ - auto * p = reinterpret_cast(buffer); \ - auto arr = tensorstore::Array(p, shape, tensorstore::c_order); \ - auto writeFuture = tensorstore::Write(tensorstore::UnownedToShared(arr), writeStore); \ - TS_EVAL_CHECK(writeFuture); \ +#define ELEMENT_WRITE(typeName) \ + else if (toITKComponentType == this->GetComponentType()) \ + { \ + if (sizeof(typeName) == 1) \ + { \ + dtype = "|"; \ + } \ + if (std::numeric_limits::is_integer) \ + { \ + if (std::numeric_limits::is_signed) \ + { \ + dtype += 'i'; \ + } \ + else \ + { \ + dtype += 'u'; \ + } \ + } \ + else \ + { \ + dtype += 'f'; \ + } \ + dtype += std::to_string(sizeof(typeName)); \ + \ + auto openFuture = tensorstore::Open( \ + { \ + { "driver", "zarr" }, \ + { "kvstore", { { "driver", driver }, { "path", this->m_FileName + "/" + path } } }, \ + { "metadata", \ + { \ + { "compressor", { { "id", "blosc" } } }, \ + { "dtype", dtype }, \ + { "shape", shape }, \ + } }, \ + }, \ + tsContext, \ + tensorstore::OpenMode::create | tensorstore::OpenMode::delete_existing, \ + tensorstore::ReadWriteMode::read_write); \ + TS_EVAL_CHECK(openFuture); \ + \ + auto writeStore = openFuture.value(); \ + auto * p = reinterpret_cast(buffer); \ + auto arr = tensorstore::Array(p, shape, tensorstore::c_order); \ + auto writeFuture = tensorstore::Write(tensorstore::UnownedToShared(arr), writeStore); \ + TS_EVAL_CHECK(writeFuture); \ } void