<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "factory_p.h"
#include "objectdescription.h"
#include "audiooutputadaptor_p.h"
#include "globalconfig.h"
#include "audiooutputinterface.h"
#include "phononnamespace_p.h"
#include "platform_p.h"
#include "pulsesupport.h"

#include <QtCore/qmath.h>

#define PHONON_CLASSNAME AudioOutput
#define IFACES2 AudioOutputInterface42
#define IFACES1 IFACES2
#define IFACES0 AudioOutputInterface40, IFACES1
#define PHONON_INTERFACENAME IFACES0

QT_BEGIN_NAMESPACE

namespace Phonon
{

static inline bool callSetOutputDevice(AudioOutputPrivate *const d, int index)
{
    PulseSupport *pulse = PulseSupport::getInstance();
    if (pulse->isActive())
        return pulse->setOutputDevice(d->getStreamUuid(), index);

    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(AudioOutputDevice::fromIndex(index));
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(index);
}

static inline bool callSetOutputDevice(AudioOutputPrivate *const d, const AudioOutputDevice &dev)
{
    PulseSupport *pulse = PulseSupport::getInstance();
    if (pulse->isActive())
        return pulse->setOutputDevice(d->getStreamUuid(), dev.index());

    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(dev);
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(dev.index());
}

AudioOutput::AudioOutput(Phonon::Category category, QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(category);
}

AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(NoCategory);
}

void AudioOutputPrivate::init(Phonon::Category c)
{
    Q_Q(AudioOutput);
#ifndef QT_NO_DBUS
    adaptor = new AudioOutputAdaptor(q);
    static unsigned int number = 0;
    const QString &path = QLatin1String("/AudioOutputs/") + QString::number(number++);
    QDBusConnection con = QDBusConnection::sessionBus();
    con.registerObject(path, q);
    emit adaptor->newOutputAvailable(con.baseService(), path);
    q->connect(q, SIGNAL(volumeChanged(qreal)), adaptor, SIGNAL(volumeChanged(qreal)));
    q->connect(q, SIGNAL(mutedChanged(bool)), adaptor, SIGNAL(mutedChanged(bool)));
#endif

    category = c;
    streamUuid = QUuid::createUuid().toString();
    PulseSupport::getInstance()->setStreamPropList(category, streamUuid);

    createBackendObject();

    q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged()));
}

QString AudioOutputPrivate::getStreamUuid()
{
    return streamUuid;
}

void AudioOutputPrivate::createBackendObject()
{
    if (m_backendObject)
        return;
    Q_Q(AudioOutput);
    m_backendObject = Factory::createAudioOutput(q);
    device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices));
    if (m_backendObject) {
        setupBackendObject();
    }
}

QString AudioOutput::name() const
{
    K_D(const AudioOutput);
    return d->name;
}

void AudioOutput::setName(const QString &newName)
{
    K_D(AudioOutput);
    if (d->name == newName) {
        return;
    }
    d->name = newName;
    setVolume(Platform::loadVolume(newName));
#ifndef QT_NO_DBUS
    if (d->adaptor) {
        emit d->adaptor->nameChanged(newName);
    }
#endif
}

static const qreal LOUDNESS_TO_VOLTAGE_EXPONENT = qreal(0.67);
static const qreal VOLTAGE_TO_LOUDNESS_EXPONENT = qreal(1.0/LOUDNESS_TO_VOLTAGE_EXPONENT);

void AudioOutput::setVolume(qreal volume)
{
    K_D(AudioOutput);
    d->volume = volume;
    if (k_ptr->backendObject() && !d->muted) {
        // using Stevens' power law loudness is proportional to (sound pressure)^0.67
        // sound pressure is proportional to voltage:
        // p² \prop P \prop V²
        // => if a factor for loudness of x is requested
        INTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
    } else {
        emit volumeChanged(volume);
    }
    Platform::saveVolume(d->name, volume);
}

qreal AudioOutput::volume() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return d->volume;
    }
    return pow(INTERFACE_CALL(volume()), LOUDNESS_TO_VOLTAGE_EXPONENT);
}

#ifndef PHONON_LOG10OVER20
#define PHONON_LOG10OVER20
static const qreal log10over20 = qreal(0.1151292546497022842); // ln(10) / 20
#endif // PHONON_LOG10OVER20

qreal AudioOutput::volumeDecibel() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return log(d->volume) / log10over20;
    }
    return 0.67 * log(INTERFACE_CALL(volume())) / log10over20;
}

void AudioOutput::setVolumeDecibel(qreal newVolumeDecibel)
{
    setVolume(exp(newVolumeDecibel * log10over20));
}

bool AudioOutput::isMuted() const
{
    K_D(const AudioOutput);
    return d->muted;
}

void AudioOutput::setMuted(bool mute)
{
    K_D(AudioOutput);
    if (d->muted != mute) {
        if (mute) {
            d->muted = mute;
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(0.0));
            }
        } else {
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(pow(d->volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
            }
            d->muted = mute;
        }
        emit mutedChanged(mute);
    }
}

Category AudioOutput::category() const
{
    K_D(const AudioOutput);
    return d->category;
}

AudioOutputDevice AudioOutput::outputDevice() const
{
    K_D(const AudioOutput);
    return d->device;
}

bool AudioOutput::setOutputDevice(const AudioOutputDevice &newAudioOutputDevice)
{
    K_D(AudioOutput);
    if (!newAudioOutputDevice.isValid()) {
        d->outputDeviceOverridden = false;
        const int newIndex = GlobalConfig().audioOutputDeviceFor(d->category);
        if (newIndex == d->device.index()) {
            return true;
        }
        d->device = AudioOutputDevice::fromIndex(newIndex);
    } else {
        d->outputDeviceOverridden = true;
        if (d->device == newAudioOutputDevice) {
            return true;
        }
        d->device = newAudioOutputDevice;
    }
    if (k_ptr->backendObject()) {
        return callSetOutputDevice(d, d->device.index());
    }
    return true;
}

bool AudioOutputPrivate::aboutToDeleteBackendObject()
{
    if (m_backendObject) {
        volume = pINTERFACE_CALL(volume());
    }
    return AbstractAudioOutputPrivate::aboutToDeleteBackendObject();
}

void AudioOutputPrivate::setupBackendObject()
{
    Q_Q(AudioOutput);
    Q_ASSERT(m_backendObject);
    AbstractAudioOutputPrivate::setupBackendObject();

    QObject::connect(m_backendObject, SIGNAL(volumeChanged(qreal)), q, SLOT(_k_volumeChanged(qreal)));
    QObject::connect(m_backendObject, SIGNAL(audioDeviceFailed()), q, SLOT(_k_audioDeviceFailed()));

    // set up attributes
    pINTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));

    // if the output device is not available and the device was not explicitly set
    if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) {
        // fall back in the preference list of output devices
        QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
        if (deviceList.isEmpty()) {
            return;
        }
        foreach (int devIndex, deviceList) {
            const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, dev)) {
                handleAutomaticDeviceChange(dev, AudioOutputPrivate::FallbackChange);
                return; // found one that works
            }
        }
        // if we get here there is no working output device. Tell the backend.
        const AudioOutputDevice none;
        callSetOutputDevice(this, none);
        handleAutomaticDeviceChange(none, FallbackChange);
    }
}

void AudioOutputPrivate::_k_volumeChanged(qreal newVolume)
{
    if (!muted) {
        Q_Q(AudioOutput);
        emit q->volumeChanged(pow(newVolume, qreal(0.67)));
    }
}

void AudioOutputPrivate::_k_revertFallback()
{
    if (deviceBeforeFallback == -1) {
        return;
    }
    device = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    callSetOutputDevice(this, device);
    Q_Q(AudioOutput);
    emit q->outputDeviceChanged(device);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
}

void AudioOutputPrivate::_k_audioDeviceFailed()
{
    pDebug() << Q_FUNC_INFO;
    // outputDeviceIndex identifies a failing device
    // fall back in the preference list of output devices
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
    foreach (int devIndex, deviceList) {
        // if it's the same device as the one that failed, ignore it
        if (device.index() != devIndex) {
            const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, info)) {
                handleAutomaticDeviceChange(info, FallbackChange);
                return; // found one that works
            }
        }
    }
    // if we get here there is no working output device. Tell the backend.
    const AudioOutputDevice none;
    callSetOutputDevice(this, none);
    handleAutomaticDeviceChange(none, FallbackChange);
}

void AudioOutputPrivate::_k_deviceListChanged()
{
    pDebug() << Q_FUNC_INFO;
    // let's see if there's a usable device higher in the preference list
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
    DeviceChangeType changeType = HigherPreferenceChange;
    foreach (int devIndex, deviceList) {
        const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
        if (!info.property("available").toBool()) {
            if (device.index() == devIndex) {
                // we've reached the currently used device and it's not available anymore, so we
                // fallback to the next available device
                changeType = FallbackChange;
            }
            pDebug() << devIndex << "is not available";
            continue;
        }
        pDebug() << devIndex << "is available";
        if (device.index() == devIndex) {
            // we've reached the currently used device, nothing to change
            break;
        }
        if (callSetOutputDevice(this, info)) {
            handleAutomaticDeviceChange(info, changeType);
            break; // found one with higher preference that works
        }
    }
}

static struct
{
    int first;
    int second;
} g_lastFallback = { 0, 0 };

void AudioOutputPrivate::handleAutomaticDeviceChange(const AudioOutputDevice &device2, DeviceChangeType type)
{
    Q_Q(AudioOutput);
    deviceBeforeFallback = device.index();
    device = device2;
    emit q->outputDeviceChanged(device2);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
    const AudioOutputDevice &device1 = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    switch (type) {
    case FallbackChange:
        if (g_lastFallback.first != device1.index() || g_lastFallback.second != device2.index()) {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
            const QString &text = //device2.isValid() ?
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "Falling back to %2.").arg(device1.name()).arg(device2.name()) /*:
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "No other device available.").arg(device1.name())*/;
            Platform::notification("AudioDeviceFallback", text);
#endif //QT_NO_PHONON_PLATFORMPLUGIN
            g_lastFallback.first = device1.index();
            g_lastFallback.second = device2.index();
        }
        break;
    case HigherPreferenceChange:
        {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
        const QString text = AudioOutput::tr("Switching to the audio playback device %1
"
                "which just became available and has higher preference.").arg(device2.name());
        Platform::notification("AudioDeviceFallback", text,
                QStringList(AudioOutput::tr("Revert back to device '%1'").arg(device1.name())),
                q, SLOT(_k_revertFallback()));
#endif //QT_NO_PHONON_PLATFORMPLUGIN
        g_lastFallback.first = 0;
        g_lastFallback.second = 0;
        }
        break;
    }
}

AudioOutputPrivate::~AudioOutputPrivate()
{
    PulseSupport::getInstance()->clearStreamCache(streamUuid);
#ifndef QT_NO_DBUS
    if (adaptor) {
        emit adaptor->outputDestroyed();
    }
#endif
}

} //namespace Phonon

QT_END_NAMESPACE

#include "moc_audiooutput.cpp"

#undef PHONON_CLASSNAME
#undef PHONON_INTERFACENAME
#undef IFACES2
#undef IFACES1
#undef IFACES0
<commit_msg>add missed include<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "factory_p.h"
#include "objectdescription.h"
#include "audiooutputadaptor_p.h"
#include "globalconfig.h"
#include "audiooutputinterface.h"
#include "phononnamespace_p.h"
#include "platform_p.h"
#include "pulsesupport.h"

