GetDateCollectionLength

Retrieve the current number of date items in a date collection

Overview

GetDateCollectionLength returns the current count of date items stored in a date collection handle. This function provides thread-safe access to the collection's length by acquiring the internal mutex and reading the length field.

Purpose

Get the actual number of date items currently in a collection. This is useful for:

Key Features

Function Signature


DWORD _Check_return_ _On_failure_(return > DATE_LOG_MAX) GetDateCollectionLength(
    _In_ DATE_COLLECTION_HANDLE hDateCollection
);
            

Calling Convention

Standard C calling convention with SAL annotations for parameter and return value validation.

SAL Annotations


_Check_return_ : Caller must check the return value; ignoring it may lead to processing invalid data
_On_failure_(return > DATE_LOG_MAX) : On failure, return value will exceed DATE_LOG_MAX (0x00000000 to 0x001388 range)
                

Parameters

hDateCollection

[In] DATE_COLLECTION_HANDLE

A handle to a date collection previously created via one of the initialization functions.

  • Must be a valid DATE_COLLECTION_HANDLE (DATE_LOG_HANDLE, DATE_RANGE_HANDLE, or HOLIDAYS_HANDLE)
  • Must not be NULL
  • Must have been created and not yet closed/freed
  • Precondition: Must be pre-validated by IsValidDateLogHandle()

Return Values

Success Case

0 to DATE_LOG_MAX (0x00000000 to 0x00001388)

Returns the actual number of date items in the collection. Range is 0 (empty collection) through DATE_LOG_MAX (5000 items maximum). A value of 0 indicates an empty collection, which is valid.

Error Case

DATE_LOG_SENTINEL (0x00845698)

Indicates an error occurred. Possible error conditions:

Return Value Semantics

Return Value Meaning Action
0x00000000 Empty collection (valid) No items; handle is valid but unpopulated
1 to 0x001388 Collection size (valid) Normal operation; collection contains this many items
0x00845698 ERROR_SENTINEL (error) Do not use returned value; close handle and retry
Any other value Data corruption detected Indicates memory corruption; handle state is unreliable

Checking Return Values


// Pattern 1: Simple validity check
DWORD dwLength = GetDateCollectionLength(hCollection);
if (dwLength == DATE_LOG_SENTINEL) {
    // Error occurred
    printf("Failed to get collection length\n");
    // Close handle and retry
} else if (dwLength == 0) {
    // Empty collection (valid)
    printf("Collection is empty\n");
} else {
    // Valid collection with dwLength items
    printf("Collection has %u items\n", dwLength);
}

// Pattern 2: Loop processing
DWORD dwMaxLen = GetDateCollectionMaximumLength(hCollection);
DWORD dwLen = GetDateCollectionLength(hCollection);
if (dwLen != DATE_LOG_SENTINEL && dwMaxLen != DATE_LOG_SENTINEL) {
    printf("Utilization: %u of %u (%.1f%%)\n", 
        dwLen, dwMaxLen, (100.0 * dwLen) / dwMaxLen);
}
            

Behavior and Operations

Execution Flow

Validate Handle
Acquire Mutex
Read Length
Release Mutex

Step-by-Step Operation

  1. Handle Validation:
    Calls IsValidDateLogHandle(hDateCollection) to verify:
    • Handle pointer is not NULL
    • Handle magic number is valid (not marked invalid)
    • Handle context is not NULL
    • Handle type matches expected enum value
  2. Early Exit on Invalid Handle:
    If validation fails, immediately returns DATE_LOG_SENTINEL
  3. Context Extraction:
    Casts handle to PDATE_LOG and retrieves the core handle from pContext->hDateLogCore
  4. Delegate to Core Getter:
    Calls GetDateLogCoreLength() which:
    • Re-validates the core pointer
    • Acquires the core's mutex with 5-second timeout
    • Reads the dwLength field inside the mutex
    • Releases the mutex
  5. Return Result:
    Returns the length value or DATE_LOG_SENTINEL if any step fails

Thread Safety

The function is fully thread-safe:

Error Handling Flow


// Error conditions handled gracefully
if (IsValidDateLogHandle(hDateCollection) == FALSE)
    return DATE_LOG_SENTINEL;  // Handle is invalid

PDATE_LOG pDateLog = (PDATE_LOG)hDateCollection;
return GetDateLogCoreLength(pDateLog->pContext->hDateLogCore);

// GetDateLogCoreLength also checks:
// - IsValidDateLogCore(hDateLogCore) 
// - Mutex timeout
// - Mutex wait result
            

Usage Examples

Example 1: Simple Collection Size Check

