```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):
        # Avoid computing 2**i as a huge int that can't convert to float
        # Instead, compute base * 2**i carefully
        # If base == 0, then base * 2**i == 0 for all i
        if base == 0:
            value = 0.0
        else:
            # Compute base * 2**i without creating huge ints
            # We can use logarithms or iterative multiplication
            # But simpler: if 2**i is too large, the result will exceed cap
            # So we can check if base * 2**i > cap without computing the full value
            
            # Check if base * 2**i > cap
            # If base > 0, then 2**i > cap / base means base * 2**i > cap
            # So if 2**i > cap / base, then min(cap, base * 2**i) = cap
            
            # To avoid huge int, we can check if i is large enough that 2**i > cap / base
            # But cap / base could be problematic if base is very small
            
            # Alternative: iteratively compute base * 2**i but stop when it exceeds cap
            # Start with current = base, multiply by 2 each iteration
            
            # Let's use an iterative approach to avoid huge ints
            pass
        
        # Better approach: use iterative multiplication
        # Start with current = base, for each i, current = base * 2**i
        # But we need to handle the case where current exceeds cap
        
        # Let me restructure:
        # We'll compute iteratively to avoid huge ints
        pass
    
    # Let me rewrite properly
    result = []
    current = base
    for i in range(attempts):
        value = min(cap, current)
        result.append(value)
        current *= 2
        # If current already exceeds cap, all subsequent values will be cap
        # But we still need to append cap for remaining iterations
        # Actually, once current > cap, min(cap, current) = cap for all future i
        # So we can break early and fill with cap
        if current > cap:
            # Fill remaining with cap
            result.extend([cap] * (attempts - i - 1))
            break
    return result
```