def _size_columns(self, container):
        """Calculate the table's column sizes constrained by:

        - requested (absolute, relative and automatic) column widths
        - container width (= available width)
        - cell contents

        """
        def calculate_column_widths(max_cell_width):
            """Calculate required column widths given a maximum cell width"""
            def cell_content_width(cell):
                buffer = VirtualContainer(container, width=max_cell_width)
                width, _, _ = cell.flow(buffer, None)
                return float(width)

            widths = [0] * self.body.num_columns
            for row in chain(self.head or [], self.body):
                for cell in (cell for cell in row if cell.colspan == 1):
                    col = int(cell.column_index)
                    widths[col] = max(widths[col], cell_content_width(cell))
            for row in chain(self.head or [], self.body):
                for cell in (cell for cell in row if cell.colspan > 1):
                    c = int(cell.column_index)
                    c_end = c + cell.colspan
                    padding = cell_content_width(cell) - sum(widths[c:c_end])
                    if padding > 0:
                        per_column_padding = padding / cell.colspan
                        for i in range(cell.colspan):
                            widths[c + i] += per_column_padding
            return widths

        width = self._width(container)
        try:
            fixed_width = width.to_points(container.width)
        except AttributeError:
            fixed_width = width or FlowableWidth.AUTO
        min_column_widths = calculate_column_widths(0)
        max_column_widths = calculate_column_widths(float('+inf'))

        # calculate relative column widths for auto-sized columns
        auto_rel_colwidths = [sqrt(minimum * maximum) for minimum, maximum
                              in zip(min_column_widths, max_column_widths)]
        column_widths = self.column_widths or [None for _ in max_column_widths]
        try:          # TODO: max() instead of min()?
            relative_factor = min(auto_relative_width / width
                                  for width, auto_relative_width
                                  in zip(column_widths, auto_rel_colwidths)
                                  if width and not isinstance(width, DimBase))
        except ValueError:
            relative_factor = 1
        column_widths = [auto_relative_width * relative_factor
                         if width is None else width
                         for width, auto_relative_width
                         in zip(column_widths, auto_rel_colwidths)]

        # set min = max for columns with a fixed width
        total_fixed_cols_width = 0
        total_portions = 0
        for i, column_width in enumerate(column_widths):
            if isinstance(column_width, DimBase):
                width_in_pt = column_width.to_points(container.width)
                min_column_widths[i] = max_column_widths[i] = width_in_pt
                total_fixed_cols_width += width_in_pt
            else:
                total_portions += column_width

        # does the table fit within the available width without wrapping?
        if sum(max_column_widths) <= container.width:
            return max_column_widths

        # determine table width
        if fixed_width != FlowableWidth.AUTO:
            table_width = fixed_width
        elif total_portions:
            max_factor = max(maximum / width for width, maximum,
                             in zip(column_widths, max_column_widths)
                             if not isinstance(width, DimBase))
            no_wrap_rel_cols_width = total_portions * max_factor
            table_width = min(total_fixed_cols_width + no_wrap_rel_cols_width,
                              float(container.width))
        else:
            table_width = total_fixed_cols_width

        # TODO: warn when a column's fixed width < min width

        # determine absolute width of columns with relative widths
        if total_portions:
            total_relative_cols_width = table_width - total_fixed_cols_width
            portion_width = total_relative_cols_width / total_portions
            auto_widths = [width if isinstance(width, DimBase)
                           else width * portion_width
                           for width in column_widths]
            extra = [0 if isinstance(width, DimBase)
                     else auto_width - min_column_widths[index]
                     for index, auto_width in enumerate(auto_widths)]
            excess = [0 if isinstance(width, DimBase)
                      else auto_width - max_column_widths[index]
                      for index, auto_width in enumerate(auto_widths)]
            excess_pos = sum(x for x in excess if x > 0)
            extra_neg = sum(x for x in extra if x <= 0) + excess_pos
            extra_pos = (sum(x for x, c in zip(extra, excess)
                             if x > 0 and c <= 0))
            if extra_pos + extra_neg < 0:
                self.warn('Table contents are too wide to fit within the '
                          'available width', container)
                return [width.to_points(container.width)
                        if isinstance(width, DimBase) else width
                        for width in auto_widths]

            def final_column_width(index, width):
                if isinstance(width, DimBase):
                    return width.to_points(container.width)
                elif excess[index] > 0:
                    return max_column_widths[index]
                elif extra[index] <= 0:
                    return min_column_widths[index]
                else:
                    return width + (extra_neg * extra[index] / extra_pos)

            return [final_column_width(i, width)
                    for i, width in enumerate(auto_widths)]
        else:
            return [width.to_points(container.width)
                    for width in column_widths]
Calculate the table's column sizes constrained by:

        - requested (absolute, relative and automatic) column widths
        - container width (= available width)
        - cell contents