mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Clean up TypedArray and TimeSamples: remove stale code and add helpers
- Remove stale factory functions from typed-array.hh that referenced non-existent constructors from old TypedArrayImpl class: MakeOwnedTypedArray, MakeDedupTypedArray, MakeSharedTypedArray, MakeMmapTypedArray, CreateOwnedTypedArray, CreateDedupTypedArray, CreateMmapTypedArray - Keep working convenience functions: MakeTypedArrayCopy, MakeTypedArrayReserved, DuplicateTypedArray - Delete stale typed-array-factories test directory using old API - Add time-finding helper functions to TimeSamples class to reduce code duplication: find_time_index_in_unified(), find_time_index_in_samples(), kNotFound constant - Refactor get_typed_array_at_time, get_typed_array_view_at_time, get_vector_at_time to use new helpers - Fix is_using_pod() documentation to accurately describe behavior - Remove stale #if 1 TODO comment and fix typos (bloked -> blocked) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -180,7 +180,9 @@ struct TimeSamples {
|
||||
/// This determines whether to use POD optimization or regular storage
|
||||
bool init(uint32_t type_id);
|
||||
|
||||
/// Check if using unified POD storage (deprecated - always true now)
|
||||
/// Check if unified storage has samples (i.e., _times is not empty)
|
||||
/// Returns true if any samples have been added to unified storage path.
|
||||
/// Note: After PODTimeSamples removal, this checks unified storage, not a separate POD type.
|
||||
bool is_using_pod() const { return !_times.empty(); }
|
||||
|
||||
/// Check if storing std::vector-based array data
|
||||
@@ -710,11 +712,8 @@ struct TimeSamples {
|
||||
|
||||
// Use unified storage - find index by time
|
||||
if (!_times.empty()) {
|
||||
auto it = std::find_if(_times.begin(), _times.end(), [&t](double sample_t) {
|
||||
return std::fabs(t - sample_t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
if (it != _times.end()) {
|
||||
size_t idx = static_cast<size_t>(std::distance(_times.begin(), it));
|
||||
size_t idx = find_time_index_in_unified(t);
|
||||
if (idx != kNotFound) {
|
||||
return get_typed_array_at<T>(idx, typed_array, blocked);
|
||||
}
|
||||
}
|
||||
@@ -857,22 +856,15 @@ struct TimeSamples {
|
||||
|
||||
// Check unified storage first
|
||||
if (!_times.empty()) {
|
||||
auto it = std::find_if(_times.begin(), _times.end(), [&t](double sample_t) {
|
||||
return std::fabs(t - sample_t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
if (it != _times.end()) {
|
||||
size_t idx = static_cast<size_t>(std::distance(_times.begin(), it));
|
||||
size_t idx = find_time_index_in_unified(t);
|
||||
if (idx != kNotFound) {
|
||||
return get_typed_array_view_at<T>(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// For regular Value storage
|
||||
const auto it = std::find_if(_samples.begin(), _samples.end(), [&t](const Sample& s) {
|
||||
return std::fabs(t - s.t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
|
||||
if (it != _samples.end()) {
|
||||
size_t idx = static_cast<size_t>(std::distance(_samples.begin(), it));
|
||||
size_t idx = find_time_index_in_samples(t);
|
||||
if (idx != kNotFound) {
|
||||
return get_typed_array_view_at<T>(idx);
|
||||
}
|
||||
|
||||
@@ -1079,34 +1071,32 @@ struct TimeSamples {
|
||||
return _samples;
|
||||
}
|
||||
|
||||
#if 1 // TODO: Write implementation in .cc
|
||||
// Get value at specified time.
|
||||
// For non-interpolatable types (includes enums and unknown types)
|
||||
//
|
||||
// Return `Held` value even when TimeSampleInterpolationType is
|
||||
// Linear. Returns false when specified time is out-of-range.
|
||||
template<typename T, std::enable_if_t<!value::LerpTraits<T>::supported(), std::nullptr_t> = nullptr>
|
||||
bool get(T *dst, double t = value::TimeCode::Default(),
|
||||
value::TimeSampleInterpolationType interp =
|
||||
value::TimeSampleInterpolationType::Linear) const {
|
||||
|
||||
// Get value at specified time.
|
||||
// For non-interpolatable types(includes enums and unknown types)
|
||||
//
|
||||
// Return `Held` value even when TimeSampleInterpolationType is
|
||||
// Linear. Returns nullopt when specified time is out-of-range.
|
||||
template<typename T, std::enable_if_t<!value::LerpTraits<T>::supported(), std::nullptr_t> = nullptr>
|
||||
bool get(T *dst, double t = value::TimeCode::Default(),
|
||||
value::TimeSampleInterpolationType interp =
|
||||
value::TimeSampleInterpolationType::Linear) const {
|
||||
(void)interp;
|
||||
|
||||
(void)interp;
|
||||
if (!dst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dst) {
|
||||
return false;
|
||||
}
|
||||
if (empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty()) {
|
||||
return false;
|
||||
}
|
||||
if (_dirty) {
|
||||
update();
|
||||
}
|
||||
|
||||
if (_dirty) {
|
||||
update();
|
||||
}
|
||||
|
||||
if (value::TimeCode(t).is_default()) {
|
||||
// TODO: Handle bloked
|
||||
if (value::TimeCode(t).is_default()) {
|
||||
// TODO: Handle blocked
|
||||
if (const auto pv = _samples[0].value.as<T>()) {
|
||||
(*dst) = *pv;
|
||||
return true;
|
||||
@@ -1159,7 +1149,7 @@ struct TimeSamples {
|
||||
|
||||
if (value::TimeCode(t).is_default()) {
|
||||
// FIXME: Use the first item for now.
|
||||
// TODO: Handle bloked
|
||||
// TODO: Handle blocked
|
||||
if (!_samples.empty()) {
|
||||
if (const auto pv = _samples[0].value.as<T>()) {
|
||||
(*dst) = *pv;
|
||||
@@ -1243,7 +1233,6 @@ struct TimeSamples {
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t estimate_memory_usage() const {
|
||||
size_t total = sizeof(TimeSamples);
|
||||
@@ -1578,25 +1567,16 @@ struct TimeSamples {
|
||||
|
||||
// Check unified POD storage
|
||||
if (!_times.empty()) {
|
||||
// Find index for time
|
||||
auto it = std::find_if(_times.begin(), _times.end(), [&t](double sample_t) {
|
||||
return std::fabs(t - sample_t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
|
||||
if (it != _times.end()) {
|
||||
size_t idx = static_cast<size_t>(std::distance(_times.begin(), it));
|
||||
size_t idx = find_time_index_in_unified(t);
|
||||
if (idx != kNotFound) {
|
||||
return get_vector_at<T>(idx, out_vec, out_blocked);
|
||||
}
|
||||
return false; // Time not found
|
||||
}
|
||||
|
||||
// Check generic Value storage
|
||||
auto it = std::find_if(_samples.begin(), _samples.end(), [&t](const Sample& s) {
|
||||
return std::fabs(t - s.t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
|
||||
if (it != _samples.end()) {
|
||||
size_t idx = static_cast<size_t>(std::distance(_samples.begin(), it));
|
||||
size_t idx = find_time_index_in_samples(t);
|
||||
if (idx != kNotFound) {
|
||||
return get_vector_at<T>(idx, out_vec, out_blocked);
|
||||
}
|
||||
|
||||
@@ -1684,6 +1664,34 @@ struct TimeSamples {
|
||||
|
||||
// _pod_samples removed - using unified storage directly
|
||||
|
||||
/// Find index for time value in _times vector using epsilon comparison
|
||||
/// @param t Time value to search for
|
||||
/// @return Index if found, or size_t(-1) if not found
|
||||
size_t find_time_index_in_unified(double t) const {
|
||||
auto it = std::find_if(_times.begin(), _times.end(), [&t](double sample_t) {
|
||||
return std::fabs(t - sample_t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
if (it != _times.end()) {
|
||||
return static_cast<size_t>(std::distance(_times.begin(), it));
|
||||
}
|
||||
return static_cast<size_t>(-1); // Not found
|
||||
}
|
||||
|
||||
/// Find index for time value in _samples vector using epsilon comparison
|
||||
/// @param t Time value to search for
|
||||
/// @return Index if found, or size_t(-1) if not found
|
||||
size_t find_time_index_in_samples(double t) const {
|
||||
auto it = std::find_if(_samples.begin(), _samples.end(), [&t](const Sample& s) {
|
||||
return std::fabs(t - s.t) < std::numeric_limits<double>::epsilon();
|
||||
});
|
||||
if (it != _samples.end()) {
|
||||
return static_cast<size_t>(std::distance(_samples.begin(), it));
|
||||
}
|
||||
return static_cast<size_t>(-1); // Not found
|
||||
}
|
||||
|
||||
static constexpr size_t kNotFound = static_cast<size_t>(-1);
|
||||
|
||||
public:
|
||||
// Helper constants for value array dedup
|
||||
static constexpr uint64_t VALUE_ARRAY_DEDUP_BIT = uint64_t(1) << 63;
|
||||
|
||||
@@ -2266,78 +2266,8 @@ void swap(ChunkedTypedArray<T>& lhs, ChunkedTypedArray<T>& rhs) noexcept {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TypedArray Factory Functions
|
||||
// TypedArray Convenience Functions
|
||||
// ============================================================================
|
||||
// These factory functions provide clearer, more intuitive interfaces for
|
||||
// creating TypedArray instances for common use cases: ownership, deduplication,
|
||||
// memory-mapping, and views.
|
||||
//
|
||||
// Benefits:
|
||||
// - Self-documenting: Function names clearly indicate intent
|
||||
// - Type-safe: No confusing boolean flag parameters
|
||||
// - Zero overhead: All inline, same performance as direct constructors
|
||||
// - Backward compatible: Existing code continues to work
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TypedArray Factory Functions (Smart Pointer Wrapper)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Create TypedArray for owned array (will be deleted by TypedArray)
|
||||
/// Use this when TypedArray should manage the lifetime of the implementation.
|
||||
///
|
||||
/// Example:
|
||||
/// auto* impl = new TypedArray<float>(100);
|
||||
/// TypedArray<float> arr = MakeOwnedTypedArray(impl);
|
||||
/// // arr will delete impl when destroyed
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> MakeOwnedTypedArray(TypedArray<T>* ptr) {
|
||||
return TypedArray<T>(ptr, false); // dedup_flag = false: will delete
|
||||
}
|
||||
|
||||
///
|
||||
/// Create TypedArray for deduplicated array (shared, won't be deleted)
|
||||
/// Use this when the array is shared/cached and managed elsewhere.
|
||||
///
|
||||
/// Example:
|
||||
/// // Array is stored in dedup cache
|
||||
/// auto it = _dedup_float_array.find(value_rep);
|
||||
/// TypedArray<float> arr = MakeDedupTypedArray(it->second.get());
|
||||
/// // arr won't delete the cached array
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> MakeDedupTypedArray(TypedArray<T>* ptr) {
|
||||
return TypedArray<T>(ptr, true); // dedup_flag = true: won't delete
|
||||
}
|
||||
|
||||
///
|
||||
/// Create TypedArray for shared array (alias for MakeDedupTypedArray)
|
||||
/// Use this when the array is shared among multiple owners.
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> MakeSharedTypedArray(TypedArray<T>* ptr) {
|
||||
return TypedArray<T>(ptr, true); // dedup_flag = true: won't delete
|
||||
}
|
||||
|
||||
///
|
||||
/// Create TypedArray for memory-mapped array (non-owning, won't be deleted)
|
||||
/// Use this for arrays backed by mmap'd files or external memory.
|
||||
///
|
||||
/// Example:
|
||||
/// float* mmap_data = static_cast<float*>(mmap_ptr);
|
||||
/// auto* impl = new TypedArray<float>(mmap_data, count, true);
|
||||
/// TypedArray<float> arr = MakeMmapTypedArray(impl);
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> MakeMmapTypedArray(TypedArray<T>* ptr) {
|
||||
return TypedArray<T>(ptr, true); // dedup_flag = true: won't delete
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TypedArray Factory Functions (Array Implementation)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Create TypedArray with owned copy of data
|
||||
@@ -2369,94 +2299,16 @@ inline TypedArray<T> MakeTypedArrayReserved(size_t capacity) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Combined Convenience Functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Create owned TypedArray from data copy
|
||||
/// Combines allocation, copy, and wrapping in one call.
|
||||
///
|
||||
/// Example:
|
||||
/// float data[] = {1.0f, 2.0f, 3.0f};
|
||||
/// TypedArray<float> arr = CreateOwnedTypedArray(data, 3);
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> CreateOwnedTypedArray(const T* data, size_t count) {
|
||||
auto* impl = new TypedArray<T>(data, count);
|
||||
return MakeOwnedTypedArray(impl);
|
||||
}
|
||||
|
||||
///
|
||||
/// Create owned TypedArray with specified size (uninitialized)
|
||||
/// Allocates array with given size, elements are uninitialized.
|
||||
///
|
||||
/// Example:
|
||||
/// TypedArray<int> arr = CreateOwnedTypedArray<int>(100);
|
||||
/// for (size_t i = 0; i < arr.size(); ++i) {
|
||||
/// arr[i] = static_cast<int>(i);
|
||||
/// }
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> CreateOwnedTypedArray(size_t count) {
|
||||
auto* impl = new TypedArray<T>(count);
|
||||
return MakeOwnedTypedArray(impl);
|
||||
}
|
||||
|
||||
///
|
||||
/// Create owned TypedArray with specified size and default value
|
||||
/// Allocates and initializes all elements with the given value.
|
||||
///
|
||||
/// Example:
|
||||
/// TypedArray<float> arr = CreateOwnedTypedArray<float>(100, 1.0f);
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> CreateOwnedTypedArray(size_t count, const T& value) {
|
||||
auto* impl = new TypedArray<T>(count, value);
|
||||
return MakeOwnedTypedArray(impl);
|
||||
}
|
||||
|
||||
///
|
||||
/// Create deduplicated TypedArray from existing implementation pointer
|
||||
/// Use this when storing in deduplication cache.
|
||||
///
|
||||
/// Example:
|
||||
/// TypedArray<int32_t>& cached = _dedup_int32_array[value_rep];
|
||||
/// TypedArray<int32_t> arr = CreateDedupTypedArray(&cached);
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> CreateDedupTypedArray(TypedArray<T>* ptr) {
|
||||
return MakeDedupTypedArray(ptr);
|
||||
}
|
||||
|
||||
///
|
||||
/// Create mmap TypedArray over external memory
|
||||
/// Combines view creation and wrapping for mmap use cases.
|
||||
///
|
||||
/// Example:
|
||||
/// float* mmap_data = static_cast<float*>(mmap_ptr);
|
||||
/// TypedArray<float> arr = CreateMmapTypedArray(mmap_data, count);
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> CreateMmapTypedArray(T* data, size_t count) {
|
||||
auto* impl = new TypedArray<T>(data, count, true); // View mode
|
||||
return MakeMmapTypedArray(impl);
|
||||
}
|
||||
|
||||
///
|
||||
/// Deep copy an existing TypedArray
|
||||
/// Creates a new independent copy with its own storage.
|
||||
///
|
||||
/// Deep copy a TypedArray
|
||||
/// Creates a new implementation with copied data.
|
||||
///
|
||||
/// Example:
|
||||
/// TypedArray<float> original = ...;
|
||||
/// TypedArray<float> copy = DuplicateTypedArray(original);
|
||||
///
|
||||
template <typename T>
|
||||
inline TypedArray<T> DuplicateTypedArray(
|
||||
const TypedArray<T>& source) {
|
||||
inline TypedArray<T> DuplicateTypedArray(const TypedArray<T>& source) {
|
||||
if (source.empty()) {
|
||||
return TypedArray<T>();
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
# Makefile for TypedArray Factory Functions Tests
|
||||
# Standalone test that can be built without CMake
|
||||
|
||||
CXX = g++-13
|
||||
CXXFLAGS = -std=c++17 -Wall -Wextra -O2 -g
|
||||
INCLUDES = -I../../../src
|
||||
|
||||
# Source files
|
||||
TEST_SRC = test-typed-array-factories.cc
|
||||
TEST_BIN = test-typed-array-factories
|
||||
|
||||
# Build target
|
||||
all: $(TEST_BIN)
|
||||
|
||||
$(TEST_BIN): $(TEST_SRC)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(TEST_SRC) -o $(TEST_BIN)
|
||||
@echo "Built: $(TEST_BIN)"
|
||||
|
||||
# Run tests
|
||||
test: $(TEST_BIN)
|
||||
@echo "Running factory function tests..."
|
||||
./$(TEST_BIN)
|
||||
|
||||
# Run with verbose output
|
||||
test-verbose: $(TEST_BIN)
|
||||
@echo "Running factory function tests (verbose)..."
|
||||
./$(TEST_BIN) -v
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -f $(TEST_BIN) *.o
|
||||
|
||||
# Help target
|
||||
help:
|
||||
@echo "TypedArray Factory Functions Test Makefile"
|
||||
@echo ""
|
||||
@echo "Targets:"
|
||||
@echo " all - Build test executable (default)"
|
||||
@echo " test - Build and run tests"
|
||||
@echo " test-verbose - Build and run tests with verbose output"
|
||||
@echo " clean - Remove build artifacts"
|
||||
@echo " help - Show this help message"
|
||||
@echo ""
|
||||
@echo "Example usage:"
|
||||
@echo " make # Build"
|
||||
@echo " make test # Build and run"
|
||||
@echo " make clean # Clean up"
|
||||
|
||||
.PHONY: all test test-verbose clean help
|
||||
@@ -1,185 +0,0 @@
|
||||
# TypedArray Factory Functions Test
|
||||
|
||||
This test verifies the TypedArray factory functions that provide clearer, more intuitive interfaces for creating TypedArray instances.
|
||||
|
||||
## Overview
|
||||
|
||||
The factory functions provide self-documenting alternatives to the boolean flag constructors:
|
||||
|
||||
### Before (Confusing)
|
||||
```cpp
|
||||
TypedArray<T>(ptr, true); // ❌ What does 'true' mean?
|
||||
```
|
||||
|
||||
### After (Clear)
|
||||
```cpp
|
||||
MakeDedupTypedArray(ptr); // ✅ Clear: deduplicated array
|
||||
```
|
||||
|
||||
## Factory Functions Tested
|
||||
|
||||
### TypedArray Wrappers (4 functions)
|
||||
- `MakeOwnedTypedArray()` - Owned array (will delete)
|
||||
- `MakeDedupTypedArray()` - Deduplicated array (won't delete)
|
||||
- `MakeSharedTypedArray()` - Shared array (won't delete)
|
||||
- `MakeMmapTypedArray()` - Memory-mapped array (won't delete)
|
||||
|
||||
### TypedArrayImpl Creation (4 functions)
|
||||
- `MakeTypedArrayCopy()` - Copy data into owned storage
|
||||
- `MakeTypedArrayView()` - Non-owning view over external memory
|
||||
- `MakeTypedArrayMmap()` - Non-owning view for mmap data
|
||||
- `MakeTypedArrayReserved()` - Empty array with reserved capacity
|
||||
|
||||
### Convenience Functions (7 functions)
|
||||
- `CreateOwnedTypedArray()` - 3 overloads for creating owned arrays
|
||||
- `CreateDedupTypedArray()` - Wrap as deduplicated
|
||||
- `CreateMmapTypedArray()` - Create mmap in one call
|
||||
- `DuplicateTypedArray()` - Deep copy TypedArray
|
||||
- `DuplicateTypedArrayImpl()` - Deep copy TypedArrayImpl
|
||||
|
||||
## Building
|
||||
|
||||
### Using Make (Standalone)
|
||||
|
||||
```bash
|
||||
# Build
|
||||
make
|
||||
|
||||
# Build and run tests
|
||||
make test
|
||||
|
||||
# Clean
|
||||
make clean
|
||||
```
|
||||
|
||||
### Manual Compilation
|
||||
|
||||
```bash
|
||||
g++-13 -std=c++17 -I../../../src test-typed-array-factories.cc -o test-typed-array-factories
|
||||
./test-typed-array-factories
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
The test suite includes:
|
||||
|
||||
1. **Ownership Tests**
|
||||
- Verify owned arrays delete on destruction
|
||||
- Verify dedup arrays don't delete on destruction
|
||||
- Verify dedup flag is set correctly
|
||||
|
||||
2. **Data Integrity Tests**
|
||||
- Verify data is copied correctly
|
||||
- Verify views reference original data
|
||||
- Verify modifications affect/don't affect original
|
||||
|
||||
3. **View Tests**
|
||||
- Verify view mode is set correctly
|
||||
- Verify views don't own memory
|
||||
- Verify modifications through views work
|
||||
|
||||
4. **Convenience Function Tests**
|
||||
- Verify combined operations work correctly
|
||||
- Verify duplication creates independent copies
|
||||
|
||||
5. **Real-World Pattern Tests**
|
||||
- Deduplication cache pattern
|
||||
- Memory-mapped file pattern
|
||||
- Temporary view pattern
|
||||
|
||||
## Expected Output
|
||||
|
||||
```
|
||||
Testing TypedArray Factory Functions
|
||||
|
||||
Testing MakeOwnedTypedArray... ✓ PASS
|
||||
Testing MakeDedupTypedArray... ✓ PASS
|
||||
Testing MakeSharedTypedArray... ✓ PASS
|
||||
Testing MakeMmapTypedArray... ✓ PASS
|
||||
Testing MakeTypedArrayCopy... ✓ PASS
|
||||
Testing MakeTypedArrayView... ✓ PASS
|
||||
Testing MakeTypedArrayMmap... ✓ PASS
|
||||
Testing MakeTypedArrayReserved... ✓ PASS
|
||||
Testing CreateOwnedTypedArray_data... ✓ PASS
|
||||
Testing CreateOwnedTypedArray_size... ✓ PASS
|
||||
Testing CreateOwnedTypedArray_value... ✓ PASS
|
||||
Testing CreateDedupTypedArray... ✓ PASS
|
||||
Testing CreateMmapTypedArray... ✓ PASS
|
||||
Testing DuplicateTypedArray... ✓ PASS
|
||||
Testing DuplicateTypedArrayImpl... ✓ PASS
|
||||
Testing deduplication_pattern... ✓ PASS
|
||||
|
||||
----------------------------------------
|
||||
Total: 16 tests
|
||||
Passed: 16
|
||||
Failed: 0
|
||||
|
||||
✓ All tests passed!
|
||||
```
|
||||
|
||||
## Implementation Location
|
||||
|
||||
The factory functions are implemented in:
|
||||
- **File**: `src/typed-array.hh`
|
||||
- **Lines**: 2376-2614
|
||||
- **Functions**: 15 factory functions
|
||||
|
||||
## Documentation
|
||||
|
||||
Complete documentation available in `doc/`:
|
||||
- `FACTORY_FUNCTIONS_INTEGRATION.md` - Integration summary
|
||||
- `TYPED_ARRAY_FACTORY_PROPOSAL.md` - Detailed proposal
|
||||
- `TYPED_ARRAY_MIGRATION_EXAMPLES.md` - Before/after examples
|
||||
- `TYPED_ARRAY_ARCHITECTURE.md` - Architecture details
|
||||
- `TYPED_ARRAY_API_SUMMARY.md` - Quick reference
|
||||
|
||||
## Requirements
|
||||
|
||||
- C++14 compiler (tested with g++-13)
|
||||
- No external dependencies beyond standard library
|
||||
- Header-only implementation (zero runtime overhead)
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Self-Documenting** - Function names clearly indicate intent
|
||||
✅ **Type-Safe** - No confusing boolean flags
|
||||
✅ **Zero Overhead** - All inline, same performance
|
||||
✅ **Backward Compatible** - Existing code still works
|
||||
✅ **Easy Migration** - Can adopt gradually
|
||||
|
||||
## Common Usage Patterns
|
||||
|
||||
### Deduplication Cache
|
||||
```cpp
|
||||
auto it = _dedup_float_array.find(value_rep);
|
||||
if (it != _dedup_float_array.end()) {
|
||||
return MakeDedupTypedArray(it->second.get());
|
||||
} else {
|
||||
auto* impl = new TypedArrayImpl<float>(data, size);
|
||||
_dedup_float_array[value_rep] = MakeOwnedTypedArray(impl);
|
||||
return MakeDedupTypedArray(impl);
|
||||
}
|
||||
```
|
||||
|
||||
### Memory-Mapped Files
|
||||
```cpp
|
||||
float* mmap_data = static_cast<float*>(mmap_ptr);
|
||||
TypedArray<float> arr = CreateMmapTypedArray(mmap_data, count);
|
||||
// arr doesn't own mmap_data, just references it
|
||||
```
|
||||
|
||||
### Temporary Views
|
||||
```cpp
|
||||
float buffer[1000];
|
||||
PopulateBuffer(buffer);
|
||||
auto view = MakeTypedArrayView(buffer, 1000);
|
||||
ProcessData(view);
|
||||
// buffer still valid after view destruction
|
||||
```
|
||||
|
||||
## Test Status
|
||||
|
||||
- **Status**: ✅ All 16 tests passing
|
||||
- **Last Updated**: 2025-01-09
|
||||
- **Compiler**: g++-13
|
||||
- **Standard**: C++14
|
||||
@@ -1,420 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright 2025 - Present, Light Transport Entertainment Inc.
|
||||
//
|
||||
// Test TypedArray factory functions
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include "../../../src/typed-array.hh"
|
||||
|
||||
using namespace tinyusdz;
|
||||
|
||||
// Helper function to check test results
|
||||
#define TEST(name) \
|
||||
std::cout << "Testing " << #name << "... "; \
|
||||
if (test_##name()) { \
|
||||
std::cout << "✓ PASS" << std::endl; \
|
||||
passed++; \
|
||||
} else { \
|
||||
std::cout << "✗ FAIL" << std::endl; \
|
||||
failed++; \
|
||||
}
|
||||
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
// Test MakeOwnedTypedArray
|
||||
bool test_MakeOwnedTypedArray() {
|
||||
auto* impl = new TypedArrayImpl<float>(10);
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
(*impl)[i] = static_cast<float>(i);
|
||||
}
|
||||
|
||||
TypedArray<float> owned = MakeOwnedTypedArray(impl);
|
||||
|
||||
// Check ownership flag
|
||||
if (owned.is_dedup()) return false;
|
||||
|
||||
// Check data
|
||||
if (owned.size() != 10) return false;
|
||||
if (owned[0] != 0.0f) return false;
|
||||
if (owned[9] != 9.0f) return false;
|
||||
|
||||
// owned will delete impl on destruction
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeDedupTypedArray
|
||||
bool test_MakeDedupTypedArray() {
|
||||
auto* impl = new TypedArrayImpl<int>(20);
|
||||
for (size_t i = 0; i < 20; ++i) {
|
||||
(*impl)[i] = static_cast<int>(i * 2);
|
||||
}
|
||||
|
||||
TypedArray<int> dedup = MakeDedupTypedArray(impl);
|
||||
|
||||
// Check dedup flag
|
||||
if (!dedup.is_dedup()) return false;
|
||||
|
||||
// Check data
|
||||
if (dedup.size() != 20) return false;
|
||||
if (dedup[0] != 0) return false;
|
||||
if (dedup[10] != 20) return false;
|
||||
|
||||
// Need to manually delete since dedup won't delete it
|
||||
delete impl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeSharedTypedArray
|
||||
bool test_MakeSharedTypedArray() {
|
||||
auto* impl = new TypedArrayImpl<double>(15);
|
||||
for (size_t i = 0; i < 15; ++i) {
|
||||
(*impl)[i] = static_cast<double>(i) * 1.5;
|
||||
}
|
||||
|
||||
TypedArray<double> shared = MakeSharedTypedArray(impl);
|
||||
|
||||
// Check dedup flag (shared is same as dedup)
|
||||
if (!shared.is_dedup()) return false;
|
||||
|
||||
// Check data
|
||||
if (shared.size() != 15) return false;
|
||||
if (shared[0] != 0.0) return false;
|
||||
if (shared[10] != 15.0) return false;
|
||||
|
||||
// Need to manually delete
|
||||
delete impl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeMmapTypedArray
|
||||
bool test_MakeMmapTypedArray() {
|
||||
float mmap_buffer[100];
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
mmap_buffer[i] = static_cast<float>(i);
|
||||
}
|
||||
|
||||
auto* impl = new TypedArrayImpl<float>(mmap_buffer, 100, true);
|
||||
TypedArray<float> mmap_arr = MakeMmapTypedArray(impl);
|
||||
|
||||
// Check dedup flag
|
||||
if (!mmap_arr.is_dedup()) return false;
|
||||
|
||||
// Check it's a view
|
||||
if (!impl->is_view()) return false;
|
||||
|
||||
// Check data
|
||||
if (mmap_arr.size() != 100) return false;
|
||||
if (mmap_arr[0] != 0.0f) return false;
|
||||
if (mmap_arr[99] != 99.0f) return false;
|
||||
|
||||
// Modify original buffer
|
||||
mmap_buffer[50] = 999.0f;
|
||||
if (mmap_arr[50] != 999.0f) return false;
|
||||
|
||||
delete impl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeTypedArrayCopy
|
||||
bool test_MakeTypedArrayCopy() {
|
||||
int data[] = {1, 2, 3, 4, 5};
|
||||
auto copy = MakeTypedArrayCopy(data, 5);
|
||||
|
||||
// Check data was copied
|
||||
if (copy.size() != 5) return false;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
if (copy[i] != data[i]) return false;
|
||||
}
|
||||
|
||||
// Modify copy - should not affect original
|
||||
copy[0] = 999;
|
||||
if (data[0] != 1) return false;
|
||||
if (copy[0] != 999) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeTypedArrayView
|
||||
bool test_MakeTypedArrayView() {
|
||||
double buffer[50];
|
||||
for (size_t i = 0; i < 50; ++i) {
|
||||
buffer[i] = static_cast<double>(i) * 2.0;
|
||||
}
|
||||
|
||||
auto view = MakeTypedArrayView(buffer, 50);
|
||||
|
||||
// Check it's a view
|
||||
if (!view.is_view()) return false;
|
||||
|
||||
// Check data
|
||||
if (view.size() != 50) return false;
|
||||
if (view[0] != 0.0) return false;
|
||||
if (view[25] != 50.0) return false;
|
||||
|
||||
// Modify through view - should affect original
|
||||
view[10] = 999.0;
|
||||
if (buffer[10] != 999.0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeTypedArrayMmap
|
||||
bool test_MakeTypedArrayMmap() {
|
||||
float mmap_buffer[75];
|
||||
for (size_t i = 0; i < 75; ++i) {
|
||||
mmap_buffer[i] = static_cast<float>(i);
|
||||
}
|
||||
|
||||
auto mmap_view = MakeTypedArrayMmap(mmap_buffer, 75);
|
||||
|
||||
// Check it's a view
|
||||
if (!mmap_view.is_view()) return false;
|
||||
|
||||
// Check data
|
||||
if (mmap_view.size() != 75) return false;
|
||||
if (mmap_view[0] != 0.0f) return false;
|
||||
if (mmap_view[74] != 74.0f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MakeTypedArrayReserved
|
||||
bool test_MakeTypedArrayReserved() {
|
||||
auto reserved = MakeTypedArrayReserved<float>(1000);
|
||||
|
||||
// Check capacity
|
||||
if (reserved.capacity() < 1000) return false;
|
||||
|
||||
// Check initially empty
|
||||
if (reserved.size() != 0) return false;
|
||||
|
||||
// Add some elements
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
reserved.push_back(static_cast<float>(i));
|
||||
}
|
||||
|
||||
if (reserved.size() != 10) return false;
|
||||
if (reserved[5] != 5.0f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test CreateOwnedTypedArray (from data)
|
||||
bool test_CreateOwnedTypedArray_data() {
|
||||
float src[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
|
||||
auto owned = CreateOwnedTypedArray(src, 5);
|
||||
|
||||
// Check ownership
|
||||
if (owned.is_dedup()) return false;
|
||||
|
||||
// Check data
|
||||
if (owned.size() != 5) return false;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
if (owned[i] != src[i]) return false;
|
||||
}
|
||||
|
||||
// Modify owned - should not affect original
|
||||
owned[0] = 999.0f;
|
||||
if (src[0] != 1.0f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test CreateOwnedTypedArray (with size)
|
||||
bool test_CreateOwnedTypedArray_size() {
|
||||
auto owned = CreateOwnedTypedArray<int>(100);
|
||||
|
||||
// Check ownership
|
||||
if (owned.is_dedup()) return false;
|
||||
|
||||
// Check size
|
||||
if (owned.size() != 100) return false;
|
||||
|
||||
// Initialize and check
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
owned[i] = static_cast<int>(i);
|
||||
}
|
||||
if (owned[50] != 50) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test CreateOwnedTypedArray (with size and value)
|
||||
bool test_CreateOwnedTypedArray_value() {
|
||||
auto owned = CreateOwnedTypedArray<double>(50, 3.14);
|
||||
|
||||
// Check ownership
|
||||
if (owned.is_dedup()) return false;
|
||||
|
||||
// Check size
|
||||
if (owned.size() != 50) return false;
|
||||
|
||||
// Check all values
|
||||
for (size_t i = 0; i < 50; ++i) {
|
||||
if (owned[i] != 3.14) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test CreateDedupTypedArray
|
||||
bool test_CreateDedupTypedArray() {
|
||||
TypedArrayImpl<float> impl_stack(10);
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
impl_stack[i] = static_cast<float>(i) * 0.5f;
|
||||
}
|
||||
|
||||
auto dedup = CreateDedupTypedArray(&impl_stack);
|
||||
|
||||
// Check dedup flag
|
||||
if (!dedup.is_dedup()) return false;
|
||||
|
||||
// Check data
|
||||
if (dedup.size() != 10) return false;
|
||||
if (dedup[5] != 2.5f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test CreateMmapTypedArray
|
||||
bool test_CreateMmapTypedArray() {
|
||||
float mmap_buffer[200];
|
||||
for (size_t i = 0; i < 200; ++i) {
|
||||
mmap_buffer[i] = static_cast<float>(i);
|
||||
}
|
||||
|
||||
auto mmap = CreateMmapTypedArray(mmap_buffer, 200);
|
||||
|
||||
// Check dedup flag (mmap arrays are marked as dedup)
|
||||
if (!mmap.is_dedup()) return false;
|
||||
|
||||
// Check data
|
||||
if (mmap.size() != 200) return false;
|
||||
if (mmap[100] != 100.0f) return false;
|
||||
|
||||
// Modify original
|
||||
mmap_buffer[150] = 999.0f;
|
||||
if (mmap[150] != 999.0f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test DuplicateTypedArray
|
||||
bool test_DuplicateTypedArray() {
|
||||
float data[] = {1.0f, 2.0f, 3.0f};
|
||||
auto original = CreateOwnedTypedArray(data, 3);
|
||||
|
||||
auto copy = DuplicateTypedArray(original);
|
||||
|
||||
// Check ownership
|
||||
if (copy.is_dedup()) return false;
|
||||
|
||||
// Check data copied
|
||||
if (copy.size() != 3) return false;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (copy[i] != original[i]) return false;
|
||||
}
|
||||
|
||||
// Modify copy - should not affect original
|
||||
copy[0] = 999.0f;
|
||||
if (original[0] != 1.0f) return false;
|
||||
if (copy[0] != 999.0f) return false;
|
||||
|
||||
// Check they're independent
|
||||
if (copy.data() == original.data()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test DuplicateTypedArrayImpl
|
||||
bool test_DuplicateTypedArrayImpl() {
|
||||
TypedArrayImpl<int> original(10);
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
original[i] = static_cast<int>(i);
|
||||
}
|
||||
|
||||
auto copy = DuplicateTypedArrayImpl(original);
|
||||
|
||||
// Check data copied
|
||||
if (copy.size() != 10) return false;
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
if (copy[i] != original[i]) return false;
|
||||
}
|
||||
|
||||
// Modify copy - should not affect original
|
||||
copy[5] = 999;
|
||||
if (original[5] != 5) return false;
|
||||
if (copy[5] != 999) return false;
|
||||
|
||||
// Check they're independent
|
||||
if (copy.data() == original.data()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test deduplication use case
|
||||
bool test_deduplication_pattern() {
|
||||
// Simulate deduplication cache
|
||||
TypedArrayImpl<float>* cached_impl = new TypedArrayImpl<float>(5);
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
(*cached_impl)[i] = static_cast<float>(i);
|
||||
}
|
||||
|
||||
// Store in cache as owned
|
||||
TypedArray<float> cache_entry = MakeOwnedTypedArray(cached_impl);
|
||||
|
||||
// Return deduplicated reference (won't delete)
|
||||
TypedArray<float> dedup_ref = MakeDedupTypedArray(cached_impl);
|
||||
|
||||
// Check both point to same data
|
||||
if (cache_entry.data() != dedup_ref.data()) return false;
|
||||
|
||||
// Check dedup ref won't delete
|
||||
if (!dedup_ref.is_dedup()) return false;
|
||||
|
||||
// Check cache entry will delete
|
||||
if (cache_entry.is_dedup()) return false;
|
||||
|
||||
// cache_entry will delete cached_impl on destruction
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Testing TypedArray Factory Functions\n" << std::endl;
|
||||
|
||||
// Test factory functions
|
||||
TEST(MakeOwnedTypedArray);
|
||||
TEST(MakeDedupTypedArray);
|
||||
TEST(MakeSharedTypedArray);
|
||||
TEST(MakeMmapTypedArray);
|
||||
TEST(MakeTypedArrayCopy);
|
||||
TEST(MakeTypedArrayView);
|
||||
TEST(MakeTypedArrayMmap);
|
||||
TEST(MakeTypedArrayReserved);
|
||||
TEST(CreateOwnedTypedArray_data);
|
||||
TEST(CreateOwnedTypedArray_size);
|
||||
TEST(CreateOwnedTypedArray_value);
|
||||
TEST(CreateDedupTypedArray);
|
||||
TEST(CreateMmapTypedArray);
|
||||
TEST(DuplicateTypedArray);
|
||||
TEST(DuplicateTypedArrayImpl);
|
||||
TEST(deduplication_pattern);
|
||||
|
||||
std::cout << "\n----------------------------------------" << std::endl;
|
||||
std::cout << "Total: " << (passed + failed) << " tests" << std::endl;
|
||||
std::cout << "Passed: " << passed << std::endl;
|
||||
std::cout << "Failed: " << failed << std::endl;
|
||||
|
||||
if (failed == 0) {
|
||||
std::cout << "\n✓ All tests passed!" << std::endl;
|
||||
return 0;
|
||||
} else {
|
||||
std::cout << "\n✗ Some tests failed!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user