docs: def _add(self, uri, methods, handler, host=None):
          """Add a handler to the route list
  
          :param uri: path to match
          :param methods: sequence of accepted method names. If none are
              provided, any method is allowed
          :param handler: request handler function.
              When executed, it should provide a response object.
          :return: Nothing
          """
          if host is not None:
              if isinstance(host, str):
                  uri = host + uri
                  self.hosts.add(host)
  
              else:
                  if not isinstance(host, Iterable):
                      raise ValueError("Expected either string or Iterable of "
                                       "host strings, not {!r}".format(host))
  
                  for host_ in host:
                      self.add(uri, methods, handler, host_)
                  return
  
          # Dict for faster lookups of if method allowed
          if methods:
              methods = frozenset(methods)
  
          parameters = []
          properties = {"unhashable": None}
  
          def add_parameter(match):
              name = match.group(1)
              name, _type, pattern = self.parse_parameter_string(name)
  
              parameter = Parameter(
                  name=name, cast=_type)
              parameters.append(parameter)
  
              # Mark the whole route as unhashable if it has the hash key in it
              if re.search(r'(^|[^^]){1}/', pattern):
                  properties['unhashable'] = True
              # Mark the route as unhashable if it matches the hash key
              elif re.search(r'/', pattern):
                  properties['unhashable'] = True
  
              return '({})'.format(pattern)
  
          pattern_string = re.sub(self.parameter_pattern, add_parameter, uri)
          pattern = re.compile(r'^{}$'.format(pattern_string))
  
          def merge_route(route, methods, handler):
              # merge to the existing route when possible.
              if not route.methods or not methods:
                  # method-unspecified routes are not mergeable.
                  raise RouteExists(
                      "Route already registered: {}".format(uri))
              elif route.methods.intersection(methods):
                  # already existing method is not overloadable.
                  duplicated = methods.intersection(route.methods)
                  raise RouteExists(
                      "Route already registered: {} [{}]".format(
                          uri, ','.join(list(duplicated))))
              if isinstance(route.handler, self._composition_view_class):
                  view = route.handler
              else:
                  view = self._composition_view_class()
                  view.add(route.methods, route.handler)
              view.add(methods, handler)
              route = route._replace(
                  handler=view, methods=methods.union(route.methods))
              return route
  
          if parameters:
              # TODO: This is too complex, we need to reduce the complexity
              if properties['unhashable']:
                  routes_to_check = self.routes_always_check
                  ndx, route = self.check_dynamic_route_exists(
                      pattern, routes_to_check)
              else:
                  routes_to_check = self.routes_dynamic[url_hash(uri)]
                  ndx, route = self.check_dynamic_route_exists(
                      pattern, routes_to_check)
              if ndx != -1:
                  # Pop the ndx of the route, no dups of the same route
                  routes_to_check.pop(ndx)
          else:
              route = self.routes_all.get(uri)
  
          if route:
              route = merge_route(route, methods, handler)
          else:
              # prefix the handler name with the blueprint name
              # if available
              if hasattr(handler, '__blueprintname__'):
                  handler_name = '{}.{}'.format(
                      handler.__blueprintname__, handler.__name__)
              else:
                  handler_name = getattr(handler, '__name__', None)
  
              route = Route(
                  handler=handler, methods=methods, pattern=pattern,
                  parameters=parameters, name=handler_name, uri=uri)
  
          self.routes_all[uri] = route
          if properties['unhashable']:
              self.routes_always_check.append(route)
          elif parameters:
              self.routes_dynamic[url_hash(uri)].append(route)
          else:
              self.routes_static[uri] = route