code: def _limit_size(
      self, x: Tuple[int], max_size: List
  ) -> Tuple[int, ...]:
      new_shape, dims = list(x), len(x)
      for i in range(dims):
          next_idx = (i + 1) % dims
          while new_shape[i] > max_size[i]:
              new_shape[i] = new_shape[i] // 2
              if new_shape[next_idx] <= max_size[next_idx]:
                  new_shape[next_idx] = new_shape[next_idx] * 2
              else:
                  next_idx = (next_idx + 1) % dims
                  new_shape[next_idx] = new_shape[next_idx] * 2
      return tuple(new_shape)
  
imports: from __future__ import annotations
  import os, math, itertools
  from typing import NamedTuple, Optional, List, Tuple, cast, Dict, Union
  from tinygrad.ops import LazyOp, FlopCounter, get_lazyop_info, UnaryOps, BinaryOps, ReduceOps, MemBuffer, ConstBuffer, BufferOps
  from tinygrad.device import Device, Compiled
  from tinygrad.dtype import dtypes, ImageDType, DType
  from tinygrad.helpers import dedup, colored, ansilen, getenv, prod, DEBUG, round_up, all_int
  from tinygrad.shape.shapetracker import ShapeTracker, get_contraction
  from tinygrad.shape.symbolic import sint
  from tinygrad.shape.view import View, strides_for_shape
  from dataclasses import dataclass
  from enum import Enum, auto
label_desc: Use image node_id 23 for calling the Kernel obj's underlying member method code with example usage: obj._limit_size(x, max_size) and returns: tuple