#include <QtCore/QUuid>
#include <QtCore/qmath.h>

#define PHONON_CLASSNAME AudioOutput
#define IFACES2 AudioOutputInterface42
#define IFACES1 IFACES2
#define IFACES0 AudioOutputInterface40, IFACES1
#define PHONON_INTERFACENAME IFACES0

QT_BEGIN_NAMESPACE

namespace Phonon
{

static inline bool callSetOutputDevice(AudioOutputPrivate *const d, int index)
{
    PulseSupport *pulse = PulseSupport::getInstance();
    if (pulse->isActive())
        return pulse->setOutputDevice(d->getStreamUuid(), index);

    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(AudioOutputDevice::fromIndex(index));
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(index);
}

static inline bool callSetOutputDevice(AudioOutputPrivate *const d, const AudioOutputDevice &dev)
{
    PulseSupport *pulse = PulseSupport::getInstance();
    if (pulse->isActive())
        return pulse->setOutputDevice(d->getStreamUuid(), dev.index());

    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(dev);
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(dev.index());
}

AudioOutput::AudioOutput(Phonon::Category category, QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(category);
}

AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(NoCategory);
}

void AudioOutputPrivate::init(Phonon::Category c)
{
    Q_Q(AudioOutput);
#ifndef QT_NO_DBUS
    adaptor = new AudioOutputAdaptor(q);
    static unsigned int number = 0;
    const QString &path = QLatin1String("/AudioOutputs/") + QString::number(number++);
    QDBusConnection con = QDBusConnection::sessionBus();
    con.registerObject(path, q);
    emit adaptor->newOutputAvailable(con.baseService(), path);
    q->connect(q, SIGNAL(volumeChanged(qreal)), adaptor, SIGNAL(volumeChanged(qreal)));
    q->connect(q, SIGNAL(mutedChanged(bool)), adaptor, SIGNAL(mutedChanged(bool)));
#endif

    category = c;
    streamUuid = QUuid::createUuid().toString();
    PulseSupport::getInstance()->setStreamPropList(category, streamUuid);

    createBackendObject();

    q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged()));
}

QString AudioOutputPrivate::getStreamUuid()
{
    return streamUuid;
}

void AudioOutputPrivate::createBackendObject()
{
    if (m_backendObject)
        return;
    Q_Q(AudioOutput);
    m_backendObject = Factory::createAudioOutput(q);
    device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices));
    if (m_backendObject) {
        setupBackendObject();
    }
}

QString AudioOutput::name() const
{
    K_D(const AudioOutput);
    return d->name;
}

void AudioOutput::setName(const QString &newName)
{
    K_D(AudioOutput);
    if (d->name == newName) {
        return;
    }
    d->name = newName;
    setVolume(Platform::loadVolume(newName));
#ifndef QT_NO_DBUS
    if (d->adaptor) {
        emit d->adaptor->nameChanged(newName);
    }
#endif
}

static const qreal LOUDNESS_TO_VOLTAGE_EXPONENT = qreal(0.67);
static const qreal VOLTAGE_TO_LOUDNESS_EXPONENT = qreal(1.0/LOUDNESS_TO_VOLTAGE_EXPONENT);

void AudioOutput::setVolume(qreal volume)
{
    K_D(AudioOutput);
    d->volume = volume;
    if (k_ptr->backendObject() && !d->muted) {
        // using Stevens' power law loudness is proportional to (sound pressure)^0.67
        // sound pressure is proportional to voltage:
        // p² \prop P \prop V²
        // => if a factor for loudness of x is requested
        INTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
    } else {
        emit volumeChanged(volume);
    }
    Platform::saveVolume(d->name, volume);
}

qreal AudioOutput::volume() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return d->volume;
    }
    return pow(INTERFACE_CALL(volume()), LOUDNESS_TO_VOLTAGE_EXPONENT);
}

#ifndef PHONON_LOG10OVER20
#define PHONON_LOG10OVER20
static const qreal log10over20 = qreal(0.1151292546497022842); // ln(10) / 20
#endif // PHONON_LOG10OVER20

qreal AudioOutput::volumeDecibel() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return log(d->volume) / log10over20;
    }
    return 0.67 * log(INTERFACE_CALL(volume())) / log10over20;
}

void AudioOutput::setVolumeDecibel(qreal newVolumeDecibel)
{
    setVolume(exp(newVolumeDecibel * log10over20));
}

bool AudioOutput::isMuted() const
{
    K_D(const AudioOutput);
    return d->muted;
}

void AudioOutput::setMuted(bool mute)
{
    K_D(AudioOutput);
    if (d->muted != mute) {
        if (mute) {
            d->muted = mute;
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(0.0));
            }
        } else {
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(pow(d->volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
            }
            d->muted = mute;
        }
        emit mutedChanged(mute);
    }
}

Category AudioOutput::category() const
{
    K_D(const AudioOutput);
    return d->category;
}

AudioOutputDevice AudioOutput::outputDevice() const
{
    K_D(const AudioOutput);
    return d->device;
}

bool AudioOutput::setOutputDevice(const AudioOutputDevice &newAudioOutputDevice)
{
    K_D(AudioOutput);
    if (!newAudioOutputDevice.isValid()) {
        d->outputDeviceOverridden = false;
        const int newIndex = GlobalConfig().audioOutputDeviceFor(d->category);
        if (newIndex == d->device.index()) {
            return true;
        }
        d->device = AudioOutputDevice::fromIndex(newIndex);
    } else {
        d->outputDeviceOverridden = true;
        if (d->device == newAudioOutputDevice) {
            return true;
        }
        d->device = newAudioOutputDevice;
    }
    if (k_ptr->backendObject()) {
        return callSetOutputDevice(d, d->device.index());
    }
    return true;
}

bool AudioOutputPrivate::aboutToDeleteBackendObject()
{
    if (m_backendObject) {
        volume = pINTERFACE_CALL(volume());
    }
    return AbstractAudioOutputPrivate::aboutToDeleteBackendObject();
}

void AudioOutputPrivate::setupBackendObject()
{
    Q_Q(AudioOutput);
    Q_ASSERT(m_backendObject);
    AbstractAudioOutputPrivate::setupBackendObject();

    QObject::connect(m_backendObject, SIGNAL(volumeChanged(qreal)), q, SLOT(_k_volumeChanged(qreal)));
    QObject::connect(m_backendObject, SIGNAL(audioDeviceFailed()), q, SLOT(_k_audioDeviceFailed()));

    // set up attributes
    pINTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));

    // if the output device is not available and the device was not explicitly set
    if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) {
        // fall back in the preference list of output devices
        QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
        if (deviceList.isEmpty()) {
            return;
        }
        foreach (int devIndex, deviceList) {
            const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, dev)) {
                handleAutomaticDeviceChange(dev, AudioOutputPrivate::FallbackChange);
                return; // found one that works
            }
        }
        // if we get here there is no working output device. Tell the backend.
        const AudioOutputDevice none;
        callSetOutputDevice(this, none);
        handleAutomaticDeviceChange(none, FallbackChange);
    }
}

void AudioOutputPrivate::_k_volumeChanged(qreal newVolume)
{
    if (!muted) {
        Q_Q(AudioOutput);
        emit q->volumeChanged(pow(newVolume, qreal(0.67)));
    }
}

void AudioOutputPrivate::_k_revertFallback()
{
    if (deviceBeforeFallback == -1) {
        return;
    }
    device = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    callSetOutputDevice(this, device);
    Q_Q(AudioOutput);
    emit q->outputDeviceChanged(device);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
}

void AudioOutputPrivate::_k_audioDeviceFailed()
{
    pDebug() << Q_FUNC_INFO;
    // outputDeviceIndex identifies a failing device
    // fall back in the preference list of output devices
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
    foreach (int devIndex, deviceList) {
        // if it's the same device as the one that failed, ignore it
        if (device.index() != devIndex) {
            const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, info)) {
                handleAutomaticDeviceChange(info, FallbackChange);
                return; // found one that works
            }
        }
    }
    // if we get here there is no working output device. Tell the backend.
    const AudioOutputDevice none;
    callSetOutputDevice(this, none);
    handleAutomaticDeviceChange(none, FallbackChange);
}

void AudioOutputPrivate::_k_deviceListChanged()
{
    pDebug() << Q_FUNC_INFO;
    // let's see if there's a usable device higher in the preference list
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
    DeviceChangeType changeType = HigherPreferenceChange;
    foreach (int devIndex, deviceList) {
        const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
        if (!info.property("available").toBool()) {
            if (device.index() == devIndex) {
                // we've reached the currently used device and it's not available anymore, so we
                // fallback to the next available device
                changeType = FallbackChange;
            }
            pDebug() << devIndex << "is not available";
            continue;
        }
        pDebug() << devIndex << "is available";
        if (device.index() == devIndex) {
            // we've reached the currently used device, nothing to change
            break;
        }
        if (callSetOutputDevice(this, info)) {
            handleAutomaticDeviceChange(info, changeType);
            break; // found one with higher preference that works
        }
    }
}

static struct
{
    int first;
    int second;
} g_lastFallback = { 0, 0 };

void AudioOutputPrivate::handleAutomaticDeviceChange(const AudioOutputDevice &device2, DeviceChangeType type)
{
    Q_Q(AudioOutput);
    deviceBeforeFallback = device.index();
    device = device2;
    emit q->outputDeviceChanged(device2);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
    const AudioOutputDevice &device1 = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    switch (type) {
    case FallbackChange:
        if (g_lastFallback.first != device1.index() || g_lastFallback.second != device2.index()) {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
            const QString &text = //device2.isValid() ?
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "Falling back to %2.").arg(device1.name()).arg(device2.name()) /*:
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "No other device available.").arg(device1.name())*/;
            Platform::notification("AudioDeviceFallback", text);
#endif //QT_NO_PHONON_PLATFORMPLUGIN
            g_lastFallback.first = device1.index();
            g_lastFallback.second = device2.index();
        }
        break;
    case HigherPreferenceChange:
        {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
        const QString text = AudioOutput::tr("Switching to the audio playback device %1
"
                "which just became available and has higher preference.").arg(device2.name());
        Platform::notification("AudioDeviceFallback", text,
                QStringList(AudioOutput::tr("Revert back to device '%1'").arg(device1.name())),
                q, SLOT(_k_revertFallback()));
#endif //QT_NO_PHONON_PLATFORMPLUGIN
        g_lastFallback.first = 0;
        g_lastFallback.second = 0;
        }
        break;
    }
}

AudioOutputPrivate::~AudioOutputPrivate()
{
    PulseSupport::getInstance()->clearStreamCache(streamUuid);
#ifndef QT_NO_DBUS
    if (adaptor) {
        emit adaptor->outputDestroyed();
    }
#endif
}

} //namespace Phonon

QT_END_NAMESPACE

#include "moc_audiooutput.cpp"

#undef PHONON_CLASSNAME
#undef PHONON_INTERFACENAME
#undef IFACES2
#undef IFACES1
#undef IFACES0
<|endoftext|>


<commit_before>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee --- Response Module
 *
 * @author Sam Baskinger <sbaskinger@qualys.com>
 */

#include <ironbee/path.h>

