```python
def retry_delays(attempts, base, cap):
    if isinstance(attempts, bool) or not isinstance(attempts, int):
        raise TypeError("attempts must be a non-negative integer")
    if attempts < 0:
        raise ValueError("attempts must be non-negative")
    if base < 0:
        raise ValueError("base must be non-negative")
    if cap < 0:
        raise ValueError("cap must be non-negative")
    
    result = []
    for i in range(attempts):
        # Compute base * 2**i carefully to avoid overflow
        # If base is 0, delay is 0
        if base == 0:
            delay = 0
        else:
            # Check if base * 2**i would exceed cap
            # We can compare using logarithms or incremental multiplication
            # To avoid overflow, we can check if 2**i * base > cap
            # Since cap is non-negative, if base * 2**i >= cap, use cap
            # We need to avoid computing 2**i as a huge int then converting to float
            
            # Use incremental approach: start with base, multiply by 2 each step
            # But we need to handle the case where base * 2**i might overflow float
            
            # Alternative: use math.log2 to check if base * 2**i > cap
            # But we can't import math (no third-party, but math is stdlib)
            # Actually, we can use math since it's stdlib
            
            # Let's use a safe approach:
            # If base == 0, delay = 0
            # Otherwise, compute value = base * (2 ** i)
            # But 2**i can be huge for large i, causing overflow when converting to float
            
            # We can check: if base * 2**i >= cap, then delay = cap
            # To avoid overflow, we can use logarithms:
            # base * 2**i >= cap  <=>  log2(base) + i >= log2(cap)
            # But base could be 0, handled separately
            
            # Simpler: use incremental multiplication with early termination
            # Start with current = base
            # For each i, if current >= cap, delay = cap
            # Otherwise, delay = current, then current *= 2
            
            # But we need to handle the case where current might overflow float
            # If current is already >= cap, we can just use cap
            
            # Let's implement incremental approach:
            current = base
            for i in range(attempts):
                if current >= cap:
                    delay = cap
                else:
                    delay = current
                    current = current * 2
                result.append(delay)
            return result
        
        result.append(delay)
    return result
```