static PyObject *
_lookup(lookup *self, 
        PyObject *required, PyObject *provided, PyObject *name, 
        PyObject *default_)
{
  PyObject *result, *key, *cache;

  cache = _getcache(self, provided, name);
  if (cache == NULL)
    return NULL;

  required = tuplefy(required);
  if (required == NULL)
    return NULL;

  if (PyTuple_GET_SIZE(required) == 1)
    key = PyTuple_GET_ITEM(required, 0);
  else
    key = required;

  result = PyDict_GetItem(cache, key);
  if (result == NULL)
    {
      int status;

      result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup,
                                          required, provided, name, NULL);
      if (result == NULL)
        {
          Py_DECREF(required);
          return NULL;
        }
      status = PyDict_SetItem(cache, key, result);
      Py_DECREF(required);
      if (status < 0)
        {
          Py_DECREF(result);
          return NULL;
        }
    }
  else
    {
      Py_INCREF(result);
      Py_DECREF(required);
    }

  if (result == Py_None && default_ != NULL)
    {
      Py_DECREF(Py_None);
      Py_INCREF(default_);
      return default_;
    }

  return result;
}
/*
    def subscriptions(self, required, provided):
        cache = self._scache.get(provided)
        if cache is None:
            cache = {}
            self._scache[provided] = cache

        required = tuple(required)
        result = cache.get(required, _not_in_mapping)
        if result is _not_in_mapping:
            result = self._uncached_subscriptions(required, provided)
            cache[required] = result

        return result
*/
static PyObject *
_subscriptions(lookup *self, PyObject *required, PyObject *provided)
{
  PyObject *cache, *result;

  ASSURE_DICT(self->_scache);
  cache = _subcache(self->_scache, provided);
  if (cache == NULL)
    return NULL;

  required = tuplefy(required);
  if (required == NULL)
    return NULL;

  result = PyDict_GetItem(cache, required);
  if (result == NULL)
    {
      int status;

      result = PyObject_CallMethodObjArgs(
                                 OBJECT(self), str_uncached_subscriptions,
                                 required, provided, NULL);
      if (result == NULL)
        {
          Py_DECREF(required);
          return NULL;
        }
      status = PyDict_SetItem(cache, required, result);
      Py_DECREF(required);
      if (status < 0)
        {
          Py_DECREF(result);
          return NULL;
        }
    }
  else
    {
      Py_INCREF(result);
      Py_DECREF(required);
    }

  return result;
}
static PyObject *
_lookup(lookup *self,
        PyObject *required, PyObject *provided, PyObject *name,
        PyObject *default_)
{
  PyObject *result, *key, *cache;

#ifdef PY3K
  if ( name && !PyUnicode_Check(name) )
#else
  if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
#endif
  {
    PyErr_SetString(PyExc_ValueError,
                    "name is not a string or unicode");
    return NULL;
  }
  cache = _getcache(self, provided, name);
  if (cache == NULL)
    return NULL;

  required = tuplefy(required);
  if (required == NULL)
    return NULL;

  if (PyTuple_GET_SIZE(required) == 1)
    key = PyTuple_GET_ITEM(required, 0);
  else
    key = required;

  result = PyDict_GetItem(cache, key);
  if (result == NULL)
    {
      int status;

      result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup,
                                          required, provided, name, NULL);
      if (result == NULL)
        {
          Py_DECREF(required);
          return NULL;
        }
      status = PyDict_SetItem(cache, key, result);
      Py_DECREF(required);
      if (status < 0)
        {
          Py_DECREF(result);
          return NULL;
        }
    }
  else
    {
      Py_INCREF(result);
      Py_DECREF(required);
    }

  if (result == Py_None && default_ != NULL)
    {
      Py_DECREF(Py_None);
      Py_INCREF(default_);
      return default_;
    }

  return result;
}