#include <ironbeepp/action.hpp>
#include <ironbeepp/configuration_parser.hpp>
#include <ironbeepp/module.hpp>
#include <ironbeepp/module_delegate.hpp>
#include <ironbeepp/module_bootstrap.hpp>
#include <ironbeepp/memory_manager.hpp>
#include <ironbeepp/transformation.hpp>

#ifdef __clang__
#pragma clang diagnostic push
#if __has_warning("-Wc++11-extensions")
#pragma clang diagnostic ignored "-Wc++11-extensions"
#endif
#if __has_warning("-Wunused-local-typedef")
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#endif
#endif
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>

#include <boost/iostreams/code_converter.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/iostreams/operations.hpp>
#include <boost/iostreams/read.hpp>

#ifdef __clang__
#pragma clang diagnostic pop
#endif

#include <ios>

namespace {

using namespace IronBee;

//! Config structure for response data.
struct ResponseContextData {

};

//! Tx structure for response data.
struct ResponseTxData {

};

//! The response action.
class ResponseAction {
public:
    ResponseAction(IronBee::Engine engine);
    static Action::action_instance_t generate(
        MemoryManager mm,
        Context       ctx,
        const char *  arg
    );

    /**
     * Implement this function object.
     */
    void operator()(const ib_rule_exec_t * rule_exec);
    void addHeader(const std::string& name, const std::string& value);
    void addHeader(const std::vector<std::string>& headers);
    void setStatus(int status);
    void setFile(const std::string& file);

    //! Get the status.
    int status() const;
    const std::string& file() const;

private:
    IronBee::Engine m_engine;
    int m_status;
    std::string m_file;
    ib_parsed_headers_t *m_headers;
};

ResponseAction::ResponseAction(IronBee::Engine engine)
:
    m_engine(engine)
{
    IronBee::throw_if_error(
        ib_parsed_headers_create(&m_headers, engine.main_memory_mm().ib())
    );
}

void ResponseAction::addHeader(
    const std::string& name,
    const std::string& value
)
{
    ib_log_debug(
        m_engine.ib(),
        "Adding header %.*s=%.*s.",
        static_cast<int>(name.length()),
        name.data(),
        static_cast<int>(value.length()),
        value.data()
    );

    IronBee::throw_if_error(
        ib_parsed_headers_add(
            m_headers,
            name.data(),
            name.length(),
            value.data(),
            value.length()
        )
    );
}

void ResponseAction::addHeader(const std::vector<std::string>& headers)
{
    assert(headers.size() == 2 && "Header must be length 2.");
    addHeader(headers[0], headers[1]);
}

int ResponseAction::status() const
{
    return m_status;
}

void ResponseAction::setStatus(int status)
{
    ib_log_debug(
        m_engine.ib(),
        "Setting status to %d.",
        status
    );
    m_status = status;
}

const std::string& ResponseAction::file() const
{
    return m_file;
}

void ResponseAction::setFile(const std::string& file)
{
    ib_log_debug(
        m_engine.ib(),
        "Setting response file to %s.",
        file.c_str()
    );

    ib_status_t rc;
    const ib_cfgparser_t *ib_cp;

    rc = ib_engine_cfgparser_get(m_engine.ib(), &ib_cp);
    if (rc == IB_OK) {
        IronBee::ConstConfigurationParser cp(ib_cp);

        m_file = ib_util_relative_file(
            ib_engine_mm_config_get(m_engine.ib()),
            cp.current_file(),
            file.c_str()
        );

        ib_log_debug(
            m_engine.ib(),
            "Response file set to relative file %s.", m_file.c_str()
        );
    }
    else {
        ib_log_error(
            m_engine.ib(),
            "Failed to get cfg parser. "
            "Cannot set relative path of error page."
        );
        m_file = file;
    }
}

class ResponseModuleDelegate : public ModuleDelegate
{
public:
    ResponseModuleDelegate(Module m);
private:
}; // end class ResponseModuleDelegate

Action::action_instance_t ResponseAction::generate(
    MemoryManager mm,
    Context       ctx,
    const char *  arg
)
{
    // Build a response action that will be populated by the parser.
    ResponseAction r(ctx.engine());

    namespace qi = boost::spirit::qi;
    namespace phoenix = boost::phoenix;

    const char *first = arg;
    const char *last  = first + strlen(arg);

    /* Parse a single comment. */
    bool parse_success = qi::phrase_parse(
        // Range to parse.
        first, last,

        // Begin grammar.
        // Parse the status.
        qi::omit[qi::int_ [ boost::bind(&ResponseAction::setStatus, boost::ref(r), _1)]]
        // Optionally parse the headers.
        >> -(
                qi::lit(",") >>
                (
                    qi::as< std::vector< std::string > >()
                    [
                        qi::as_string[+(qi::char_ - ':')] >>
                        qi::omit[qi::lit(":")]    >>
                        qi::as_string[+(qi::char_ - ',')]
                    ]
                    [
                        phoenix::bind(&ResponseAction::addHeader, boost::ref(r), qi::_1)
                    ] % qi::lit(",")
                )
        )
        // Optionally parse the file.
        >> -(
            qi::lit(",") >>
            qi::as_string[+qi::char_][
                phoenix::bind(&ResponseAction::setFile, boost::ref(r), qi::_1)
            ]
        )
        ,
        // End grammar.

        // Skip parser.
        qi::space
    );

    /* If
     * (1) we fully matched
     * (2) parsed successfully
     */
    if (first == last && parse_success) {
        ib_log_debug(
            ctx.engine().ib(),
            "Built response with status %d and content from %s.",
            r.status(),
            r.file().c_str()
        );
        return r;
    }

    BOOST_THROW_EXCEPTION(
        IronBee::einval()
            << IronBee::errinfo_what(
                str(boost::format("Failed to parse argument: %s") % arg)
            )
    );
}

void ResponseAction::operator()(const ib_rule_exec_t * rule_exec)
{
    assert(rule_exec != NULL);
    assert(rule_exec->tx != NULL);

    ib_status_t rc;

    IronBee::MemoryManager mm = IronBee::MemoryManager(rule_exec->tx->mm);

    IronBee::ByteString page_bs;
    boost::iostreams::mapped_file_source page;

    try
    {
        // Throws an error if the file does not exist.
        page.open(m_file);

        if (page.is_open()) {
            page_bs =
                IronBee::ByteString::create_alias(mm, page.data(), page.size());
        }
        else {
            page_bs = IronBee::ByteString::create_alias(mm, "", 0);
        }
    }
    catch (const std::ios_base::failure& e)
    {
        ib_log_error_tx(
            rule_exec->tx,
            "Failed to read error page file %s: %s", m_file.c_str(), e.what()
        );
        page_bs = IronBee::ByteString::create(mm, "", 0);
    }

    rc = ib_tx_response(
        rule_exec->tx,
        m_status,
        m_headers,
        page_bs.ib()
    );
    if (rc != IB_OK) {
        ib_log_debug_tx(rule_exec->tx, "Failed to send custom response.");
    }

    // Close out here because we want the file to stay mapped until
    // the response is delivered.
    if (page.is_open()) {
        page.close();
    }

}

ResponseModuleDelegate::ResponseModuleDelegate(Module m)
:
ModuleDelegate(m)
{
    ResponseContextData config;
    m.set_configuration_data(config);
    MemoryManager mm = m.engine().main_memory_mm();

    // Action response =
    Action::create(
        mm,
        "response",
        boost::bind(ResponseAction::generate, _1, _2, _3)
    ).register_with(m.engine());
}

} // Anonymous Namespace

IBPP_BOOTSTRAP_MODULE_DELEGATE("response", ResponseModuleDelegate);
<commit_msg>response.cpp: Using phoenix for all binding.<commit_after>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee --- Response Module
 *
 * @author Sam Baskinger <sbaskinger@qualys.com>
 */

#include <ironbee/path.h>

#include <ironbeepp/action.hpp>
#include <ironbeepp/configuration_parser.hpp>
#include <ironbeepp/module.hpp>
#include <ironbeepp/module_delegate.hpp>
#include <ironbeepp/module_bootstrap.hpp>
#include <ironbeepp/memory_manager.hpp>
#include <ironbeepp/transformation.hpp>

#ifdef __clang__
#pragma clang diagnostic push
#if __has_warning("-Wc++11-extensions")
#pragma clang diagnostic ignored "-Wc++11-extensions"
#endif
#if __has_warning("-Wunused-local-typedef")
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#endif
#endif
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>

#include <boost/iostreams/code_converter.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/iostreams/operations.hpp>
#include <boost/iostreams/read.hpp>

#ifdef __clang__
#pragma clang diagnostic pop
#endif

#include <ios>

namespace {

using namespace IronBee;

//! Config structure for response data.
struct ResponseContextData {

};

//! Tx structure for response data.
struct ResponseTxData {

};

//! The response action.
class ResponseAction {
public:
    ResponseAction(IronBee::Engine engine);
    static Action::action_instance_t generate(
        MemoryManager mm,
        Context       ctx,
        const char *  arg
    );

    /**
     * Implement this function object.
     */
    void operator()(const ib_rule_exec_t * rule_exec);
    void addHeader(const std::string& name, const std::string& value);
    void addHeader(const std::vector<std::string>& headers);
    void setStatus(int status);
    void setFile(const std::string& file);

