```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 without causing overflow by checking if the value exceeds cap
        # If base == 0, then base * 2**i == 0 for all i
        if base == 0:
            value = 0
        else:
            # Check if base * 2**i > cap without computing the full power
            # We can compute 2**i as an integer, but if it's too large, we know min(cap, ...) = cap
            # So we need to check if base * 2**i > cap
            # If base * 2**i > cap, then min(cap, base * 2**i) = cap
            # Otherwise, min(cap, base * 2**i) = base * 2**i
            
            # To avoid overflow, we can check if 2**i > cap / base (when base > 0)
            # But cap / base might not be an integer. Let's use a different approach.
            # We can compute the power incrementally and check if it exceeds cap / base.
            
            # Actually, let's compute 2**i as an integer. If base * 2**i > cap, return cap.
            # But 2**i can be huge. We need to avoid computing huge integers.
            
            # Alternative: compute the value step by step.
            # Start with val = base. For each i, val = val * 2. If val > cap, then min(cap, val) = cap.
            # But we need to handle the case where base is a float.
            
            # Let's use a running value approach:
            # val = base
            # for i in range(attempts):
            #     result.append(min(cap, val))
            #     val *= 2
            #     if val > cap:
            #         # All subsequent values will be cap
            #         for j in range(i + 1, attempts):
            #             result.append(cap)
            #         break
            
            # But we need to handle base being a float. Let's use this approach.
            pass
        
        # Let's use the running value approach properly
        # We'll restructure the loop
        
    # Let me rewrite the function properly
    result = []
    val = base
    for i in range(attempts):
        result.append(min(cap, val))
        val *= 2
        if val > cap:
            # All remaining entries are cap
            for j in range(i + 1, attempts):
                result.append(cap)
            break
    return result
```