"""
Misc stuff.
"""
from __future__ import absolute_import


from _compat import *

from collections import namedtuple as _namedtuple

from util.collections import is_mapping


class Pair(_namedtuple('_Pair', 'false true')):
    __slots__ = ()

    def _mapwith(self, func):
        return Pair._make(map(func, self))

bools = Pair(False, True)


def to_dict(iterable_or_mapping, check_exclusive=False):
    if isinstance(iterable_or_mapping, dict):
        return iterable_or_mapping

    if not check_exclusive or is_mapping(iterable_or_mapping):
        return dict(iterable_or_mapping)

    items = list(iterable_or_mapping)
    ret_dict = dict(items)
    if len(ret_dict) != len(items):
        raise ValueError('Item(s) with conflicting keys detected')

    return ret_dict


if hasattr(0, 'bit_length'):
    def single_set_bit(x):
        if x > 0 and not (x & (x-1)):
            return x.bit_length() - 1

else:
    def single_set_bit(x):
        if x > 0 and not (x & (x-1)):
            return len(bin(x)) - 3  # 5 -> bin=0b101 -> len=5 -> ret=2


def singleton(cls):
    """Decorator for declaring and instantiating a class in-place."""
    return cls()


class NotifyingMixin(object):
    """docstring for NotifyingMixin"""
    __slots__ = '__subscribers'

    def __init__(self):
        super(NotifyingMixin, self).__init__()
        self.__subscribers = []

    def _notify(self, *args, **kwargs):
        for func in self.__subscribers:
            func(*args, **kwargs)

    def subscribe(self, func):
        self.__subscribers.append(func)


class InstanceBoundTypeMixin(object):
    """
    Base class for per-instance types, that is types defined for each instance
    of the target type.

    Do not use without mixing in a instance-private type.
    """
    __slots__ = ()

    # These may be too strict checks, but it is OK,
    # since types are mapped to the corresponding instances one-to-one.
    _type_eq   = classmethod(lambda cls, other: cls is type(other))
    _type_hash = classmethod(id)

    def __eq__(self, other):
        return self._type_eq(type(other))
    def __hash__(self):
        return self._type_hash()


"""
Misc stuff.
"""
from __future__ import absolute_import


from _compat import *

from collections import namedtuple as _namedtuple

from util.collections import is_mapping


class Pair(_namedtuple('_Pair', 'false true')):
    __slots__ = ()

    def _mapwith(self, func):
        return Pair._make(map(func, self))

bools = Pair(False, True)


def to_dict(iterable_or_mapping, check_exclusive=False):
    if isinstance(iterable_or_mapping, dict):
        return iterable_or_mapping

    if not check_exclusive or is_mapping(iterable_or_mapping):
        return dict(iterable_or_mapping)

    items = list(iterable_or_mapping)
    ret_dict = dict(items)
    if len(ret_dict) != len(items):
        raise ValueError('Item(s) with conflicting keys detected')

    return ret_dict


if hasattr(0, 'bit_length'):
    def single_set_bit(x):
        if x > 0 and not (x & (x-1)):
            return x.bit_length() - 1

else:
    def single_set_bit(x):
        if x > 0 and not (x & (x-1)):
            return len(bin(x)) - 3  # 5 -> bin=0b101 -> len=5 -> ret=2


def singleton(cls):
    """Decorator for declaring and instantiating a class in-place."""
    return cls()


class NotifyingMixin(object):
    """docstring for NotifyingMixin"""
    __slots__ = '__subscribers'

    def __init__(self):
        super(NotifyingMixin, self).__init__()
        self.__subscribers = []

    def _notify(self, *args, **kwargs):
        for func in self.__subscribers:
            func(*args, **kwargs)

    def subscribe(self, func):
        self.__subscribers.append(func)


class InstanceBoundTypeMixin(object):
    """
    Base class for per-instance types, that is types defined for each instance
    of the target type.

    Do not use without mixing in a instance-private type.
    """
    __slots__ = ()

    # These may be too strict checks, but it is OK,
    # since types are mapped to the corresponding instances one-to-one.
    _type_eq   = classmethod(lambda cls, other: cls is type(other))
    _type_hash = classmethod(id)

    def __eq__(self, other):
        return self._type_eq(other)
    def __hash__(self):
        return self._type_hash()


fix a stupid bug in InstanceBoundTypeMixin