    //! Get the status.
    int status() const;
    const std::string& file() const;

private:
    IronBee::Engine m_engine;
    int m_status;
    std::string m_file;
    ib_parsed_headers_t *m_headers;
};

ResponseAction::ResponseAction(IronBee::Engine engine)
:
    m_engine(engine)
{
    IronBee::throw_if_error(
        ib_parsed_headers_create(&m_headers, engine.main_memory_mm().ib())
    );
}

void ResponseAction::addHeader(
    const std::string& name,
    const std::string& value
)
{
    ib_log_debug(
        m_engine.ib(),
        "Adding header %.*s=%.*s.",
        static_cast<int>(name.length()),
        name.data(),
        static_cast<int>(value.length()),
        value.data()
    );

    IronBee::throw_if_error(
        ib_parsed_headers_add(
            m_headers,
            name.data(),
            name.length(),
            value.data(),
            value.length()
        )
    );
}

void ResponseAction::addHeader(const std::vector<std::string>& headers)
{
    assert(headers.size() == 2 && "Header must be length 2.");
    addHeader(headers[0], headers[1]);
}

int ResponseAction::status() const
{
    return m_status;
}

void ResponseAction::setStatus(int status)
{
    ib_log_debug(
        m_engine.ib(),
        "Setting status to %d.",
        status
    );
    m_status = status;
}

const std::string& ResponseAction::file() const
{
    return m_file;
}

void ResponseAction::setFile(const std::string& file)
{
    ib_log_debug(
        m_engine.ib(),
        "Setting response file to %s.",
        file.c_str()
    );

    ib_status_t rc;
    const ib_cfgparser_t *ib_cp;

    rc = ib_engine_cfgparser_get(m_engine.ib(), &ib_cp);
    if (rc == IB_OK) {
        IronBee::ConstConfigurationParser cp(ib_cp);

        m_file = ib_util_relative_file(
            ib_engine_mm_config_get(m_engine.ib()),
            cp.current_file(),
            file.c_str()
        );

        ib_log_debug(
            m_engine.ib(),
            "Response file set to relative file %s.", m_file.c_str()
        );
    }
    else {
        ib_log_error(
            m_engine.ib(),
            "Failed to get cfg parser. "
            "Cannot set relative path of error page."
        );
        m_file = file;
    }
}

class ResponseModuleDelegate : public ModuleDelegate
{
public:
    ResponseModuleDelegate(Module m);
private:
}; // end class ResponseModuleDelegate

Action::action_instance_t ResponseAction::generate(
    MemoryManager mm,
    Context       ctx,
    const char *  arg
)
{
    // Build a response action that will be populated by the parser.
    ResponseAction r(ctx.engine());

    namespace qi = boost::spirit::qi;
    namespace phoenix = boost::phoenix;

    const char *first = arg;
    const char *last  = first + strlen(arg);

    /* Parse a single comment. */
    bool parse_success = qi::phrase_parse(
        // Range to parse.
        first, last,

        // Begin grammar.
        // Parse the status.
        qi::omit[qi::int_ [ phoenix::bind(&ResponseAction::setStatus, boost::ref(r), qi::_1)]]
        // Optionally parse the headers.
        >> -(
                qi::lit(",") >>
                (
                    qi::as< std::vector< std::string > >()
                    [
                        qi::as_string[+(qi::char_ - ':')] >>
                        qi::omit[qi::lit(":")]    >>
                        qi::as_string[+(qi::char_ - ',')]
                    ]
                    [
                        phoenix::bind(&ResponseAction::addHeader, boost::ref(r), qi::_1)
                    ] % qi::lit(",")
                )
        )
        // Optionally parse the file.
        >> -(
            qi::lit(",") >>
            qi::as_string[+qi::char_][
                phoenix::bind(&ResponseAction::setFile, boost::ref(r), qi::_1)
            ]
        )
        ,
        // End grammar.

        // Skip parser.
        qi::space
    );

    /* If
     * (1) we fully matched
     * (2) parsed successfully
     */
    if (first == last && parse_success) {
        ib_log_debug(
            ctx.engine().ib(),
            "Built response with status %d and content from %s.",
            r.status(),
            r.file().c_str()
        );
        return r;
    }

    BOOST_THROW_EXCEPTION(
        IronBee::einval()
            << IronBee::errinfo_what(
                str(boost::format("Failed to parse argument: %s") % arg)
            )
    );
}

void ResponseAction::operator()(const ib_rule_exec_t * rule_exec)
{
    assert(rule_exec != NULL);
    assert(rule_exec->tx != NULL);

    ib_status_t rc;

    IronBee::MemoryManager mm = IronBee::MemoryManager(rule_exec->tx->mm);

    IronBee::ByteString page_bs;
    boost::iostreams::mapped_file_source page;

    try
    {
        // Throws an error if the file does not exist.
        page.open(m_file);

        if (page.is_open()) {
            page_bs =
                IronBee::ByteString::create_alias(mm, page.data(), page.size());
        }
        else {
            page_bs = IronBee::ByteString::create_alias(mm, "", 0);
        }
    }
    catch (const std::ios_base::failure& e)
    {
        ib_log_error_tx(
            rule_exec->tx,
            "Failed to read error page file %s: %s", m_file.c_str(), e.what()
        );
        page_bs = IronBee::ByteString::create(mm, "", 0);
    }

    rc = ib_tx_response(
        rule_exec->tx,
        m_status,
        m_headers,
        page_bs.ib()
    );
    if (rc != IB_OK) {
        ib_log_debug_tx(rule_exec->tx, "Failed to send custom response.");
    }

    // Close out here because we want the file to stay mapped until
    // the response is delivered.
    if (page.is_open()) {
        page.close();
    }

}

ResponseModuleDelegate::ResponseModuleDelegate(Module m)
:
ModuleDelegate(m)
{
    ResponseContextData config;
    m.set_configuration_data(config);
    MemoryManager mm = m.engine().main_memory_mm();

    // Action response =
    Action::create(
        mm,
        "response",
        boost::bind(ResponseAction::generate, _1, _2, _3)
    ).register_with(m.engine());
}

} // Anonymous Namespace

IBPP_BOOTSTRAP_MODULE_DELEGATE("response", ResponseModuleDelegate);
<|endoftext|>


<commit_before>#include <stdexcept>
#include <cassert>

#include <boost/regex.hpp>
#include <boost/optional.hpp>

#include "move_generation.hpp"
#include "direction.hpp"

using namespace directions;

// after https://chessprogramming.wikispaces.com/Hyperbola+Quintessence
Bitboard moves::slides(const Bitboard occupancy, const Bitboard piece, const Bitboard mobility) {
  Bitboard forward, reverse;
  assert((mobility & piece) == 0);
  forward = occupancy & mobility;
  reverse  = __builtin_bswap64(forward);
  forward -= piece;
  reverse -= __builtin_bswap64(piece);
  forward ^= __builtin_bswap64(reverse);
  forward &= mobility;
  return forward;
}

Bitboard rank_onto_a1h8(Bitboard b, const ranks::Index& rank) {
  // put the bits for the relevant rank into LSB
  b = (b >> rank * directions::vertical) & 0xff;
  // map LSB onto a1h8 diagonal
  b = (b * 0x0101010101010101) & giadonals::bitboards::a1h8;
  return b;
}

Bitboard a1h8_onto_rank(Bitboard b, const ranks::Index& rank) {
  b &= giadonals::bitboards::a1h8;
  // map diagonal onto MSB
  b *= 0x0101010101010101;
  // down to LSB, dropping everything except MSB
  b /= 0x0100000000000000;
  // shift up to the desired rank
  b <<= rank * directions::vertical;
  return b;
}

// like slides, but for attacks by a single rook along a rank.  slides() doesn't work for
// that because the byteswap does not reverse the relevant bits; they are all in the same
// byte.
Bitboard moves::slides_rank(Bitboard occupancy, Bitboard piece, const ranks::Index rank) {
  occupancy = rank_onto_a1h8(occupancy, rank);
  piece     = rank_onto_a1h8(piece,     rank);
  Bitboard attacks = slides(occupancy, piece, giadonals::bitboards::a1h8 & ~piece);
  return a1h8_onto_rank(attacks, rank);
}

const std::vector<moves::PawnDingbat>& moves::get_pawn_dingbats() {
  using namespace ranks::bitboards;
  static std::vector<PawnDingbat> pawn_dingbats = {
    { vertical, 0, _4, _8 },
    { 0, vertical, _5, _1 },
  };
  return pawn_dingbats;
}

const std::vector<moves::PawnAttackType>& moves::get_pawn_attack_types() {
  using namespace files::bitboards;
  static std::vector<PawnAttackType> result = {
    { 0, horizontal, h },
    { horizontal, 0, a },
  };
  return result;
}

const std::vector<moves::KnightAttackType>& moves::get_knight_attack_types() {
  using namespace files::bitboards;
  static std::vector<KnightAttackType> result = {
    {2*vertical +   horizontal,                         0, a     },
    {               horizontal, 2*vertical               , a     },
    {2*vertical               ,                horizontal, h     },
    {                        0, 2*vertical +   horizontal, h     },
    {  vertical + 2*horizontal,                         0, a | b },
    {             2*horizontal,   vertical               , a | b },
    {  vertical               ,              2*horizontal, g | h },
    {                        0,   vertical + 2*horizontal, g | h },
  };
  return result;
}

Bitboard moves::pawn_attacks(const Bitboard pawn, const PawnDingbat& pd, const PawnAttackType& pa) {
  return (pawn << (pd.leftshift + pa.leftshift) >> (pd.rightshift + pa.rightshift)) & ~pa.badtarget;
}

Bitboard moves::knight_attacks(const Bitboard knight, const KnightAttackType& ka) {
  return (knight << ka.leftshift >> ka.rightshift) & ~ka.badtarget;
}

Bitboard moves::bishop_attacks(const Bitboard occupancy, const squares::Index source) {
  Bitboard piece = squares::bitboard(source);
  return
    slides(occupancy, piece, diagonals::bitboards::by_square(source) & ~piece) |
    slides(occupancy, piece, giadonals::bitboards::by_square(source) & ~piece);
}

Bitboard moves::rook_attacks(const Bitboard occupancy, const squares::Index source) {
  Bitboard piece = squares::bitboard(source);
  return
    slides     (occupancy, piece, files::bitboards::by_square(source) & ~piece) |
    slides_rank(occupancy, piece, ranks::by_square(source));
}

Bitboard moves::queen_attacks(const Bitboard occupancy, const squares::Index source) {
  return bishop_attacks(occupancy, source) | rook_attacks(occupancy, source);
}

Bitboard moves::king_attacks(const Bitboard king) {
  using namespace files::bitboards;
  Bitboard leftright = ((king & ~a) >> horizontal) | ((king & ~h) << horizontal);
  Bitboard triple = leftright | king;
  return leftright | (triple << vertical) | (triple >> vertical);
}

// NOTE: includes attacks on own pieces
Bitboard moves::attacks(const Color us, const Bitboard occupancy, const Halfboard& attackers) {
  Bitboard attacks = 0;

  for (PawnAttackType pa: get_pawn_attack_types())
    attacks |= pawn_attacks(attackers[pieces::pawn], get_pawn_dingbats()[us], pa);

  for (KnightAttackType ka: get_knight_attack_types())
    attacks |= knight_attacks(attackers[pieces::knight], ka);

  // TODO: dry up
  squares::do_bits(attackers[pieces::bishop], [&attacks, &occupancy](squares::Index source) {
      attacks |= bishop_attacks(occupancy, source);
    });

  squares::do_bits(attackers[pieces::rook], [&attacks, &occupancy](squares::Index source) {
      attacks |= rook_attacks(occupancy, source);
    });

  squares::do_bits(attackers[pieces::queen], [&attacks, &occupancy](squares::Index source) {
      attacks |= queen_attacks(occupancy, source);
    });

  return attacks | king_attacks(attackers[pieces::king]);
}

enum Relativity {
  absolute=0, relative = 1
};

// Generate moves from the set of targets.  `source' is the index of the source square, either
// relative to the target or absolute.  The moves are added to the `moves' vector.
void moves_from_targets(std::vector<Move>& moves, const Bitboard targets, const int source_offset, const Relativity relative, const MoveType type) {
  squares::do_bits(targets, [&moves, &relative, &source_offset, &type](squares::Index target) {
      squares::Index source = static_cast<squares::Index>(relative*target + source_offset);
      moves.push_back(Move(source, target, type));
    });
}

// Generate normal and capturing moves from the set of attacks.
void moves_from_attacks(std::vector<Move>& moves, const Bitboard attacks,
                        const Bitboard us, const Bitboard them,
                        const int source, const Relativity relativity) {
  moves_from_targets(moves, attacks & ~us & ~them, source, relativity, move_types::normal);
  assert((us & them) == 0);
  moves_from_targets(moves, attacks & them, source, relativity, move_types::capture);
}

void moves::pawn(std::vector<Move>& moves,
                 const Color us, const Color them,
                 const Bitboard pawn, const Occupancy& occupancy,
                 const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);

  const PawnDingbat &pd = get_pawn_dingbats()[us];

  short direction = pd.leftshift - pd.rightshift;

