Yul, solidity docs example (mstore & padding)

Im trying to understand this yul example of the solidity docs (https://docs.soliditylang.org/en/v0.8.17/assembly.html):

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

library GetCode {
    function at(address addr) public view returns (bytes memory code) {
        assembly {
            // retrieve the size of the code, this needs assembly
            let size := extcodesize(addr)
            // allocate output byte array - this could also be done without assembly
            // by using code = new bytes(size)
            code := mload(0x40)
            // new "memory end" including padding
            mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            // store length in memory
            mstore(code, size)
            // actually retrieve the code, this needs assembly
            extcodecopy(addr, add(code, 0x20), 0, size)

What is the idea behind and((..., 0x1f), not(0x1f)) and is it needed?

The expression is: (size + 0x20 + 0x1f) & ~0x1f

More generally (x + 0x1f) & ~0x1f is rounding the number x up to a multiple of 32 (= 0x1f + 1).

I'm not sure why it's doing this though. I can't think of a reason why you would want to round up to multiple of 32. Memory is byte-addressable.