class_docstr: Base class for Hoeffding Decision Trees.
  
  This is an **abstract class**, so it cannot be used directly. It defines base operations
  and properties that all the Hoeffding decision trees must inherit or implement according to
  their own design.
  
  Parameters
  ----------
  max_depth
      The maximum depth a tree can reach. If `None`, the tree will grow indefinitely.
  binary_split
      If True, only allow binary splits.
  max_size
      The max size of the tree, in Megabytes (MB).
  memory_estimate_period
      Interval (number of processed instances) between memory consumption checks.
  stop_mem_management
      If True, stop growing as soon as memory limit is hit.
  remove_poor_attrs
      If True, disable poor attributes to reduce memory usage.
  merit_preprune
      If True, enable merit-based tree pre-pruning.
docstr: Track the size of the tree and disable/enable nodes if required.
  
  This memory-management routine shared by all the Hoeffding Trees is based on [^1].
  
  References
  ----------
  [^1]: Kirkby, R.B., 2007. Improving hoeffding trees (Doctoral dissertation,
  The University of Waikato).
code: def _enforce_size_limit(self):
      """Track the size of the tree and disable/enable nodes if required.
  
      This memory-management routine shared by all the Hoeffding Trees is based on [^1].
  
      References
      ----------
      [^1]: Kirkby, R.B., 2007. Improving hoeffding trees (Doctoral dissertation,
      The University of Waikato).
      """
      tree_size = self._size_estimate_overhead_fraction * (
          self._active_leaf_size_estimate
          + self._n_inactive_leaves * self._inactive_leaf_size_estimate
      )
      if self._n_inactive_leaves > 0 or tree_size > self._max_byte_size:
          if self.stop_mem_management:
              self._growth_allowed = False
              return
      leaves = self._find_leaves()
      leaves.sort(key=lambda leaf: leaf.calculate_promise())
      max_active = 0
      while max_active < len(leaves):
          max_active += 1
          if (
              (
                  max_active * self._active_leaf_size_estimate
                  + (len(leaves) - max_active)
                  * self._inactive_leaf_size_estimate
              )
              * self._size_estimate_overhead_fraction
          ) > self._max_byte_size:
              max_active -= 1
              break
      cutoff = len(leaves) - max_active
      for i in range(cutoff):
          if leaves[i].is_active():
              leaves[i].deactivate()
              self._n_inactive_leaves += 1
              self._n_active_leaves -= 1
      for i in range(cutoff, len(leaves)):
          if (
              not leaves[i].is_active()
              and leaves[i].depth < self.max_depth
          ):
              leaves[i].activate()
              self._n_active_leaves += 1
              self._n_inactive_leaves -= 1
  
imports: from __future__ import annotations
  import collections
  import functools
  import io
  import math
  from abc import ABC, abstractmethod
  from river import base
  from river.utils.norm import normalize_values_in_dict
  from .nodes.branch import DTBranch, NominalBinaryBranch, NominalMultiwayBranch, NumericBinaryBranch, NumericMultiwayBranch
  from .nodes.leaf import HTLeaf
  from .utils import calculate_object_size
label_desc: Use image node_id 19 for calling the HoeffdingTree obj's underlying member method code with example usage: obj._enforce_size_limit() without return types