#define FORWARD(pawn) ((pawn) << pd.leftshift >> pd.rightshift)
  // single push
  Bitboard single_push_targets = FORWARD(pawn) & ~flat_occupancy;
  moves_from_targets(moves, single_push_targets & ~pd.promotion_rank, -direction, relative, move_types::normal);
  Bitboard promotion_targets = single_push_targets & pd.promotion_rank;
  if (promotion_targets != 0) {
    for (MoveType promotion: {move_types::promotion_knight, move_types::promotion_bishop,
                              move_types::promotion_rook,   move_types::promotion_queen}) {
      moves_from_targets(moves, promotion_targets, -direction, relative, promotion);
    }
  }

  // double push
  Bitboard double_push_targets = FORWARD(FORWARD(pawn) & ~flat_occupancy) & pd.double_push_target_rank & ~flat_occupancy;
  moves_from_targets(moves, double_push_targets, -2*direction, relative, move_types::double_push);
#undef FORWARD

  // captures
  for (const PawnAttackType& pa: get_pawn_attack_types()) {
    direction = pd.leftshift - pd.rightshift + pa.leftshift - pa.rightshift;

    Bitboard capture_targets = pawn_attacks(pawn, pd, pa) & (occupancy[them] | en_passant_square);
    moves_from_targets(moves, capture_targets & ~pd.promotion_rank, -direction, relative, move_types::capture);
    promotion_targets = capture_targets & pd.promotion_rank;
    if (promotion_targets != 0) {
      for (MoveType promotion: {move_types::capturing_promotion_knight, move_types::capturing_promotion_bishop,
                                move_types::capturing_promotion_rook,   move_types::capturing_promotion_queen}) {
        moves_from_targets(moves, promotion_targets, -direction, relative, promotion);
      }
    }
  }
}

void moves::knight(std::vector<Move>& moves,
                   const Color us, const Color them,
                   const Bitboard knight, const Occupancy& occupancy,
                   const Bitboard en_passant_square) {
  for (KnightAttackType ka: get_knight_attack_types()) {
    moves_from_attacks(moves, knight_attacks(knight, ka),
                       occupancy[us], occupancy[them], -(ka.leftshift - ka.rightshift), relative);
  }
}

void moves::bishop(std::vector<Move>& moves,
                   const Color us, const Color them,
                   const Bitboard bishop, const Occupancy& occupancy,
                   const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);
  squares::do_bits(bishop, [&moves, &us, &them, &occupancy, &flat_occupancy](squares::Index source) {
      moves_from_attacks(moves, bishop_attacks(flat_occupancy, source), occupancy[us], occupancy[them], source, absolute);
    });
}

void moves::rook(std::vector<Move>& moves,
                 const Color us, const Color them,
                 const Bitboard rook, const Occupancy& occupancy,
                 const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);
  squares::do_bits(rook, [&moves, &us, &them, &occupancy, &flat_occupancy](squares::Index source) {
      moves_from_attacks(moves, rook_attacks(flat_occupancy, source), occupancy[us], occupancy[them], source, absolute);
    });
}

void moves::queen(std::vector<Move>& moves,
                  const Color us, const Color them,
                  const Bitboard queen, const Occupancy& occupancy,
                  const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);
  squares::do_bits(queen, [&moves, &us, &them, &occupancy, &flat_occupancy](squares::Index source) {
      moves_from_attacks(moves, queen_attacks(flat_occupancy, source), occupancy[us], occupancy[them], source, absolute);
    });
}

void moves::king(std::vector<Move>& moves,
                 const Color us, const Color them,
                 const Bitboard king, const Occupancy& occupancy,
                 const Bitboard en_passant_square) {
  moves_from_attacks(moves, king_attacks(king), occupancy[us], occupancy[them], squares::index(king), absolute);
}

// NOTE: can_castle_{king,queen}side convey that castling rights have not been lost,
// i.e., the king and the relevant rook have not moved
void moves::castle(std::vector<Move>& moves,
                   const Color us, const Color them,
                   const Occupancy& occupancy,
                   const Bitboard their_attacks,
                   const CastlingRights& castling_rights) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);

  using namespace squares;

  for (Castle castle: castles::values) {
    if (castling_rights[us][castle]
        && bitboard::is_empty(castles::safe_squares(us, castle) & their_attacks)
        && bitboard::is_empty(castles::free_squares(us, castle) & flat_occupancy))
      moves.push_back(Move::castle(us, castle));
  }
}

void moves::moves(std::vector<Move>& moves,
                  const Color us, const Color them,
                  const Board& board, const Occupancy& occupancy,
                  const Bitboard their_attacks,
                  const Bitboard en_passant_square,
                  const CastlingRights& castling_rights) {
#define GENERATE_MOVES(piece) moves::piece(moves, us, them, board[us][pieces::piece], occupancy, en_passant_square)
  GENERATE_MOVES(pawn);
  GENERATE_MOVES(knight);
  GENERATE_MOVES(bishop);
  GENERATE_MOVES(rook);
  GENERATE_MOVES(queen);
  GENERATE_MOVES(king);
#undef GENERATE_MOVES
  castle(moves, us, them, occupancy, their_attacks, castling_rights);
}
<commit_msg>less std::function, more speed<commit_after>#include <stdexcept>
#include <cassert>

#include <boost/regex.hpp>
#include <boost/optional.hpp>

#include "move_generation.hpp"
#include "direction.hpp"

using namespace directions;

// after https://chessprogramming.wikispaces.com/Hyperbola+Quintessence
Bitboard moves::slides(const Bitboard occupancy, const Bitboard piece, const Bitboard mobility) {
  Bitboard forward, reverse;
  assert((mobility & piece) == 0);
  forward = occupancy & mobility;
  reverse  = __builtin_bswap64(forward);
  forward -= piece;
  reverse -= __builtin_bswap64(piece);
  forward ^= __builtin_bswap64(reverse);
  forward &= mobility;
  return forward;
}

Bitboard rank_onto_a1h8(Bitboard b, const ranks::Index& rank) {
  // put the bits for the relevant rank into LSB
  b = (b >> rank * directions::vertical) & 0xff;
  // map LSB onto a1h8 diagonal
  b = (b * 0x0101010101010101) & giadonals::bitboards::a1h8;
  return b;
}

Bitboard a1h8_onto_rank(Bitboard b, const ranks::Index& rank) {
  b &= giadonals::bitboards::a1h8;
  // map diagonal onto MSB
  b *= 0x0101010101010101;
  // down to LSB, dropping everything except MSB
  b /= 0x0100000000000000;
  // shift up to the desired rank
  b <<= rank * directions::vertical;
  return b;
}

// like slides, but for attacks by a single rook along a rank.  slides() doesn't work for
// that because the byteswap does not reverse the relevant bits; they are all in the same
// byte.
Bitboard moves::slides_rank(Bitboard occupancy, Bitboard piece, const ranks::Index rank) {
  occupancy = rank_onto_a1h8(occupancy, rank);
  piece     = rank_onto_a1h8(piece,     rank);
  Bitboard attacks = slides(occupancy, piece, giadonals::bitboards::a1h8 & ~piece);
  return a1h8_onto_rank(attacks, rank);
}

const std::vector<moves::PawnDingbat>& moves::get_pawn_dingbats() {
  using namespace ranks::bitboards;
  static std::vector<PawnDingbat> pawn_dingbats = {
    { vertical, 0, _4, _8 },
    { 0, vertical, _5, _1 },
  };
  return pawn_dingbats;
}

const std::vector<moves::PawnAttackType>& moves::get_pawn_attack_types() {
  using namespace files::bitboards;
  static std::vector<PawnAttackType> result = {
    { 0, horizontal, h },
    { horizontal, 0, a },
  };
  return result;
}

const std::vector<moves::KnightAttackType>& moves::get_knight_attack_types() {
  using namespace files::bitboards;
  static std::vector<KnightAttackType> result = {
    {2*vertical +   horizontal,                         0, a     },
    {               horizontal, 2*vertical               , a     },
    {2*vertical               ,                horizontal, h     },
    {                        0, 2*vertical +   horizontal, h     },
    {  vertical + 2*horizontal,                         0, a | b },
    {             2*horizontal,   vertical               , a | b },
    {  vertical               ,              2*horizontal, g | h },
    {                        0,   vertical + 2*horizontal, g | h },
  };
  return result;
}

Bitboard moves::pawn_attacks(const Bitboard pawn, const PawnDingbat& pd, const PawnAttackType& pa) {
  return (pawn << (pd.leftshift + pa.leftshift) >> (pd.rightshift + pa.rightshift)) & ~pa.badtarget;
}

Bitboard moves::knight_attacks(const Bitboard knight, const KnightAttackType& ka) {
  return (knight << ka.leftshift >> ka.rightshift) & ~ka.badtarget;
}

Bitboard moves::bishop_attacks(const Bitboard occupancy, const squares::Index source) {
  Bitboard piece = squares::bitboard(source);
  return
    slides(occupancy, piece, diagonals::bitboards::by_square(source) & ~piece) |
    slides(occupancy, piece, giadonals::bitboards::by_square(source) & ~piece);
}

Bitboard moves::rook_attacks(const Bitboard occupancy, const squares::Index source) {
  Bitboard piece = squares::bitboard(source);
  return
    slides     (occupancy, piece, files::bitboards::by_square(source) & ~piece) |
    slides_rank(occupancy, piece, ranks::by_square(source));
}

Bitboard moves::queen_attacks(const Bitboard occupancy, const squares::Index source) {
  return bishop_attacks(occupancy, source) | rook_attacks(occupancy, source);
}

Bitboard moves::king_attacks(const Bitboard king) {
  using namespace files::bitboards;
  Bitboard leftright = ((king & ~a) >> horizontal) | ((king & ~h) << horizontal);
  Bitboard triple = leftright | king;
  return leftright | (triple << vertical) | (triple >> vertical);
}

// NOTE: includes attacks on own pieces
Bitboard moves::attacks(const Color us, const Bitboard occupancy, const Halfboard& attackers) {
  Bitboard attacks = 0;

  for (PawnAttackType pa: get_pawn_attack_types())
    attacks |= pawn_attacks(attackers[pieces::pawn], get_pawn_dingbats()[us], pa);

  for (KnightAttackType ka: get_knight_attack_types())
    attacks |= knight_attacks(attackers[pieces::knight], ka);

  // TODO: dry up
  Bitboard b;

  b = attackers[pieces::bishop];
  while (!bitboard::is_empty(b)) {
    squares::Index source = static_cast<squares::Index>(bitboard::scan_forward_with_reset(b));
    attacks |= bishop_attacks(occupancy, source);
  }

  b = attackers[pieces::rook];
  while (!bitboard::is_empty(b)) {
    squares::Index source = static_cast<squares::Index>(bitboard::scan_forward_with_reset(b));
    attacks |= rook_attacks(occupancy, source);
  }

  b = attackers[pieces::queen];
  while (!bitboard::is_empty(b)) {
    squares::Index source = static_cast<squares::Index>(bitboard::scan_forward_with_reset(b));
    attacks |= queen_attacks(occupancy, source);
  }

  return attacks | king_attacks(attackers[pieces::king]);
}

enum Relativity {
  absolute=0, relative = 1
};

// Generate moves from the set of targets.  `source' is the index of the source square, either
// relative to the target or absolute.  The moves are added to the `moves' vector.
void moves_from_targets(std::vector<Move>& moves, Bitboard targets, const int source_offset, const Relativity relative, const MoveType type) {
  while (!bitboard::is_empty(targets)) {
    squares::Index target = static_cast<squares::Index>(bitboard::scan_forward_with_reset(targets));
    squares::Index source = static_cast<squares::Index>(relative*target + source_offset);
    moves.push_back(Move(source, target, type));
  }
}