#include "datelog.h"

DWORD dwLength = GetDateCollectionLength(hMyCollection);

if (dwLength == DATE_LOG_SENTINEL) {
    printf("ERROR: Failed to get collection length\n");
    goto error_cleanup;
}

if (dwLength == 0) {
    printf("Collection is empty\n");
} else {
    printf("Collection contains %u market dates\n", dwLength);
}

// ... continue processing ...

error_cleanup:
    CloseDateLogHandle(hMyCollection);
    return FALSE;
                
Example 2: Validation After Merge

// After merging two collections
HRESULT hr = MergeDateLogHandle(hDestLog, hSourceLog, 
                                DATE_RANGE_MERGE_FAVOR_SOURCE);

if (SUCCEEDED(hr)) {
    DWORD dwNewLength = GetDateCollectionLength(hDestLog);
    DWORD dwMaxLength = GetDateCollectionMaximumLength(hDestLog);
    
    if (dwNewLength != DATE_LOG_SENTINEL && 
        dwMaxLength != DATE_LOG_SENTINEL) {
        
        printf("Merge successful. Collection now has %u dates\n", dwNewLength);
        printf("Capacity utilization: %.1f%%\n", 
            (100.0 * dwNewLength) / dwMaxLength);
        
        // Verify merge didn't exceed capacity
        if (dwNewLength > dwMaxLength) {
            printf("ERROR: Length exceeds maximum!\n");
        }
    } else {
        printf("ERROR: Failed to verify merged collection state\n");
    }
}
                
Example 3: Iterating Over Collection Items

// Process each item in the collection
DWORD dwCount = GetDateCollectionLength(hCollection);

if (dwCount == DATE_LOG_SENTINEL) {
    printf("Invalid collection\n");
    return;
}

if (dwCount == 0) {
    printf("Collection is empty, nothing to process\n");
    return;
}

for (DWORD i = 0; i < dwCount; i++) {
    DATE_ITEM_HANDLE hItem = GetDateLogFirstDate(hCollection);
    if (hItem == NULL) {
        printf("Failed to get date item %u\n", i);
        break;
    }
    
    DATE_STRUCT date = {0};
    GetDateItemDate(hItem, &date);
    
    printf("Date %u: %04d-%02d-%02d\n", i, 
           date.year, date.month, date.day);
}
                
Example 4: Buffer Allocation Based on Collection Size

// Allocate buffer sized to collection
DWORD dwLength = GetDateCollectionLength(hCollection);

if (dwLength == DATE_LOG_SENTINEL || dwLength == 0) {
    printf("Cannot allocate buffer for empty/invalid collection\n");
    return NULL;
}

// Each date item is sizeof(DATE_STRUCT) bytes
SIZE_T cbBuffer = dwLength * sizeof(DATE_STRUCT);

PDATE_STRUCT pDates = (PDATE_STRUCT)malloc(cbBuffer);
if (pDates == NULL) {
    printf("Failed to allocate %zu bytes\n", cbBuffer);
    return NULL;
}

printf("Allocated %zu bytes for %u dates\n", cbBuffer, dwLength);
return pDates;
                

Thread Safety and Synchronization

Mutex Acquisition

Aspect Detail
Mutex Timeout 5 seconds (5000 milliseconds)
Lock Scope Only the dwLength field read
Lock Duration Minimal (~1-2 microseconds)
Deadlock Risk None—single lock acquisition

Concurrent Access Scenarios

Scenario 1: Concurrent Read
Multiple threads calling GetDateCollectionLength simultaneously will each acquire and release the mutex independently. No conflicts; all threads see consistent (though possibly different) values.
Scenario 2: Read During Merge
While MergeDateLogHandle holds locks for modification, a concurrent GetDateCollectionLength call will wait up to 5 seconds for the merge to complete. If merge takes longer than 5 seconds, GetDateCollectionLength returns DATE_LOG_SENTINEL.
Scenario 3: Timeout During Contention
If high thread contention causes mutex wait to exceed 5 seconds, the function returns DATE_LOG_SENTINEL rather than blocking indefinitely. Caller should handle this gracefully.

Visibility Guarantees

Important Notes and Considerations

Return Value Semantics

Empty Collections Are Valid:
A return value of 0 indicates an empty collection, which is a valid state. Do not treat this as an error. Compare the return value to DATE_LOG_SENTINEL to detect errors.
Sentinel vs. Error:
Always check return value == DATE_LOG_SENTINEL (0x00845698) to detect errors, not zero or any other value.

Related Functions

Performance Considerations

Common Pitfalls

Updates and Changes