diff --git a/cpp/csp/adapters/arrow/ArrowFieldWriter.cpp b/cpp/csp/adapters/arrow/ArrowFieldWriter.cpp index 53f9979d2..90e040d4b 100644 --- a/cpp/csp/adapters/arrow/ArrowFieldWriter.cpp +++ b/cpp/csp/adapters/arrow/ArrowFieldWriter.cpp @@ -345,7 +345,11 @@ CreatedFieldWriter createFieldWriter( std::vector> childBuilders; std::vector> childWriters; - // Use fieldNames() for stable insertion order (fields() is sorted for memory layout) + // Ordering convention: csp writes struct child columns in declaration order, using + // fieldNames() rather than fields() (which is sorted by struct memory layout). This keeps + // nested-struct child order consistent with top-level column order and stable against + // internal field packing. The reader matches children by name, so either order round-trips, + // but declaration order is the on-disk contract. for( auto & subFieldName : nestedMeta -> fieldNames() ) { auto subField = nestedMeta -> field( subFieldName ); diff --git a/cpp/csp/adapters/arrow/ArrowTypeVisitor.h b/cpp/csp/adapters/arrow/ArrowTypeVisitor.h index 67e74abb7..eabfb6d92 100644 --- a/cpp/csp/adapters/arrow/ArrowTypeVisitor.h +++ b/cpp/csp/adapters/arrow/ArrowTypeVisitor.h @@ -1,9 +1,13 @@ // Arrow type visitor: maps arrow::Type::type to the corresponding C++ value type. +// Eliminates repeated switch statements on arrow types across the codebase. // // Usage: // visitArrowValueType( typeId, -// [&]( auto tag ) { using T = typename decltype(tag)::type; ... }, -// [&]() { /* unsupported */ } ); +// [&]( auto tag ) -> ReturnType { +// using T = typename decltype( tag )::type; +// return doSomething( ... ); +// }, +// [&]() -> ReturnType { /* unsupported type fallback */ } ); #ifndef _IN_CSP_ADAPTERS_ARROW_ArrowTypeVisitor_H #define _IN_CSP_ADAPTERS_ARROW_ArrowTypeVisitor_H @@ -20,12 +24,14 @@ namespace csp::adapters::arrow template struct TypeTag { using type = T; }; -// Invokes fn(TypeTag{}) for the C++ type corresponding to the arrow type. +// Invokes fn( TypeTag{} ) for the C++ value type corresponding to +// the given arrow type. Calls onDefault() for unrecognised arrow types. template decltype(auto) visitArrowValueType( ::arrow::Type::type typeId, Fn && fn, DefaultFn && onDefault ) { switch( typeId ) { + // --- Numeric --- case ::arrow::Type::BOOL: return fn( TypeTag{} ); case ::arrow::Type::INT8: return fn( TypeTag{} ); case ::arrow::Type::INT16: return fn( TypeTag{} ); @@ -39,6 +45,7 @@ decltype(auto) visitArrowValueType( ::arrow::Type::type typeId, Fn && fn, Defaul case ::arrow::Type::FLOAT: case ::arrow::Type::DOUBLE: return fn( TypeTag{} ); + // --- String / Binary --- case ::arrow::Type::STRING: case ::arrow::Type::LARGE_STRING: case ::arrow::Type::BINARY: @@ -47,6 +54,7 @@ decltype(auto) visitArrowValueType( ::arrow::Type::type typeId, Fn && fn, Defaul case ::arrow::Type::DICTIONARY: return fn( TypeTag{} ); + // --- Temporal --- case ::arrow::Type::TIMESTAMP: return fn( TypeTag{} ); case ::arrow::Type::DURATION: return fn( TypeTag{} ); case ::arrow::Type::DATE32: @@ -54,6 +62,7 @@ decltype(auto) visitArrowValueType( ::arrow::Type::type typeId, Fn && fn, Defaul case ::arrow::Type::TIME32: case ::arrow::Type::TIME64: return fn( TypeTag