// Generate normal and capturing moves from the set of attacks.
void moves_from_attacks(std::vector<Move>& moves, const Bitboard attacks,
                        const Bitboard us, const Bitboard them,
                        const int source, const Relativity relativity) {
  moves_from_targets(moves, attacks & ~us & ~them, source, relativity, move_types::normal);
  assert((us & them) == 0);
  moves_from_targets(moves, attacks & them, source, relativity, move_types::capture);
}

void moves::pawn(std::vector<Move>& moves,
                 const Color us, const Color them,
                 const Bitboard pawn, const Occupancy& occupancy,
                 const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);

  const PawnDingbat &pd = get_pawn_dingbats()[us];

  short direction = pd.leftshift - pd.rightshift;

#define FORWARD(pawn) ((pawn) << pd.leftshift >> pd.rightshift)
  // single push
  Bitboard single_push_targets = FORWARD(pawn) & ~flat_occupancy;
  moves_from_targets(moves, single_push_targets & ~pd.promotion_rank, -direction, relative, move_types::normal);
  Bitboard promotion_targets = single_push_targets & pd.promotion_rank;
  if (promotion_targets != 0) {
    for (MoveType promotion: {move_types::promotion_knight, move_types::promotion_bishop,
                              move_types::promotion_rook,   move_types::promotion_queen}) {
      moves_from_targets(moves, promotion_targets, -direction, relative, promotion);
    }
  }

  // double push
  Bitboard double_push_targets = FORWARD(FORWARD(pawn) & ~flat_occupancy) & pd.double_push_target_rank & ~flat_occupancy;
  moves_from_targets(moves, double_push_targets, -2*direction, relative, move_types::double_push);
#undef FORWARD

  // captures
  for (const PawnAttackType& pa: get_pawn_attack_types()) {
    direction = pd.leftshift - pd.rightshift + pa.leftshift - pa.rightshift;

    Bitboard capture_targets = pawn_attacks(pawn, pd, pa) & (occupancy[them] | en_passant_square);
    moves_from_targets(moves, capture_targets & ~pd.promotion_rank, -direction, relative, move_types::capture);
    promotion_targets = capture_targets & pd.promotion_rank;
    if (promotion_targets != 0) {
      for (MoveType promotion: {move_types::capturing_promotion_knight, move_types::capturing_promotion_bishop,
                                move_types::capturing_promotion_rook,   move_types::capturing_promotion_queen}) {
        moves_from_targets(moves, promotion_targets, -direction, relative, promotion);
      }
    }
  }
}

void moves::knight(std::vector<Move>& moves,
                   const Color us, const Color them,
                   const Bitboard knight, const Occupancy& occupancy,
                   const Bitboard en_passant_square) {
  for (KnightAttackType ka: get_knight_attack_types()) {
    moves_from_attacks(moves, knight_attacks(knight, ka),
                       occupancy[us], occupancy[them], -(ka.leftshift - ka.rightshift), relative);
  }
}

void moves::bishop(std::vector<Move>& moves,
                   const Color us, const Color them,
                   Bitboard bishop, const Occupancy& occupancy,
                   const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);
  while (!bitboard::is_empty(bishop)) {
    squares::Index source = static_cast<squares::Index>(bitboard::scan_forward_with_reset(bishop));
    moves_from_attacks(moves, bishop_attacks(flat_occupancy, source), occupancy[us], occupancy[them], source, absolute);
  }
}

void moves::rook(std::vector<Move>& moves,
                 const Color us, const Color them,
                 Bitboard rook, const Occupancy& occupancy,
                 const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);
  while (!bitboard::is_empty(rook)) {
    squares::Index source = static_cast<squares::Index>(bitboard::scan_forward_with_reset(rook));
    moves_from_attacks(moves, rook_attacks(flat_occupancy, source), occupancy[us], occupancy[them], source, absolute);
  }
}

void moves::queen(std::vector<Move>& moves,
                  const Color us, const Color them,
                  Bitboard queen, const Occupancy& occupancy,
                  const Bitboard en_passant_square) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);
  while (!bitboard::is_empty(queen)) {
    squares::Index source = static_cast<squares::Index>(bitboard::scan_forward_with_reset(queen));
    moves_from_attacks(moves, queen_attacks(flat_occupancy, source), occupancy[us], occupancy[them], source, absolute);
  }
}

void moves::king(std::vector<Move>& moves,
                 const Color us, const Color them,
                 const Bitboard king, const Occupancy& occupancy,
                 const Bitboard en_passant_square) {
  moves_from_attacks(moves, king_attacks(king), occupancy[us], occupancy[them], squares::index(king), absolute);
}

// NOTE: can_castle_{king,queen}side convey that castling rights have not been lost,
// i.e., the king and the relevant rook have not moved
void moves::castle(std::vector<Move>& moves,
                   const Color us, const Color them,
                   const Occupancy& occupancy,
                   const Bitboard their_attacks,
                   const CastlingRights& castling_rights) {
  Bitboard flat_occupancy;
  board::flatten(occupancy, flat_occupancy);

  using namespace squares;

  for (Castle castle: castles::values) {
    if (castling_rights[us][castle]
        && bitboard::is_empty(castles::safe_squares(us, castle) & their_attacks)
        && bitboard::is_empty(castles::free_squares(us, castle) & flat_occupancy))
      moves.push_back(Move::castle(us, castle));
  }
}

void moves::moves(std::vector<Move>& moves,
                  const Color us, const Color them,
                  const Board& board, const Occupancy& occupancy,
                  const Bitboard their_attacks,
                  const Bitboard en_passant_square,
                  const CastlingRights& castling_rights) {
#define GENERATE_MOVES(piece) moves::piece(moves, us, them, board[us][pieces::piece], occupancy, en_passant_square)
  GENERATE_MOVES(pawn);
  GENERATE_MOVES(knight);
  GENERATE_MOVES(bishop);
  GENERATE_MOVES(rook);
  GENERATE_MOVES(queen);
  GENERATE_MOVES(king);
#undef GENERATE_MOVES
  castle(moves, us, them, occupancy, their_attacks, castling_rights);
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// TODO: Make this test pass for all standards.
// XFAIL: c++98, c++03

// <type_traits>

// __convert_to_integral(Tp)

// Test that the __convert_to_integral functions properly converts Tp to the
// correct type and value for integral, enum and user defined types.

#include <limits>
#include <type_traits>
#include <cstdint>
#include <cassert>

#include "user_defined_integral.hpp"

template <class T>
struct EnumType
{
  enum type : T {E_zero, E_one};
};

template <class From, class To>
void check_integral_types()
{
  typedef std::numeric_limits<From> Limits;
  const From max = Limits::max();
  const From min = Limits::min();
  {
  auto ret = std::__convert_to_integral((From)max);
  assert(ret == max);
  ret = std::__convert_to_integral((From)min);
  assert(ret == min);
  static_assert(std::is_same<decltype(ret), To>::value, "");
  }
  {
  UserDefinedIntegral<From> f(max);
  auto ret = std::__convert_to_integral(f);
  assert(ret == max);
  f.value = min;
  ret = std::__convert_to_integral(f);
  assert(ret == min);
  static_assert(std::is_same<decltype(ret), To>::value, "");
  }
  {
  typedef typename EnumType<From>::type Enum;
  Enum e(static_cast<Enum>(max));
  auto ret = std::__convert_to_integral(e);
  assert(ret == max);
  e = static_cast<Enum>(min);
  ret = std::__convert_to_integral(min);
  assert(ret == min);
  static_assert(std::is_same<decltype(ret), To>::value, "");
  }
}

template <class From, class To>
void check_enum_types()
{
  auto ret = std::__convert_to_integral((From)1);
  assert(ret == 1);
  static_assert(std::is_same<decltype(ret), To>::value, "");
}

enum enum1 { zero = 0, one = 1 };
enum enum2 {
  value = std::numeric_limits<unsigned long>::max()
};

int main()
{
  check_integral_types<bool, int>();
  check_integral_types<char, int>();
  check_integral_types<signed char, int>();
  check_integral_types<unsigned char, int>();
  check_integral_types<wchar_t, decltype(((wchar_t)1) + 1)>();
  check_integral_types<char16_t, int>();
  check_integral_types<char32_t, uint32_t>();
  check_integral_types<short, int>();
  check_integral_types<unsigned short, int>();
  check_integral_types<int, int>();
  check_integral_types<unsigned, unsigned>();
  check_integral_types<long, long>();
  check_integral_types<unsigned long, unsigned long>();
  check_integral_types<long long, long long>();
  check_integral_types<unsigned long long, unsigned long long>();
#ifndef _LIBCPP_HAS_NO_INT128
  check_integral_types<__int128_t, __int128_t>();
  check_integral_types<__uint128_t, __uint128_t>();
#endif
    // TODO(ericwf): Not standard
  typedef std::underlying_type<enum1>::type Enum1UT;
  check_enum_types<enum1, decltype(((Enum1UT)1) + 1)>();
  typedef std::underlying_type<enum2>::type Enum2UT;
  check_enum_types<enum2, decltype(((Enum2UT)1) + 1)>();
}
<commit_msg>test: explicitly size enumeration<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// TODO: Make this test pass for all standards.
// XFAIL: c++98, c++03

// <type_traits>

// __convert_to_integral(Tp)

// Test that the __convert_to_integral functions properly converts Tp to the
// correct type and value for integral, enum and user defined types.

#include <limits>
#include <type_traits>
#include <cstdint>
#include <cassert>

#include "user_defined_integral.hpp"

template <class T>
struct EnumType
{
  enum type : T {E_zero, E_one};
};

template <class From, class To>
void check_integral_types()
{
  typedef std::numeric_limits<From> Limits;
  const From max = Limits::max();
  const From min = Limits::min();
  {
  auto ret = std::__convert_to_integral((From)max);
  assert(ret == max);
  ret = std::__convert_to_integral((From)min);
  assert(ret == min);
  static_assert(std::is_same<decltype(ret), To>::value, "");
  }
  {
  UserDefinedIntegral<From> f(max);
  auto ret = std::__convert_to_integral(f);
  assert(ret == max);
  f.value = min;
  ret = std::__convert_to_integral(f);
  assert(ret == min);
  static_assert(std::is_same<decltype(ret), To>::value, "");
  }
  {
  typedef typename EnumType<From>::type Enum;
  Enum e(static_cast<Enum>(max));
  auto ret = std::__convert_to_integral(e);
  assert(ret == max);
  e = static_cast<Enum>(min);
  ret = std::__convert_to_integral(min);
  assert(ret == min);
  static_assert(std::is_same<decltype(ret), To>::value, "");
  }
}

template <class From, class To>
void check_enum_types()
{
  auto ret = std::__convert_to_integral((From)1);
  assert(ret == 1);
  static_assert(std::is_same<decltype(ret), To>::value, "");
}

enum enum1 { zero = 0, one = 1 };
enum enum2 : unsigned long {
  value = std::numeric_limits<unsigned long>::max()
};

int main()
{
  check_integral_types<bool, int>();
  check_integral_types<char, int>();
  check_integral_types<signed char, int>();
  check_integral_types<unsigned char, int>();
  check_integral_types<wchar_t, decltype(((wchar_t)1) + 1)>();
  check_integral_types<char16_t, int>();
  check_integral_types<char32_t, uint32_t>();
  check_integral_types<short, int>();
  check_integral_types<unsigned short, int>();
  check_integral_types<int, int>();
  check_integral_types<unsigned, unsigned>();
  check_integral_types<long, long>();
  check_integral_types<unsigned long, unsigned long>();
  check_integral_types<long long, long long>();
  check_integral_types<unsigned long long, unsigned long long>();
#ifndef _LIBCPP_HAS_NO_INT128
  check_integral_types<__int128_t, __int128_t>();
  check_integral_types<__uint128_t, __uint128_t>();
#endif
    // TODO(ericwf): Not standard
  typedef std::underlying_type<enum1>::type Enum1UT;
  check_enum_types<enum1, decltype(((Enum1UT)1) + 1)>();
  typedef std::underlying_type<enum2>::type Enum2UT;
  check_enum_types<enum2, decltype(((Enum2UT)1) + 1)>();
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_proxy_client_socket_pool.h"

#include <algorithm>

#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
#include "net/http/http_network_session.h"
#include "net/http/http_proxy_client_socket.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/tcp_client_socket_pool.h"

namespace net {

HttpProxySocketParams::HttpProxySocketParams(
    const scoped_refptr<TCPSocketParams>& tcp_params,
    const scoped_refptr<SSLSocketParams>& ssl_params,
    const GURL& request_url,
    const std::string& user_agent,
    HostPortPair endpoint,
    scoped_refptr<HttpNetworkSession> session,
    bool tunnel)
    : tcp_params_(tcp_params),
      ssl_params_(ssl_params),
      request_url_(request_url),
      user_agent_(user_agent),
      endpoint_(endpoint),
      session_(tunnel ? session : NULL),
      tunnel_(tunnel) {
  DCHECK((tcp_params == NULL && ssl_params != NULL) ||
         (tcp_params != NULL && ssl_params == NULL));
}

const HostResolver::RequestInfo& HttpProxySocketParams::destination() const {
  if (tcp_params_ == NULL)
    return ssl_params_->tcp_params()->destination();
  else
    return tcp_params_->destination();
}

HttpProxySocketParams::~HttpProxySocketParams() {}

// HttpProxyConnectJobs will time out after this many seconds.  Note this is on
// top of the timeout for the transport socket.
static const int kHttpProxyConnectJobTimeoutInSeconds = 30;

HttpProxyConnectJob::HttpProxyConnectJob(
    const std::string& group_name,
    const scoped_refptr<HttpProxySocketParams>& params,
    const base::TimeDelta& timeout_duration,
    const scoped_refptr<TCPClientSocketPool>& tcp_pool,
    const scoped_refptr<SSLClientSocketPool>& ssl_pool,
    const scoped_refptr<HostResolver>& host_resolver,
    Delegate* delegate,
    NetLog* net_log)
    : ConnectJob(group_name, timeout_duration, delegate,
                 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
      params_(params),
      tcp_pool_(tcp_pool),
      ssl_pool_(ssl_pool),
      resolver_(host_resolver),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          callback_(this, &HttpProxyConnectJob::OnIOComplete)) {
}

HttpProxyConnectJob::~HttpProxyConnectJob() {}

LoadState HttpProxyConnectJob::GetLoadState() const {
  switch (next_state_) {
    case kStateTCPConnect:
    case kStateTCPConnectComplete:
    case kStateSSLConnect:
    case kStateSSLConnectComplete:
      return transport_socket_handle_->GetLoadState();
    case kStateHttpProxyConnect:
    case kStateHttpProxyConnectComplete:
      return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL;
    default:
      NOTREACHED();
      return LOAD_STATE_IDLE;
  }
}

int HttpProxyConnectJob::ConnectInternal() {
  if (params_->tcp_params())
    next_state_ = kStateTCPConnect;
  else
    next_state_ = kStateSSLConnect;
  return DoLoop(OK);
}

void HttpProxyConnectJob::OnIOComplete(int result) {
  int rv = DoLoop(result);
  if (rv != ERR_IO_PENDING)
    NotifyDelegateOfCompletion(rv);  // Deletes |this|
}

int HttpProxyConnectJob::DoLoop(int result) {
  DCHECK_NE(next_state_, kStateNone);

  int rv = result;
  do {
    State state = next_state_;
    next_state_ = kStateNone;
    switch (state) {
      case kStateTCPConnect:
        DCHECK_EQ(OK, rv);
        rv = DoTCPConnect();
        break;
      case kStateTCPConnectComplete:
        rv = DoTCPConnectComplete(rv);
        break;
      case kStateSSLConnect:
        DCHECK_EQ(OK, rv);
        rv = DoSSLConnect();
        break;
      case kStateSSLConnectComplete:
        rv = DoSSLConnectComplete(rv);
        break;
      case kStateHttpProxyConnect:
        DCHECK_EQ(OK, rv);
        rv = DoHttpProxyConnect();
        break;
      case kStateHttpProxyConnectComplete:
        rv = DoHttpProxyConnectComplete(rv);
        break;
      default:
        NOTREACHED() << "bad state";
        rv = ERR_FAILED;
        break;
    }
  } while (rv != ERR_IO_PENDING && next_state_ != kStateNone);

  return rv;
}

int HttpProxyConnectJob::DoTCPConnect() {
  next_state_ = kStateTCPConnectComplete;
  transport_socket_handle_.reset(new ClientSocketHandle());
  return transport_socket_handle_->Init(
      group_name(), params_->tcp_params(),
      params_->tcp_params()->destination().priority(), &callback_, tcp_pool_,
      net_log());
}

int HttpProxyConnectJob::DoTCPConnectComplete(int result) {
  if (result != OK)
    return result;

  // Reset the timer to just the length of time allowed for HttpProxy handshake
  // so that a fast TCP connection plus a slow HttpProxy failure doesn't take
  // longer to timeout than it should.
  ResetTimer(base::TimeDelta::FromSeconds(
      kHttpProxyConnectJobTimeoutInSeconds));
  next_state_ = kStateHttpProxyConnect;
  return result;
}

int HttpProxyConnectJob::DoSSLConnect() {
  next_state_ = kStateSSLConnectComplete;
  transport_socket_handle_.reset(new ClientSocketHandle());
  return transport_socket_handle_->Init(
      group_name(), params_->ssl_params(),
      params_->ssl_params()->tcp_params()->destination().priority(),
      &callback_, ssl_pool_, net_log());
}

int HttpProxyConnectJob::DoSSLConnectComplete(int result) {
  if (result < 0) {
    if (transport_socket_handle_->socket())
      transport_socket_handle_->socket()->Disconnect();
    return result;
  }

  // Reset the timer to just the length of time allowed for HttpProxy handshake
  // so that a fast SSL connection plus a slow HttpProxy failure doesn't take
  // longer to timeout than it should.
  ResetTimer(base::TimeDelta::FromSeconds(
      kHttpProxyConnectJobTimeoutInSeconds));
  next_state_ = kStateHttpProxyConnect;
  return result;
}

int HttpProxyConnectJob::DoHttpProxyConnect() {
  next_state_ = kStateHttpProxyConnectComplete;
  const HostResolver::RequestInfo& tcp_destination = params_->destination();
  HostPortPair proxy_server(tcp_destination.hostname(),
                            tcp_destination.port());

  // Add a HttpProxy connection on top of the tcp socket.
  transport_socket_.reset(
      new HttpProxyClientSocket(transport_socket_handle_.release(),
                                params_->request_url(),
                                params_->user_agent(),
                                params_->endpoint(),
                                proxy_server, params_->session(),
                                params_->tunnel()));
  int result = transport_socket_->Connect(&callback_);

  // Clear the circular reference to HttpNetworkSession (|params_| reference
  // HttpNetworkSession, which reference HttpProxyClientSocketPool, which
  // references |this|) here because it is safe to do so now but not at other
  // points.  This may cancel this ConnectJob.
  params_ = NULL;
  return result;
}

int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) {
  if (result == OK || result == ERR_PROXY_AUTH_REQUESTED)
      set_socket(transport_socket_.release());

  return result;
}

HttpProxyClientSocketPool::
HttpProxyConnectJobFactory::HttpProxyConnectJobFactory(
    const scoped_refptr<TCPClientSocketPool>& tcp_pool,
    const scoped_refptr<SSLClientSocketPool>& ssl_pool,
    HostResolver* host_resolver,
    NetLog* net_log)
    : tcp_pool_(tcp_pool),
      ssl_pool_(ssl_pool),
      host_resolver_(host_resolver),
      net_log_(net_log) {
  base::TimeDelta max_pool_timeout = base::TimeDelta();
  if (tcp_pool_)
    max_pool_timeout = tcp_pool_->ConnectionTimeout();
  if (ssl_pool_)
    max_pool_timeout = std::max(max_pool_timeout,
                                ssl_pool_->ConnectionTimeout());
  timeout_ = max_pool_timeout +
    base::TimeDelta::FromSeconds(kHttpProxyConnectJobTimeoutInSeconds);
}

ConnectJob*
HttpProxyClientSocketPool::HttpProxyConnectJobFactory::NewConnectJob(
    const std::string& group_name,
    const PoolBase::Request& request,
    ConnectJob::Delegate* delegate) const {
  return new HttpProxyConnectJob(group_name, request.params(),
                                 ConnectionTimeout(), tcp_pool_, ssl_pool_,
                                 host_resolver_, delegate, net_log_);
}

HttpProxyClientSocketPool::HttpProxyClientSocketPool(
    int max_sockets,
    int max_sockets_per_group,
    const scoped_refptr<ClientSocketPoolHistograms>& histograms,
    const scoped_refptr<HostResolver>& host_resolver,
    const scoped_refptr<TCPClientSocketPool>& tcp_pool,
    const scoped_refptr<SSLClientSocketPool>& ssl_pool,
    NetLog* net_log)
    : base_(max_sockets, max_sockets_per_group, histograms,
            base::TimeDelta::FromSeconds(
                ClientSocketPool::unused_idle_socket_timeout()),
            base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
            new HttpProxyConnectJobFactory(tcp_pool, ssl_pool, host_resolver,
                                           net_log)) {}

HttpProxyClientSocketPool::~HttpProxyClientSocketPool() {}

int HttpProxyClientSocketPool::RequestSocket(const std::string& group_name,
                                             const void* socket_params,
                                             RequestPriority priority,
                                             ClientSocketHandle* handle,
                                             CompletionCallback* callback,
                                             const BoundNetLog& net_log) {
  const scoped_refptr<HttpProxySocketParams>* casted_socket_params =
      static_cast<const scoped_refptr<HttpProxySocketParams>*>(socket_params);

  return base_.RequestSocket(group_name, *casted_socket_params, priority,
                             handle, callback, net_log);
}

void HttpProxyClientSocketPool::CancelRequest(
    const std::string& group_name,
    ClientSocketHandle* handle) {
  base_.CancelRequest(group_name, handle);
}

void HttpProxyClientSocketPool::ReleaseSocket(const std::string& group_name,
                                              ClientSocket* socket, int id) {
  base_.ReleaseSocket(group_name, socket, id);
}

void HttpProxyClientSocketPool::Flush() {
  base_.Flush();
}

void HttpProxyClientSocketPool::CloseIdleSockets() {
  base_.CloseIdleSockets();
}

int HttpProxyClientSocketPool::IdleSocketCountInGroup(
    const std::string& group_name) const {
  return base_.IdleSocketCountInGroup(group_name);
}

LoadState HttpProxyClientSocketPool::GetLoadState(
    const std::string& group_name, const ClientSocketHandle* handle) const {
  return base_.GetLoadState(group_name, handle);
}

}  // namespace net
<commit_msg>Ignore certificate errors when connecting to an HTTPS Proxy if LOAD_IGNORE_ALL_CERT_ERRORS is set.  This happens when the --ignore_certificate_errors command line flag is present.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_proxy_client_socket_pool.h"

#include <algorithm>

#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_network_session.h"
#include "net/http/http_proxy_client_socket.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/tcp_client_socket_pool.h"

namespace net {

HttpProxySocketParams::HttpProxySocketParams(
    const scoped_refptr<TCPSocketParams>& tcp_params,
    const scoped_refptr<SSLSocketParams>& ssl_params,
    const GURL& request_url,
    const std::string& user_agent,
    HostPortPair endpoint,
    scoped_refptr<HttpNetworkSession> session,
    bool tunnel)
    : tcp_params_(tcp_params),
      ssl_params_(ssl_params),
      request_url_(request_url),
      user_agent_(user_agent),
      endpoint_(endpoint),
      session_(tunnel ? session : NULL),
      tunnel_(tunnel) {
  DCHECK((tcp_params == NULL && ssl_params != NULL) ||
         (tcp_params != NULL && ssl_params == NULL));
}

const HostResolver::RequestInfo& HttpProxySocketParams::destination() const {
  if (tcp_params_ == NULL)
    return ssl_params_->tcp_params()->destination();
  else
    return tcp_params_->destination();
}

HttpProxySocketParams::~HttpProxySocketParams() {}

// HttpProxyConnectJobs will time out after this many seconds.  Note this is on
// top of the timeout for the transport socket.
static const int kHttpProxyConnectJobTimeoutInSeconds = 30;

HttpProxyConnectJob::HttpProxyConnectJob(
    const std::string& group_name,
    const scoped_refptr<HttpProxySocketParams>& params,
    const base::TimeDelta& timeout_duration,
    const scoped_refptr<TCPClientSocketPool>& tcp_pool,
    const scoped_refptr<SSLClientSocketPool>& ssl_pool,
    const scoped_refptr<HostResolver>& host_resolver,
    Delegate* delegate,
    NetLog* net_log)
    : ConnectJob(group_name, timeout_duration, delegate,
                 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
      params_(params),
      tcp_pool_(tcp_pool),
      ssl_pool_(ssl_pool),
      resolver_(host_resolver),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          callback_(this, &HttpProxyConnectJob::OnIOComplete)) {
}

HttpProxyConnectJob::~HttpProxyConnectJob() {}

LoadState HttpProxyConnectJob::GetLoadState() const {
  switch (next_state_) {
    case kStateTCPConnect:
    case kStateTCPConnectComplete:
    case kStateSSLConnect:
    case kStateSSLConnectComplete:
      return transport_socket_handle_->GetLoadState();
    case kStateHttpProxyConnect:
    case kStateHttpProxyConnectComplete:
      return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL;
    default:
      NOTREACHED();
      return LOAD_STATE_IDLE;
  }
}

int HttpProxyConnectJob::ConnectInternal() {
  if (params_->tcp_params())
    next_state_ = kStateTCPConnect;
  else
    next_state_ = kStateSSLConnect;
  return DoLoop(OK);
}

void HttpProxyConnectJob::OnIOComplete(int result) {
  int rv = DoLoop(result);
  if (rv != ERR_IO_PENDING)
    NotifyDelegateOfCompletion(rv);  // Deletes |this|
}

int HttpProxyConnectJob::DoLoop(int result) {
  DCHECK_NE(next_state_, kStateNone);

  int rv = result;
  do {
    State state = next_state_;
    next_state_ = kStateNone;
    switch (state) {
      case kStateTCPConnect:
        DCHECK_EQ(OK, rv);
        rv = DoTCPConnect();
        break;
      case kStateTCPConnectComplete:
        rv = DoTCPConnectComplete(rv);
        break;
      case kStateSSLConnect:
        DCHECK_EQ(OK, rv);
        rv = DoSSLConnect();
        break;
      case kStateSSLConnectComplete:
        rv = DoSSLConnectComplete(rv);
        break;
      case kStateHttpProxyConnect:
        DCHECK_EQ(OK, rv);
        rv = DoHttpProxyConnect();
        break;
      case kStateHttpProxyConnectComplete:
        rv = DoHttpProxyConnectComplete(rv);
        break;
      default:
        NOTREACHED() << "bad state";
        rv = ERR_FAILED;
        break;
    }
  } while (rv != ERR_IO_PENDING && next_state_ != kStateNone);

  return rv;
}

int HttpProxyConnectJob::DoTCPConnect() {
  next_state_ = kStateTCPConnectComplete;
  transport_socket_handle_.reset(new ClientSocketHandle());
  return transport_socket_handle_->Init(
      group_name(), params_->tcp_params(),
      params_->tcp_params()->destination().priority(), &callback_, tcp_pool_,
      net_log());
}

int HttpProxyConnectJob::DoTCPConnectComplete(int result) {
  if (result != OK)
    return result;

  // Reset the timer to just the length of time allowed for HttpProxy handshake
  // so that a fast TCP connection plus a slow HttpProxy failure doesn't take
  // longer to timeout than it should.
  ResetTimer(base::TimeDelta::FromSeconds(
      kHttpProxyConnectJobTimeoutInSeconds));
  next_state_ = kStateHttpProxyConnect;
  return result;
}

int HttpProxyConnectJob::DoSSLConnect() {
  next_state_ = kStateSSLConnectComplete;
  transport_socket_handle_.reset(new ClientSocketHandle());
  return transport_socket_handle_->Init(
      group_name(), params_->ssl_params(),
      params_->ssl_params()->tcp_params()->destination().priority(),
      &callback_, ssl_pool_, net_log());
}

int HttpProxyConnectJob::DoSSLConnectComplete(int result) {
  if (IsCertificateError(result) &&
      params_->ssl_params()->load_flags() & LOAD_IGNORE_ALL_CERT_ERRORS)
    result = OK;
  if (result < 0) {
    if (transport_socket_handle_->socket())
      transport_socket_handle_->socket()->Disconnect();
    return result;
  }

  // Reset the timer to just the length of time allowed for HttpProxy handshake
  // so that a fast SSL connection plus a slow HttpProxy failure doesn't take
  // longer to timeout than it should.
  ResetTimer(base::TimeDelta::FromSeconds(
      kHttpProxyConnectJobTimeoutInSeconds));
  next_state_ = kStateHttpProxyConnect;
  return result;
}

int HttpProxyConnectJob::DoHttpProxyConnect() {
  next_state_ = kStateHttpProxyConnectComplete;
  const HostResolver::RequestInfo& tcp_destination = params_->destination();
  HostPortPair proxy_server(tcp_destination.hostname(),
                            tcp_destination.port());

  // Add a HttpProxy connection on top of the tcp socket.
  transport_socket_.reset(
      new HttpProxyClientSocket(transport_socket_handle_.release(),
                                params_->request_url(),
                                params_->user_agent(),
                                params_->endpoint(),
                                proxy_server, params_->session(),
                                params_->tunnel()));
  int result = transport_socket_->Connect(&callback_);

  // Clear the circular reference to HttpNetworkSession (|params_| reference
  // HttpNetworkSession, which reference HttpProxyClientSocketPool, which
  // references |this|) here because it is safe to do so now but not at other
  // points.  This may cancel this ConnectJob.
  params_ = NULL;
  return result;
}

int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) {
  if (result == OK || result == ERR_PROXY_AUTH_REQUESTED)
      set_socket(transport_socket_.release());

  return result;
}

HttpProxyClientSocketPool::
HttpProxyConnectJobFactory::HttpProxyConnectJobFactory(
    const scoped_refptr<TCPClientSocketPool>& tcp_pool,
    const scoped_refptr<SSLClientSocketPool>& ssl_pool,
    HostResolver* host_resolver,
    NetLog* net_log)
    : tcp_pool_(tcp_pool),
      ssl_pool_(ssl_pool),
      host_resolver_(host_resolver),
      net_log_(net_log) {
  base::TimeDelta max_pool_timeout = base::TimeDelta();
  if (tcp_pool_)
    max_pool_timeout = tcp_pool_->ConnectionTimeout();
  if (ssl_pool_)
    max_pool_timeout = std::max(max_pool_timeout,
                                ssl_pool_->ConnectionTimeout());
  timeout_ = max_pool_timeout +
    base::TimeDelta::FromSeconds(kHttpProxyConnectJobTimeoutInSeconds);
}

ConnectJob*
HttpProxyClientSocketPool::HttpProxyConnectJobFactory::NewConnectJob(
    const std::string& group_name,
    const PoolBase::Request& request,
    ConnectJob::Delegate* delegate) const {
  return new HttpProxyConnectJob(group_name, request.params(),
                                 ConnectionTimeout(), tcp_pool_, ssl_pool_,
                                 host_resolver_, delegate, net_log_);
}

HttpProxyClientSocketPool::HttpProxyClientSocketPool(
    int max_sockets,
    int max_sockets_per_group,
    const scoped_refptr<ClientSocketPoolHistograms>& histograms,
    const scoped_refptr<HostResolver>& host_resolver,
    const scoped_refptr<TCPClientSocketPool>& tcp_pool,
    const scoped_refptr<SSLClientSocketPool>& ssl_pool,
    NetLog* net_log)
    : base_(max_sockets, max_sockets_per_group, histograms,
            base::TimeDelta::FromSeconds(
                ClientSocketPool::unused_idle_socket_timeout()),
            base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
            new HttpProxyConnectJobFactory(tcp_pool, ssl_pool, host_resolver,
                                           net_log)) {}

HttpProxyClientSocketPool::~HttpProxyClientSocketPool() {}

int HttpProxyClientSocketPool::RequestSocket(const std::string& group_name,
                                             const void* socket_params,
                                             RequestPriority priority,
                                             ClientSocketHandle* handle,
                                             CompletionCallback* callback,
                                             const BoundNetLog& net_log) {
  const scoped_refptr<HttpProxySocketParams>* casted_socket_params =
      static_cast<const scoped_refptr<HttpProxySocketParams>*>(socket_params);

  return base_.RequestSocket(group_name, *casted_socket_params, priority,
                             handle, callback, net_log);
}

void HttpProxyClientSocketPool::CancelRequest(
    const std::string& group_name,
    ClientSocketHandle* handle) {
  base_.CancelRequest(group_name, handle);
}

void HttpProxyClientSocketPool::ReleaseSocket(const std::string& group_name,
                                              ClientSocket* socket, int id) {
  base_.ReleaseSocket(group_name, socket, id);
}

void HttpProxyClientSocketPool::Flush() {
  base_.Flush();
}

void HttpProxyClientSocketPool::CloseIdleSockets() {
  base_.CloseIdleSockets();
}

int HttpProxyClientSocketPool::IdleSocketCountInGroup(
    const std::string& group_name) const {
  return base_.IdleSocketCountInGroup(group_name);
}

LoadState HttpProxyClientSocketPool::GetLoadState(
    const std::string& group_name, const ClientSocketHandle* handle) const {
  return base_.GetLoadState(group_name, handle);
}

}  // namespace net
<|endoftext|>