<commit_before>#include "Window.hpp"
#include <QApplication>
#include <QOffscreenSurface>
#include <QEventLoop>
#include <QDesktopWidget>
#include <QIcon>

namespace fast {

QGLContext* Window::mMainGLContext = NULL;

class FAST_EXPORT FASTApplication : public QApplication {
public:
    FASTApplication(int &argc, char **argv) : QApplication(argc, argv) {
    }

    virtual ~FASTApplication() {
        Reporter::info() << "FASTApplication (QApplication) is destroyed" << Reporter::end();
    }

    // reimplemented from QApplication so we can throw exceptions in slots
    virtual bool notify(QObject *receiver, QEvent *event) {
        try {
            return QApplication::notify(receiver, event);
        } catch(Exception &e) {
            Reporter::error() << "FAST exception caught in Qt event handler " << e.what() << Reporter::end();
        } catch(cl::Error &e) {
            Reporter::error() << "OpenCL exception caught in Qt event handler " << e.what() << "(" << getCLErrorString(e.err()) << ")" << Reporter::end();
        } catch(std::exception &e) {
            Reporter::error() << "Std exception caught in Qt event handler " << e.what() << Reporter::end();
        }
        return false;
    }
};

Window::Window() {
    mThread = NULL;
    mTimeout = 0;
    initializeQtApp();

    // Scaling GUI
    QFont defaultFont = QApplication::font();
    QDesktopWidget *desktop = QApplication::desktop();
    int screenWidth = desktop->width();
    if(defaultFont.pointSize() < 10 && screenWidth > 2000) {
        if(screenWidth > 3000) {
            // 4K screens
            Reporter::info() << "Large screen detected with width: " << screenWidth << Reporter::end();
            Reporter::info() << "Scaling default font with factor 2" << Reporter::end();
            mGUIScalingFactor = 2;
        } else {
            Reporter::info() << "Medium large screen detected with width: " << screenWidth << Reporter::end();
            Reporter::info() << "Scaling default font with factor 1.5" << Reporter::end();
            mGUIScalingFactor = 1.5;
        }
    }
    defaultFont.setPointSize((int)round(defaultFont.pointSize() * mGUIScalingFactor));
    QApplication::setFont(defaultFont);

	mEventLoop = NULL;
    mWidget = new WindowWidget;
    mEventLoop = new QEventLoop(mWidget);
    mWidget->connect(mWidget, SIGNAL(widgetHasClosed()), this, SLOT(stop()));
    mWidget->setContentsMargins(0, 0, 0, 0);

    // default window size
    mWidth = 512;
    mHeight = 512;
    mFullscreen = false;
    mMaximized = false;
}

void Window::enableFullscreen() {
    mFullscreen = true;
    disableMaximized();
}

void Window::disableFullscreen() {
    mFullscreen = false;
}

void Window::enableMaximized() {
    mMaximized = true;
    disableFullscreen();
}

void Window::disableMaximized() {
    mMaximized = false;
}

void Window::setTitle(std::string title) {
    mWidget->setWindowTitle(title.c_str());
}

void Window::cleanup() {
    //delete QApplication::instance();
}

void Window::initializeQtApp() {
    // Make sure only one QApplication is created
    if(!QApplication::instance()) {
        Reporter::info() << "Creating new QApp" << Reporter::end();
        // Create some dummy argc and argv options as QApplication requires it
        int* argc = new int[1];
        *argc = 0;
        QApplication* app = new FASTApplication(*argc,NULL);

        // Set default window icon
        QApplication::setWindowIcon(QIcon((Config::getDocumentationPath() + "images/fast_icon.png").c_str()));

         // Create computation GL context, if it doesn't exist
        if(mMainGLContext == NULL) {
            Reporter::info() << "Creating new GL context for computation thread" << Reporter::end();

            // Create GL context to be shared with the CL contexts
            QGLWidget* widget = new QGLWidget;
            mMainGLContext = new QGLContext(QGLFormat::defaultFormat(), widget); // by including widget here the context becomes valid
            mMainGLContext->create();
            if(!mMainGLContext->isValid()) {
                throw Exception("Qt GL context is invalid!");
            }
        }
    } else {
        Reporter::info() << "QApp already exists.." << Reporter::end();
    }

    // There is a bug in AMD OpenCL related to comma (,) as decimal point
    // This will change decimal point to dot (.)
    struct lconv * lc;
    lc = localeconv();
    if(strcmp(lc->decimal_point, ",") == 0) {
        Reporter::warning() << "Your system uses comma as decimal point." << Reporter::end();
        Reporter::warning() << "This will now be changed to dot to avoid any comma related bugs." << Reporter::end();
        setlocale(LC_NUMERIC, "C");
        // Check again to be sure
        lc = localeconv();
        if(strcmp(lc->decimal_point, ",") == 0) {
            throw Exception("Failed to convert decimal point to dot.");
        }
    }
}

void Window::stop() {
    reportInfo() << "Stop signal recieved.." << Reporter::end();
    stopComputationThread();
    if(mEventLoop != NULL)
        mEventLoop->quit();
    /*
    // Make sure event is not quit twice
    if(!mWidget->getView()->hasQuit()) {
        // This event occurs when window is closed or timeout is reached
        mWidget->getView()->quit();
    }
    */
}

View* Window::createView() {
    View* view = mWidget->addView();

    return view;
}

void Window::start() {

    QDesktopWidget *desktop = QApplication::desktop();
    int screenWidth = desktop->width();
    int screenHeight = desktop->height();

    mWidget->resize(mWidth,mHeight);
    if(mFullscreen) {
        mWidget->showFullScreen();
    } else if(mMaximized) {
        //mWidth = screenWidth;
        //mHeight = screenHeight;
        mWidget->showMaximized();
    } else {
        // Move window to center
        int x = (screenWidth - mWidth) / 2;
        int y = (screenHeight - mHeight) / 2;
        mWidget->move(x, y);
        mWidget->show();
    }

    if(mTimeout > 0) {
        QTimer* timer = new QTimer(mWidget);
        timer->start(mTimeout);
        timer->setSingleShot(true);
        mWidget->connect(timer,SIGNAL(timeout()),mWidget,SLOT(close()));
    }

    startComputationThread();

    mEventLoop->exec(); // This call blocks and starts rendering
}

Window::~Window() {
    // Cleanup
    reportInfo() << "Destroying window.." << Reporter::end();
    // Event loop is child of widget
    //reportInfo() << "Deleting event loop" << Reporter::end();
    //if(mEventLoop != NULL)
    //    delete mEventLoop;
    reportInfo() << "Deleting widget" << Reporter::end();
    if(mWidget != NULL) {
        delete mWidget;
        mWidget = NULL;
    }
    reportInfo() << "Finished deleting window widget" << Reporter::end();
    if(mThread != NULL) {
        mThread->stop();
        delete mThread;
        mThread = NULL;
    }

    reportInfo() << "Window destroyed" << Reporter::end();
}

void Window::setTimeout(unsigned int milliseconds) {
    mTimeout = milliseconds;
}

QGLContext* Window::getMainGLContext() {
    if(mMainGLContext == NULL) {
        throw Exception("No OpenGL context created");
        //initializeQtApp();
    }

    return mMainGLContext;
}

void Window::setMainGLContext(QGLContext* context) {
    mMainGLContext = context;
}

void Window::startComputationThread() {
    if(mThread == NULL) {
        // Start computation thread using QThreads which is a strange thing, see https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
        reportInfo() << "Trying to start computation thread" << Reporter::end();
        mThread = new ComputationThread(QThread::currentThread());
        QThread* thread = new QThread();
        mThread->moveToThread(thread);
        connect(thread, SIGNAL(started()), mThread, SLOT(run()));
        connect(mThread, SIGNAL(finished()), thread, SLOT(quit()));
        //connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

        for(int i = 0; i < getViews().size(); i++)
            mThread->addView(getViews()[i]);
        QGLContext* mainGLContext = Window::getMainGLContext();
        if(!mainGLContext->isValid()) {
            throw Exception("QGL context is invalid!");
        }

        mainGLContext->doneCurrent();
        mainGLContext->moveToThread(thread);
        thread->start();
        reportInfo() << "Computation thread started" << Reporter::end();
    }
}

void Window::stopComputationThread() {
    reportInfo() << "Trying to stop computation thread" << Reporter::end();
    if(mThread != NULL) {
        mThread->stop();
        delete mThread;
        mThread = NULL;
    }
    reportInfo() << "Computation thread stopped" << Reporter::end();
}

std::vector<View*> Window::getViews() const {
    return mWidget->getViews();
}

View* Window::getView(uint i) const {
    return mWidget->getViews().at(i);
}

void Window::setWidth(uint width) {
    mWidth = width;
}

void Window::setHeight(uint height) {
    mHeight = height;
}

void Window::setSize(uint width, uint height) {
    setWidth(width);
    setHeight(height);
}

float Window::getScalingFactor() const {
    return mGUIScalingFactor;
}

int Window::getScreenWidth() const {
    QDesktopWidget *desktop = QApplication::desktop();
    return desktop->width();
}

int Window::getScreenHeight() const {
    QDesktopWidget *desktop = QApplication::desktop();
    return desktop->height();
}

} // end namespace fast
<commit_msg>Lowered scaling factor for 4k screens to 1.75<commit_after>#include "Window.hpp"
#include <QApplication>
#include <QOffscreenSurface>
#include <QEventLoop>
#include <QDesktopWidget>
#include <QIcon>

namespace fast {

QGLContext* Window::mMainGLContext = NULL;

class FAST_EXPORT FASTApplication : public QApplication {
public:
    FASTApplication(int &argc, char **argv) : QApplication(argc, argv) {
    }

    virtual ~FASTApplication() {
        Reporter::info() << "FASTApplication (QApplication) is destroyed" << Reporter::end();
    }

    // reimplemented from QApplication so we can throw exceptions in slots
    virtual bool notify(QObject *receiver, QEvent *event) {
        try {
            return QApplication::notify(receiver, event);
        } catch(Exception &e) {
            Reporter::error() << "FAST exception caught in Qt event handler " << e.what() << Reporter::end();
        } catch(cl::Error &e) {
            Reporter::error() << "OpenCL exception caught in Qt event handler " << e.what() << "(" << getCLErrorString(e.err()) << ")" << Reporter::end();
        } catch(std::exception &e) {
            Reporter::error() << "Std exception caught in Qt event handler " << e.what() << Reporter::end();
        }
        return false;
    }
};

Window::Window() {
    mThread = NULL;
    mTimeout = 0;
    initializeQtApp();

    // Scaling GUI
    QFont defaultFont = QApplication::font();
    QDesktopWidget *desktop = QApplication::desktop();
    int screenWidth = desktop->width();
    if(defaultFont.pointSize() < 10 && screenWidth > 2000) {
        if(screenWidth > 3000) {
            // 4K screens
            Reporter::info() << "Large screen detected with width: " << screenWidth << Reporter::end();
            Reporter::info() << "Scaling default font with factor 2" << Reporter::end();
            mGUIScalingFactor = 1.75;
        } else {
            Reporter::info() << "Medium large screen detected with width: " << screenWidth << Reporter::end();
            Reporter::info() << "Scaling default font with factor 1.5" << Reporter::end();
            mGUIScalingFactor = 1.5;
        }
    }
    defaultFont.setPointSize((int)round(defaultFont.pointSize() * mGUIScalingFactor));
    QApplication::setFont(defaultFont);

	mEventLoop = NULL;
    mWidget = new WindowWidget;
    mEventLoop = new QEventLoop(mWidget);
    mWidget->connect(mWidget, SIGNAL(widgetHasClosed()), this, SLOT(stop()));
    mWidget->setContentsMargins(0, 0, 0, 0);

    // default window size
    mWidth = 512;
    mHeight = 512;
    mFullscreen = false;
    mMaximized = false;
}

void Window::enableFullscreen() {
    mFullscreen = true;
    disableMaximized();
}

void Window::disableFullscreen() {
    mFullscreen = false;
}

void Window::enableMaximized() {
    mMaximized = true;
    disableFullscreen();
}

void Window::disableMaximized() {
    mMaximized = false;
}

void Window::setTitle(std::string title) {
    mWidget->setWindowTitle(title.c_str());
}

void Window::cleanup() {
    //delete QApplication::instance();
}

void Window::initializeQtApp() {
    // Make sure only one QApplication is created
    if(!QApplication::instance()) {
        Reporter::info() << "Creating new QApp" << Reporter::end();
        // Create some dummy argc and argv options as QApplication requires it
        int* argc = new int[1];
        *argc = 0;
        QApplication* app = new FASTApplication(*argc,NULL);

        // Set default window icon
        QApplication::setWindowIcon(QIcon((Config::getDocumentationPath() + "images/fast_icon.png").c_str()));

         // Create computation GL context, if it doesn't exist
        if(mMainGLContext == NULL) {
            Reporter::info() << "Creating new GL context for computation thread" << Reporter::end();

            // Create GL context to be shared with the CL contexts
            QGLWidget* widget = new QGLWidget;
            mMainGLContext = new QGLContext(QGLFormat::defaultFormat(), widget); // by including widget here the context becomes valid
            mMainGLContext->create();
            if(!mMainGLContext->isValid()) {
                throw Exception("Qt GL context is invalid!");
            }
        }
    } else {
        Reporter::info() << "QApp already exists.." << Reporter::end();
    }

    // There is a bug in AMD OpenCL related to comma (,) as decimal point
    // This will change decimal point to dot (.)
    struct lconv * lc;
    lc = localeconv();
    if(strcmp(lc->decimal_point, ",") == 0) {
        Reporter::warning() << "Your system uses comma as decimal point." << Reporter::end();
        Reporter::warning() << "This will now be changed to dot to avoid any comma related bugs." << Reporter::end();
        setlocale(LC_NUMERIC, "C");
        // Check again to be sure
        lc = localeconv();
        if(strcmp(lc->decimal_point, ",") == 0) {
            throw Exception("Failed to convert decimal point to dot.");
        }
    }
}

void Window::stop() {
    reportInfo() << "Stop signal recieved.." << Reporter::end();
    stopComputationThread();
    if(mEventLoop != NULL)
        mEventLoop->quit();
    /*
    // Make sure event is not quit twice
    if(!mWidget->getView()->hasQuit()) {
        // This event occurs when window is closed or timeout is reached
        mWidget->getView()->quit();
    }
    */
}

View* Window::createView() {
    View* view = mWidget->addView();

    return view;
}

void Window::start() {

    QDesktopWidget *desktop = QApplication::desktop();
    int screenWidth = desktop->width();
    int screenHeight = desktop->height();

    mWidget->resize(mWidth,mHeight);
    if(mFullscreen) {
        mWidget->showFullScreen();
    } else if(mMaximized) {
        //mWidth = screenWidth;
        //mHeight = screenHeight;
        mWidget->showMaximized();
    } else {
        // Move window to center
        int x = (screenWidth - mWidth) / 2;
        int y = (screenHeight - mHeight) / 2;
        mWidget->move(x, y);
        mWidget->show();
    }

    if(mTimeout > 0) {
        QTimer* timer = new QTimer(mWidget);
        timer->start(mTimeout);
        timer->setSingleShot(true);
        mWidget->connect(timer,SIGNAL(timeout()),mWidget,SLOT(close()));
    }

    startComputationThread();

    mEventLoop->exec(); // This call blocks and starts rendering
}

Window::~Window() {
    // Cleanup
    reportInfo() << "Destroying window.." << Reporter::end();
    // Event loop is child of widget
    //reportInfo() << "Deleting event loop" << Reporter::end();
    //if(mEventLoop != NULL)
    //    delete mEventLoop;
    reportInfo() << "Deleting widget" << Reporter::end();
    if(mWidget != NULL) {
        delete mWidget;
        mWidget = NULL;
    }
    reportInfo() << "Finished deleting window widget" << Reporter::end();
    if(mThread != NULL) {
        mThread->stop();
        delete mThread;
        mThread = NULL;
    }

    reportInfo() << "Window destroyed" << Reporter::end();
}

void Window::setTimeout(unsigned int milliseconds) {
    mTimeout = milliseconds;
}

QGLContext* Window::getMainGLContext() {
    if(mMainGLContext == NULL) {
        throw Exception("No OpenGL context created");
        //initializeQtApp();
    }

    return mMainGLContext;
}

void Window::setMainGLContext(QGLContext* context) {
    mMainGLContext = context;
}

void Window::startComputationThread() {
    if(mThread == NULL) {
        // Start computation thread using QThreads which is a strange thing, see https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
        reportInfo() << "Trying to start computation thread" << Reporter::end();
        mThread = new ComputationThread(QThread::currentThread());
        QThread* thread = new QThread();
        mThread->moveToThread(thread);
        connect(thread, SIGNAL(started()), mThread, SLOT(run()));
        connect(mThread, SIGNAL(finished()), thread, SLOT(quit()));
        //connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

        for(int i = 0; i < getViews().size(); i++)
            mThread->addView(getViews()[i]);
        QGLContext* mainGLContext = Window::getMainGLContext();
        if(!mainGLContext->isValid()) {
            throw Exception("QGL context is invalid!");
        }

        mainGLContext->doneCurrent();
        mainGLContext->moveToThread(thread);
        thread->start();
        reportInfo() << "Computation thread started" << Reporter::end();
    }
}

void Window::stopComputationThread() {
    reportInfo() << "Trying to stop computation thread" << Reporter::end();
    if(mThread != NULL) {
        mThread->stop();
        delete mThread;
        mThread = NULL;
    }
    reportInfo() << "Computation thread stopped" << Reporter::end();
}

std::vector<View*> Window::getViews() const {
    return mWidget->getViews();
}

View* Window::getView(uint i) const {
    return mWidget->getViews().at(i);
}

void Window::setWidth(uint width) {
    mWidth = width;
}

void Window::setHeight(uint height) {
    mHeight = height;
}

void Window::setSize(uint width, uint height) {
    setWidth(width);
    setHeight(height);
}

float Window::getScalingFactor() const {
    return mGUIScalingFactor;
}

int Window::getScreenWidth() const {
    QDesktopWidget *desktop = QApplication::desktop();
    return desktop->width();
}

int Window::getScreenHeight() const {
    QDesktopWidget *desktop = QApplication::desktop();
    return desktop->height();
}

} // end namespace fast
<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <algorithm>
#include <sstream>

#include <boost/unordered_map.hpp>
#include <boost/assign/list_of.hpp>

#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>

// We intentionally omit numpy/arrayobject.h here because cpp files need to be careful with exactly when this is imported.
// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api
// Therefore, we assume the cpp file that included converters.hpp has already included numpy/arrayobject.h
// #include <numpy/arrayobject.h>

#include "BinaryData.h"
#include "DVIDException.h"

using namespace boost::python;

namespace libdvid { namespace python {

    //*********************************************************************************************
    //* Helpers
    //*********************************************************************************************

    //! PyBinaryDataHolder is the Python wrapper class for the SmartPtrHolder<BinaryDataPtr> class.
    //! It is exposed here as a global so helper functions can use it to manage BinaryData objects.
    //! It must be assigned in the module init section (see libdvid_python.cpp).
    boost::python::object PyBinaryDataHolder;

    template<class SmartPtr>
    struct SmartPtrHolder
    {
        SmartPtrHolder() {}
        SmartPtr ptr;
    };
    typedef SmartPtrHolder<libdvid::BinaryDataPtr> BinaryDataHolder;

    //*********************************************************************************************
    //*********************************************************************************************
    //* Python -> C++
    //*********************************************************************************************
    //*********************************************************************************************

    //!*********************************************************************************************
    //! This struct tells boost::python how to convert Python sequences into std::vector<T>.
    //! To use it, instantiate a single instance of it somewhere in your module init section:
    //!
    //!     libdvid::python::std_vector_from_python_iterable<unsigned int>();
    //!
    //! NOTE: This does NOT convert the other way, i.e. from std::vector<T> into Python list.
    //!      If you need to return a std::vector<T>, you'll have to implement that separately.
    //!
    //! For explanation and examples, see the following links:
    //! https://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters
    //! http://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/faq.html#custom_string
    //!*********************************************************************************************
    template <typename T>
    struct std_vector_from_python_iterable
    {
        typedef std::vector<T> vector_t;

        std_vector_from_python_iterable()
        {
          converter::registry::push_back(
              &convertible,
              &construct,
              type_id<vector_t>());
        }

        // Determine if obj_ptr can be converted in a vector
        static void* convertible(PyObject* obj_ptr)
        {
            if (!PySequence_Check(obj_ptr))
            {
                return 0;
            }
            return obj_ptr;
        }

        // Convert obj_ptr into a vector
        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            assert( PySequence_Check(obj_ptr) );

            // Grab pointer to memory into which to construct the new vector_t
            void* storage = ((converter::rvalue_from_python_storage<vector_t>*) data)->storage.bytes;

            // in-place construct the new vector_t
            vector_t * the_vector = new (storage) vector_t;

            // Now copy the data from python into the vector
            typedef stl_input_iterator<T> vector_iter_t;
            object obj = object(handle<>(borrowed(obj_ptr)));
            the_vector->assign( vector_iter_t(obj), vector_iter_t()  );

            // Stash the memory chunk pointer for later use by boost::python
            data->convertible = storage;
        }
    };

    //!*********************************************************************************************
    //! This converter auto-converts 'None' objects into empty std::strings.
    //!*********************************************************************************************
    struct std_string_from_python_none
    {
        std_string_from_python_none()
        {
          converter::registry::push_back(
              &convertible,
              &construct,
              type_id<std::string>());
        }

        // Determine if obj_ptr is None
        static void* convertible(PyObject* obj_ptr)
        {
            if (obj_ptr == Py_None)
            {
                return obj_ptr;
            }
            return 0;
        }

        // Convert obj_ptr into a std::string
        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            assert (obj_ptr == Py_None);

            // Grab pointer to memory into which to construct the std::string
            void* storage = ((converter::rvalue_from_python_storage<std::string>*) data)->storage.bytes;

            // in-place construct the new std::string
            // extraced from the python object
            new (storage) std::string;

            // Stash the memory chunk pointer for later use by boost.python
            data->convertible = storage;
        }
    };

    //!*********************************************************************************************
    //! This helper struct is specialized over integer types to provide a
    //! compile-time mapping from integer types to numpy typenumbers.
    //!*********************************************************************************************
    template <typename T> struct numpy_typenums {};
    template <> struct numpy_typenums<libdvid::uint8> { static const int typenum = NPY_UINT8; };
    template <> struct numpy_typenums<libdvid::uint64> { static const int typenum = NPY_UINT64; };

    //!*********************************************************************************************
    //! Declares a mapping between numpy typenumbers and the corresponding dtype names
    //!*********************************************************************************************
    static boost::unordered_map<int, std::string> dtype_names =
        boost::assign::map_list_of
        (NPY_UINT8, "uint8")
        (NPY_UINT64, "uint64");

    //!*********************************************************************************************
    //! Converts the given numpy ndarray object into a DVIDVoxels object.
    //! NOTE: The data from the ndarray is *copied* into the new DVIDVoxels object.
    //!*********************************************************************************************
    template <class VolumeType>
    struct ndarray_to_volume
    {
        ndarray_to_volume()
        {
          converter::registry::push_back( &convertible, &construct, type_id<VolumeType>() );
          converter::registry::push_back( &convertible, &construct, type_id<VolumeType&>() );
        }

        static void* convertible(PyObject* obj_ptr)
        {
            if (!PyArray_Check(obj_ptr))
            {
                return 0;
            }
            // We could also check shape, dtype, etc. here, but it's more helpful to
            // wait until construction time, and then throw a specific exception to
            // tell the user what he did wrong.
            return obj_ptr;
        }

        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            using namespace boost::python;
            using namespace libdvid;

            assert(PyArray_Check(obj_ptr));

            typedef typename VolumeType::voxel_type voxel_type;

            object ndarray = object(handle<>(borrowed(obj_ptr)));

            // Verify ndarray.dtype
            std::string dtype = extract<std::string>(str(ndarray.attr("dtype")));
            const int numpy_typenum = numpy_typenums<voxel_type>::typenum;
            if (dtype != dtype_names[numpy_typenum])
            {
                std::ostringstream ssMsg;
                ssMsg << "Volume has wrong dtype.  Expected " << dtype_names[numpy_typenum] << ", got " << dtype;
                throw ErrMsg(ssMsg.str());
            }

            // Verify ndarray dimensionality.
            int ndarray_ndim = extract<int>(ndarray.attr("ndim"));
            if (ndarray_ndim != VolumeType::num_dims)
            {
                std::string shape = extract<std::string>(str(ndarray.attr("shape")));
                std::ostringstream ssMsg;
                ssMsg << "Volume is not exactly " << VolumeType::num_dims << "D.  Shape is " << shape;
                throw ErrMsg( ssMsg.str() );
            }

            // Verify ndarray memory order
            if (!ndarray.attr("flags")["C_CONTIGUOUS"])
            {
                throw ErrMsg("Volume is not C_CONTIGUOUS");
            }

            // Extract dims from ndarray.shape
            object shape = ndarray.attr("shape");
            typedef stl_input_iterator<Dims_t::value_type> shape_iter_t;
            Dims_t dims;
            dims.assign( shape_iter_t(shape), shape_iter_t() );

            // Extract the voxel count
            int voxel_count = extract<int>(ndarray.attr("size"));

            // Obtain a pointer to the array's data
            PyArrayObject * array_object = reinterpret_cast<PyArrayObject *>( ndarray.ptr() );
            voxel_type const * voxel_data = static_cast<voxel_type const *>( PyArray_DATA(array_object) );

            // Grab pointer to memory into which to construct the DVIDVoxels
            void* storage = ((converter::rvalue_from_python_storage<VolumeType>*) data)->storage.bytes;

            // Create DVIDVoxels<> from ndarray data using "in-place" new().
            // FIXME: The DVIDVoxels constructor copies the data. Is that really necessary?
            VolumeType * volume = new (storage) VolumeType( voxel_data, voxel_count, dims );

            // Stash the memory chunk pointer for later use by boost.python
            data->convertible = storage;
        }
    };

    //!*********************************************************************************************
    //! Convert Python buffer objects (e.g. str, bytearray) -> BinaryDataPtr
    //!*********************************************************************************************
    struct binary_data_ptr_from_python_buffer
    {
        binary_data_ptr_from_python_buffer()
        {
          converter::registry::push_back(
              &convertible,
              &construct,
              type_id<BinaryDataPtr>());
        }

        static void* convertible(PyObject* obj_ptr)
        {
            // The "proper" thing here would be to check if this object is a buffer,
            // but I think it's more helpful to the user if we check inside construct()
            // and raise a descriptive exception if they tried to supply a non-buffer.

            // return PyObject_CheckBuffer(obj_ptr) ? obj_ptr : 0;

            return obj_ptr;
        }

        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            using namespace libdvid;
            using namespace boost::python;

            BinaryDataPtr binary_data;
            if (obj_ptr == Py_None)
            {
                // As a special convenience, we auto-convert None to an empty buffer.
                binary_data = BinaryData::create_binary_data();
            }
            else
            {
                if (!PyObject_CheckBuffer(obj_ptr))
                {
                    std::string value_str = extract<std::string>(str(object(handle<>(borrowed(obj_ptr)))));
                    throw ErrMsg("Value is not a buffer: " + value_str);
                }
                Py_buffer py_buffer;
                PyObject_GetBuffer(obj_ptr, &py_buffer, PyBUF_SIMPLE);

                // Copy buffer into BinaryData
                binary_data = BinaryData::create_binary_data(static_cast<char*>(py_buffer.buf), py_buffer.len);
                PyBuffer_Release(&py_buffer);
            }

            // Grab pointer to memory into which to construct the BinaryDataPtr
            void* storage = ((converter::rvalue_from_python_storage<BinaryDataPtr>*) data)->storage.bytes;

            // in-place construct the new std::string
            // extraced from the python object
            new (storage) BinaryDataPtr(binary_data);

            // Stash the memory chunk pointer for later use by boost.python
            data->convertible = storage;
        }
    };

    //*********************************************************************************************
    //*********************************************************************************************
    //* C++ -> Python
    //*********************************************************************************************
    //*********************************************************************************************

    //!*********************************************************************************************
    //! This converts BinaryDataPtr objects into Python strings.
    //! NOTE: It copies the data.
    //!*********************************************************************************************
    struct binary_data_ptr_to_python_str
    {
        static PyObject* convert(BinaryDataPtr const& binary_data)
        {
            return PyString_FromStringAndSize( binary_data->get_data().c_str(), binary_data->get_data().size() );
        }
    };

    //!*********************************************************************************************
    //! Converts the given DVIDVoxels object into a numpy array.
    //! NOTE:The ndarray will *steal* the data from the DVIDVoxels object.
    //!*********************************************************************************************
    template <class VolumeType> // VolumeType must be some DVIDVoxels<T, N>
    struct volume_to_ndarray
    {
        static PyObject* convert( VolumeType volume )
        {
            using namespace boost::python;
            using namespace libdvid;

            typedef typename VolumeType::voxel_type voxel_type;

            BinaryDataPtr volume_data = volume.get_binary();

            // Wrap the BinaryData in a BinaryDataHolder object,
            // which is managed via Python's reference counting scheme.
            object py_managed_bd = PyBinaryDataHolder();
            BinaryDataHolder & holder = extract<BinaryDataHolder&>(py_managed_bd);
            holder.ptr = volume_data;

            // Copy dims to type numpy expects.
            std::vector<npy_intp> numpy_dims( volume.get_dims().begin(), volume.get_dims().end() );

            // We will create a new array with the data from the existing PyBinaryData object (no copy).
            // The basic idea is described in the following link, but can get away with a lot less code
            // because boost-python already defined the new Python type for us (PyBinaryData).
            // Also, this post is old so the particular API we're using here is slightly different.
            // http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory/
            void const * raw_data = static_cast<void const*>(volume_data->get_raw());
            PyObject * array_object = PyArray_SimpleNewFromData( numpy_dims.size(),
                                                                 &numpy_dims[0],
                                                                 numpy_typenums<voxel_type>::typenum,
                                                                 const_cast<void*>(raw_data) );
            if (!array_object)
            {
                throw ErrMsg("Failed to create array from BinaryData!");
            }
            PyArrayObject * ndarray = reinterpret_cast<PyArrayObject *>( array_object );

            // As described in the link above, assigning the 'base' pointer here ensures
            //  that the memory is deallocated when the user is done with the ndarray.
            int status = PyArray_SetBaseObject(ndarray, py_managed_bd.ptr());
            if (status != 0)
            {
                throw ErrMsg("Failed to set array base object!");
            }
            // PyArray_SetBaseObject *steals* the reference, so we need to INCREF here
            //  to make sure the binary data object isn't destroyed when we return.
            incref(py_managed_bd.ptr());

            // Return the new array.
            return array_object;
        }
    };

    //!*********************************************************************************************
    //! This converts Json::Value objects into python dict objects.
    //! NOTE: This isn't an efficient conversion method.
    //!*********************************************************************************************
    struct json_value_to_dict
    {
        static PyObject* convert(Json::Value const & json_value)
        {
            using namespace boost::python;

            // For now, easiest thing to do is just export as
            //  string and re-parse via python's json module.
            std::ostringstream ss;
            ss << json_value;

            object json = import("json");
            return incref(json.attr("loads")( ss.str() ).ptr());
        }
    };

}} // namespace libdvid::python
<commit_msg>python: Corrected a comment.<commit_after>#include <vector>
#include <string>
#include <algorithm>
#include <sstream>

#include <boost/unordered_map.hpp>
#include <boost/assign/list_of.hpp>

#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>

// We intentionally omit numpy/arrayobject.h here because cpp files need to be careful with exactly when this is imported.
// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api
// Therefore, we assume the cpp file that included converters.hpp has already included numpy/arrayobject.h
// #include <numpy/arrayobject.h>

#include "BinaryData.h"
#include "DVIDException.h"

using namespace boost::python;

namespace libdvid { namespace python {

    //*********************************************************************************************
    //* Helpers
    //*********************************************************************************************

    //! PyBinaryDataHolder is the Python wrapper class for the SmartPtrHolder<BinaryDataPtr> class.
    //! It is exposed here as a global so helper functions can use it to manage BinaryData objects.
    //! It must be assigned in the module init section (see libdvid_python.cpp).
    boost::python::object PyBinaryDataHolder;

    template<class SmartPtr>
    struct SmartPtrHolder
    {
        SmartPtrHolder() {}
        SmartPtr ptr;
    };
    typedef SmartPtrHolder<libdvid::BinaryDataPtr> BinaryDataHolder;

    //*********************************************************************************************
    //*********************************************************************************************
    //* Python -> C++
    //*********************************************************************************************
    //*********************************************************************************************

    //!*********************************************************************************************
    //! This struct tells boost::python how to convert Python sequences into std::vector<T>.
    //! To use it, instantiate a single instance of it somewhere in your module init section:
    //!
    //!     libdvid::python::std_vector_from_python_iterable<unsigned int>();
    //!
    //! NOTE: This does NOT convert the other way, i.e. from std::vector<T> into Python list.
    //!      If you need to return a std::vector<T>, you'll have to implement that separately.
    //!
    //! For explanation and examples, see the following links:
    //! https://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters
    //! http://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/faq.html#custom_string
    //!*********************************************************************************************
    template <typename T>
    struct std_vector_from_python_iterable
    {
        typedef std::vector<T> vector_t;

        std_vector_from_python_iterable()
        {
          converter::registry::push_back(
              &convertible,
              &construct,
              type_id<vector_t>());
        }

        // Determine if obj_ptr can be converted in a vector
        static void* convertible(PyObject* obj_ptr)
        {
            if (!PySequence_Check(obj_ptr))
            {
                return 0;
            }
            return obj_ptr;
        }

        // Convert obj_ptr into a vector
        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            assert( PySequence_Check(obj_ptr) );

            // Grab pointer to memory into which to construct the new vector_t
            void* storage = ((converter::rvalue_from_python_storage<vector_t>*) data)->storage.bytes;

            // in-place construct the new vector_t
            vector_t * the_vector = new (storage) vector_t;

            // Now copy the data from python into the vector
            typedef stl_input_iterator<T> vector_iter_t;
            object obj = object(handle<>(borrowed(obj_ptr)));
            the_vector->assign( vector_iter_t(obj), vector_iter_t()  );

            // Stash the memory chunk pointer for later use by boost::python
            data->convertible = storage;
        }
    };

    //!*********************************************************************************************
    //! This converter auto-converts 'None' objects into empty std::strings.
    //!*********************************************************************************************
    struct std_string_from_python_none
    {
        std_string_from_python_none()
        {
          converter::registry::push_back(
              &convertible,
              &construct,
              type_id<std::string>());
        }

        // Determine if obj_ptr is None
        static void* convertible(PyObject* obj_ptr)
        {
            if (obj_ptr == Py_None)
            {
                return obj_ptr;
            }
            return 0;
        }

        // Convert obj_ptr into a std::string
        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            assert (obj_ptr == Py_None);

            // Grab pointer to memory into which to construct the std::string
            void* storage = ((converter::rvalue_from_python_storage<std::string>*) data)->storage.bytes;

            // in-place construct the new std::string
            // extraced from the python object
            new (storage) std::string;

            // Stash the memory chunk pointer for later use by boost.python
            data->convertible = storage;
        }
    };

    //!*********************************************************************************************
    //! This helper struct is specialized over integer types to provide a
    //! compile-time mapping from integer types to numpy typenumbers.
    //!*********************************************************************************************
    template <typename T> struct numpy_typenums {};
    template <> struct numpy_typenums<libdvid::uint8> { static const int typenum = NPY_UINT8; };
    template <> struct numpy_typenums<libdvid::uint64> { static const int typenum = NPY_UINT64; };

    //!*********************************************************************************************
    //! Declares a mapping between numpy typenumbers and the corresponding dtype names
    //!*********************************************************************************************
    static boost::unordered_map<int, std::string> dtype_names =
        boost::assign::map_list_of
        (NPY_UINT8, "uint8")
        (NPY_UINT64, "uint64");

    //!*********************************************************************************************
    //! Converts the given numpy ndarray object into a DVIDVoxels object.
    //! NOTE: The data from the ndarray is *copied* into the new DVIDVoxels object.
    //!*********************************************************************************************
    template <class VolumeType>
    struct ndarray_to_volume
    {
        ndarray_to_volume()
        {
          converter::registry::push_back( &convertible, &construct, type_id<VolumeType>() );
          converter::registry::push_back( &convertible, &construct, type_id<VolumeType&>() );
        }

        static void* convertible(PyObject* obj_ptr)
        {
            if (!PyArray_Check(obj_ptr))
            {
                return 0;
            }
            // We could also check shape, dtype, etc. here, but it's more helpful to
            // wait until construction time, and then throw a specific exception to
            // tell the user what he did wrong.
            return obj_ptr;
        }

        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            using namespace boost::python;
            using namespace libdvid;

            assert(PyArray_Check(obj_ptr));

            typedef typename VolumeType::voxel_type voxel_type;

            object ndarray = object(handle<>(borrowed(obj_ptr)));

            // Verify ndarray.dtype
            std::string dtype = extract<std::string>(str(ndarray.attr("dtype")));
            const int numpy_typenum = numpy_typenums<voxel_type>::typenum;
            if (dtype != dtype_names[numpy_typenum])
            {
                std::ostringstream ssMsg;
                ssMsg << "Volume has wrong dtype.  Expected " << dtype_names[numpy_typenum] << ", got " << dtype;
                throw ErrMsg(ssMsg.str());
            }

            // Verify ndarray dimensionality.
            int ndarray_ndim = extract<int>(ndarray.attr("ndim"));
            if (ndarray_ndim != VolumeType::num_dims)
            {
                std::string shape = extract<std::string>(str(ndarray.attr("shape")));
                std::ostringstream ssMsg;
                ssMsg << "Volume is not exactly " << VolumeType::num_dims << "D.  Shape is " << shape;
                throw ErrMsg( ssMsg.str() );
            }

            // Verify ndarray memory order
            if (!ndarray.attr("flags")["C_CONTIGUOUS"])
            {
                throw ErrMsg("Volume is not C_CONTIGUOUS");
            }

            // Extract dims from ndarray.shape
            object shape = ndarray.attr("shape");
            typedef stl_input_iterator<Dims_t::value_type> shape_iter_t;
            Dims_t dims;
            dims.assign( shape_iter_t(shape), shape_iter_t() );

            // Extract the voxel count
            int voxel_count = extract<int>(ndarray.attr("size"));

            // Obtain a pointer to the array's data
            PyArrayObject * array_object = reinterpret_cast<PyArrayObject *>( ndarray.ptr() );
            voxel_type const * voxel_data = static_cast<voxel_type const *>( PyArray_DATA(array_object) );

            // Grab pointer to memory into which to construct the DVIDVoxels
            void* storage = ((converter::rvalue_from_python_storage<VolumeType>*) data)->storage.bytes;

            // Create DVIDVoxels<> from ndarray data using "in-place" new().
            // FIXME: The DVIDVoxels constructor copies the data. Is that really necessary?
            VolumeType * volume = new (storage) VolumeType( voxel_data, voxel_count, dims );

            // Stash the memory chunk pointer for later use by boost.python
            data->convertible = storage;
        }
    };

    //!*********************************************************************************************
    //! Convert Python buffer objects (e.g. str, bytearray) -> BinaryDataPtr
    //!*********************************************************************************************
    struct binary_data_ptr_from_python_buffer
    {
        binary_data_ptr_from_python_buffer()
        {
          converter::registry::push_back(
              &convertible,
              &construct,
              type_id<BinaryDataPtr>());
        }

        static void* convertible(PyObject* obj_ptr)
        {
            // The "proper" thing here would be to check if this object is a buffer,
            // but I think it's more helpful to the user if we check inside construct()
            // and raise a descriptive exception if they tried to supply a non-buffer.

            // return PyObject_CheckBuffer(obj_ptr) ? obj_ptr : 0;

            return obj_ptr;
        }

        static void construct( PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
        {
            using namespace libdvid;
            using namespace boost::python;

            BinaryDataPtr binary_data;
            if (obj_ptr == Py_None)
            {
                // As a special convenience, we auto-convert None to an empty buffer.
                binary_data = BinaryData::create_binary_data();
            }
            else
            {
                if (!PyObject_CheckBuffer(obj_ptr))
                {
                    std::string value_str = extract<std::string>(str(object(handle<>(borrowed(obj_ptr)))));
                    throw ErrMsg("Value is not a buffer: " + value_str);
                }
                Py_buffer py_buffer;
                PyObject_GetBuffer(obj_ptr, &py_buffer, PyBUF_SIMPLE);

                // Copy buffer into BinaryData
                binary_data = BinaryData::create_binary_data(static_cast<char*>(py_buffer.buf), py_buffer.len);
                PyBuffer_Release(&py_buffer);
            }

            // Grab pointer to memory into which to construct the BinaryDataPtr
            void* storage = ((converter::rvalue_from_python_storage<BinaryDataPtr>*) data)->storage.bytes;

            // in-place construct the new std::string
            // extraced from the python object
            new (storage) BinaryDataPtr(binary_data);

            // Stash the memory chunk pointer for later use by boost.python
            data->convertible = storage;
        }
    };

    //*********************************************************************************************
    //*********************************************************************************************
    //* C++ -> Python
    //*********************************************************************************************
    //*********************************************************************************************

    //!*********************************************************************************************
    //! This converts BinaryDataPtr objects into Python strings.
    //! NOTE: It copies the data.
    //!*********************************************************************************************
    struct binary_data_ptr_to_python_str
    {
        static PyObject* convert(BinaryDataPtr const& binary_data)
        {
            return PyString_FromStringAndSize( binary_data->get_data().c_str(), binary_data->get_data().size() );
        }
    };

    //!*********************************************************************************************
    //! Converts the given DVIDVoxels object into a numpy array.
    //! NOTE:The ndarray will *steal* the data from the DVIDVoxels object.
    //!*********************************************************************************************
    template <class VolumeType> // VolumeType must be some DVIDVoxels<T, N>
    struct volume_to_ndarray
    {
        static PyObject* convert( VolumeType volume )
        {
            using namespace boost::python;
            using namespace libdvid;

            typedef typename VolumeType::voxel_type voxel_type;

            BinaryDataPtr volume_data = volume.get_binary();

            // Wrap the BinaryData in a BinaryDataHolder object,
            // which is managed via Python's reference counting scheme.
            object py_managed_bd = PyBinaryDataHolder();
            BinaryDataHolder & holder = extract<BinaryDataHolder&>(py_managed_bd);
            holder.ptr = volume_data;

            // Copy dims to type numpy expects.
            std::vector<npy_intp> numpy_dims( volume.get_dims().begin(), volume.get_dims().end() );

            // We will create a new array with the data from the existing PyBinaryDataHolder object (no copy).
            // The basic idea is described in the following link, but can get away with a lot less code
            // because we used boost-python to define the Python type (PyBinaryDataHolder).
            // (Note: this post is old, so the particular API we're using here is slightly different.)
            // http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory
            void const * raw_data = static_cast<void const*>(volume_data->get_raw());
            PyObject * array_object = PyArray_SimpleNewFromData( numpy_dims.size(),
                                                                 &numpy_dims[0],
                                                                 numpy_typenums<voxel_type>::typenum,
                                                                 const_cast<void*>(raw_data) );
            if (!array_object)
            {
                throw ErrMsg("Failed to create array from BinaryData!");
            }
            PyArrayObject * ndarray = reinterpret_cast<PyArrayObject *>( array_object );

            // As described in the link above, assigning the 'base' pointer here ensures
            //  that the memory is deallocated when the user is done with the ndarray.
            int status = PyArray_SetBaseObject(ndarray, py_managed_bd.ptr());
            if (status != 0)
            {
                throw ErrMsg("Failed to set array base object!");
            }
            // PyArray_SetBaseObject *steals* the reference, so we need to INCREF here
            //  to make sure the binary data object isn't destroyed when we return.
            incref(py_managed_bd.ptr());

            // Return the new array.
            return array_object;
        }
    };

    //!*********************************************************************************************
    //! This converts Json::Value objects into python dict objects.
    //! NOTE: This isn't an efficient conversion method.
    //!*********************************************************************************************
    struct json_value_to_dict
    {
        static PyObject* convert(Json::Value const & json_value)
        {
            using namespace boost::python;

            // For now, easiest thing to do is just export as
            //  string and re-parse via python's json module.
            std::ostringstream ss;
            ss << json_value;

            object json = import("json");
            return incref(json.attr("loads")( ss.str() ).ptr());
        }
    };

}} // namespace libdvid::python
<|endoftext|>


<commit_before>#include "libmemcached/memcached.h"
#include <string.h>
#include <stdio.h>

#include <string>

class Memcached
{
  memcached_st memc;
  memcached_result_st result;

public:

  Memcached()
    :
      memc(),
      result()
  {
    memcached_create(&memc);
  }

  Memcached(memcached_st *clone)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, clone);
  }

  ~Memcached()
  {
    memcached_free(&memc);
  }

  std::string fetch(const std::string& key, size_t *key_length, size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_fetch(&memc, const_cast<char *>(key.c_str()), key_length,
                                 value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  std::string get(const std::string& key, size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get(&memc, key.c_str(), key.length(),
                               value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  std::string get_by_key(const std::string& master_key,
                   const std::string& key,
                   size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get_by_key(&memc, master_key.c_str(), master_key.length(),
                                      key.c_str(), key.length(),
                                      value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  memcached_return mget(char **keys, size_t *key_length,
                        unsigned int number_of_keys)
  {

    return memcached_mget(&memc, keys, key_length, number_of_keys);
  }

  bool set(const std::string& key, const char *value, size_t value_length)
  {
    memcached_return rc= memcached_set(&memc, key.c_str(), key.length(),
                                       value, value_length,
                                       time_t(0), uint32_t(0));
    return (rc == MEMCACHED_SUCCESS);
  }

  bool set_by_key(const std::string& master_key,
                  const std::string& key,
                  const char *value, size_t value_length)
  {
    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(), key.length(),
                                              value, value_length,
                                              time_t(0),
                                              uint32_t(0));
    return (rc == MEMCACHED_SUCCESS);
  }

  bool increment(const std::string& key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool decrement(const char *key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_decrement(&memc, key, strlen(key),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add(const char *key, const char *value, size_t value_length)
  {
    memcached_return rc= memcached_add(&memc, key, strlen(key), value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add_by_key(const char *master_key, const char *key,
                  const char *value, size_t value_length)
  {
    memcached_return rc= memcached_add_by_key(&memc, master_key, strlen(master_key),
                                              key, strlen(key),
                                              value, value_length,
                                              0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace(const char *key, const char *value,
               size_t value_length)
  {
    memcached_return rc= memcached_replace(&memc, key, strlen(key),
                                           value, value_length,
                                           0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace_by_key(const char *master_key, const char *key,
                      const char *value, size_t value_length)
  {
    memcached_return rc= memcached_replace_by_key(&memc, master_key, strlen(master_key),
                                                  key, strlen(key),
                                                  value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend(const char *key, const char *value,
               size_t value_length)
  {
    memcached_return rc= memcached_prepend(&memc, key, strlen(key),
                                           value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend_by_key(const char *master_key, const char *key,
                      const char *value, size_t value_length)
  {
    memcached_return rc= memcached_prepend_by_key(&memc, master_key, strlen(master_key),
                                                  key, strlen(key),
                                                  value, value_length,
                                                  0,
                                                  0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append(const char *key, const char *value,
              size_t value_length)
  {
    memcached_return rc= memcached_append(&memc, key, strlen(key),
                                          value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append_by_key(const char *master_key, const char *key,
                     const char *value, size_t value_length)
  {
    memcached_return rc= memcached_append_by_key(&memc,
                                                 master_key, strlen(master_key),
                                                 key, strlen(key),
                                                 value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas(const char *key, const char *value,
           size_t value_length, uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas(&memc, key, strlen(key),
                                       value, value_length, 0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas_by_key(const char *master_key, const char *key,
                  const char *value, size_t value_length,
                  uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas_by_key(&memc,
                                              master_key, strlen(master_key),
                                              key, strlen(key),
                                              value, value_length,
                                              0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  // using 'remove' vs. 'delete' since 'delete' is a keyword
  bool remove(const std::string& key)
  {
    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool delete_by_key(const char *master_key, const char *key)
  {
    memcached_return rc= memcached_delete_by_key(&memc, master_key, strlen(master_key),
                                                 key, strlen(key), 0);
    return (rc == MEMCACHED_SUCCESS);
  }
};
<commit_msg>Removing un-needed include declaration from C++ interface.<commit_after>#include "libmemcached/memcached.h"
#include <string.h>

#include <string>

class Memcached
{
  memcached_st memc;
  memcached_result_st result;

public:

  Memcached()
    :
      memc(),
      result()
  {
    memcached_create(&memc);
  }

  Memcached(memcached_st *clone)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, clone);
  }

  ~Memcached()
  {
    memcached_free(&memc);
  }

  std::string fetch(const std::string& key, size_t *key_length, size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_fetch(&memc, const_cast<char *>(key.c_str()), key_length,
                                 value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  std::string get(const std::string& key, size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get(&memc, key.c_str(), key.length(),
                               value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  std::string get_by_key(const std::string& master_key,
                         const std::string& key,
                         size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get_by_key(&memc, master_key.c_str(), master_key.length(),
                                      key.c_str(), key.length(),
                                      value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  memcached_return mget(char **keys, size_t *key_length,
                        unsigned int number_of_keys)
  {

    return memcached_mget(&memc, keys, key_length, number_of_keys);
  }

  bool set(const std::string& key, const char *value, size_t value_length)
  {
    memcached_return rc= memcached_set(&memc, key.c_str(), key.length(),
                                       value, value_length,
                                       time_t(0), uint32_t(0));
    return (rc == MEMCACHED_SUCCESS);
  }

  bool set_by_key(const std::string& master_key,
                  const std::string& key,
                  const char *value, size_t value_length)
  {
    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(), key.length(),
                                              value, value_length,
                                              time_t(0),
                                              uint32_t(0));
    return (rc == MEMCACHED_SUCCESS);
  }

  bool increment(const std::string& key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool decrement(const char *key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_decrement(&memc, key, strlen(key),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add(const char *key, const char *value, size_t value_length)
  {
    memcached_return rc= memcached_add(&memc, key, strlen(key), value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add_by_key(const char *master_key, const char *key,
                  const char *value, size_t value_length)
  {
    memcached_return rc= memcached_add_by_key(&memc, master_key, strlen(master_key),
                                              key, strlen(key),
                                              value, value_length,
                                              0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace(const char *key, const char *value,
               size_t value_length)
  {
    memcached_return rc= memcached_replace(&memc, key, strlen(key),
                                           value, value_length,
                                           0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace_by_key(const char *master_key, const char *key,
                      const char *value, size_t value_length)
  {
    memcached_return rc= memcached_replace_by_key(&memc, master_key, strlen(master_key),
                                                  key, strlen(key),
                                                  value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend(const char *key, const char *value,
               size_t value_length)
  {
    memcached_return rc= memcached_prepend(&memc, key, strlen(key),
                                           value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend_by_key(const char *master_key, const char *key,
                      const char *value, size_t value_length)
  {
    memcached_return rc= memcached_prepend_by_key(&memc, master_key, strlen(master_key),
                                                  key, strlen(key),
                                                  value, value_length,
                                                  0,
                                                  0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append(const char *key, const char *value,
              size_t value_length)
  {
    memcached_return rc= memcached_append(&memc, key, strlen(key),
                                          value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append_by_key(const char *master_key, const char *key,
                     const char *value, size_t value_length)
  {
    memcached_return rc= memcached_append_by_key(&memc,
                                                 master_key, strlen(master_key),
                                                 key, strlen(key),
                                                 value, value_length, 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas(const char *key, const char *value,
           size_t value_length, uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas(&memc, key, strlen(key),
                                       value, value_length, 0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas_by_key(const char *master_key, const char *key,
                  const char *value, size_t value_length,
                  uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas_by_key(&memc,
                                              master_key, strlen(master_key),
                                              key, strlen(key),
                                              value, value_length,
                                              0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  // using 'remove' vs. 'delete' since 'delete' is a keyword
  bool remove(const std::string& key)
  {
    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool delete_by_key(const char *master_key, const char *key)
  {
    memcached_return rc= memcached_delete_by_key(&memc, master_key, strlen(master_key),
                                                 key, strlen(key), 0);
    return (rc == MEMCACHED_SUCCESS);
  }
};
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <math.h>

#include "cssysdef.h"
#include "csengine/texture.h"
#include "csengine/engine.h"
#include "iimage.h"
#include "itxtmgr.h"

//---------------------------------------------------------------------------

IMPLEMENT_CSOBJTYPE (csTextureWrapper,csPObject);

csTextureWrapper::csTextureWrapper (iImage* Image) :
  csPObject (), handle (NULL), flags (CS_TEXTURE_3D)
{
  (image = Image)->IncRef ();
  key_col_r = -1;
  if(image->HasKeycolor ())
    image->GetKeycolor( key_col_r, key_col_g, key_col_b );
  csEngine::current_engine->AddToCurrentRegion (this);
}

csTextureWrapper::csTextureWrapper (csTextureWrapper &th) :
  csPObject (), handle (NULL)
{
  flags = th.flags;
  (image = th.image)->IncRef ();
  key_col_r = th.key_col_r;
  key_col_g = th.key_col_g;
  key_col_b = th.key_col_b;
  handle = th.GetTextureHandle ();
  SetName (th.GetName ());
  if (handle)
    SetKeyColor (key_col_r, key_col_g, key_col_b);
  csEngine::current_engine->AddToCurrentRegion (this);
}

csTextureWrapper::csTextureWrapper (iTextureHandle *ith) :
  csPObject (), image (NULL)
{
  ith->IncRef ();
  flags = ith->GetFlags ();
  if (ith->GetKeyColor ())
  {
    UByte r, g, b;
    ith->GetKeyColor (r, g, b);
    SetKeyColor ((int)r, (int)g, (int)b);
  }
  handle = ith;
  csEngine::current_engine->AddToCurrentRegion (this);
}

csTextureWrapper::~csTextureWrapper ()
{
  if (handle)
    handle->DecRef ();
  if (image)
    image->DecRef ();
}

void csTextureWrapper::SetImageFile (iImage *Image)
{
  if (image)
    image->DecRef ();
  (image = Image)->IncRef ();
}

void csTextureWrapper::SetKeyColor (int red, int green, int blue)
{
  if (handle)
    if (red >= 0)
      handle->SetKeyColor (red, green, blue);
    else
      handle->SetKeyColor (false);
  key_col_r = red;
  key_col_g = green;
  key_col_b = blue;
}

void csTextureWrapper::Register (iTextureManager *txtmgr)
{
  // smgh 22/07/00
  //if (handle) handle->DecRef ();

  // Now we check the size of the loaded image. Having an image, that
  // is not a power of two will result in strange errors while
  // rendering. It is by far better to check the format of all textures
  // already while loading them.
  if (flags & CS_TEXTURE_3D)
  {
    int Width  = image->GetWidth ();
    int Height = image->GetHeight ();

    if (!IsPowerOf2 (Width) || !IsPowerOf2 (Height))
      CsPrintf (MSG_WARNING,
        "Inefficient texture image '%s' dimenstions!\n"
        "The width (%d) and height (%d) should be a power of two.\n",
        GetName (), Width, Height);
  }

  handle = txtmgr->RegisterTexture (image, flags);
  if (handle)
    SetKeyColor (key_col_r, key_col_g, key_col_b);
}

//-------------------------------------------------------- csTextureList -----//

csTextureList::~csTextureList ()
{
  DeleteAll ();
}

csTextureWrapper *csTextureList::NewTexture (iImage *image)
{
  csTextureWrapper *tm = new csTextureWrapper (image);
  Push (tm);
  return tm;
}

csTextureWrapper *csTextureList::NewTexture (iTextureHandle *ith)
{
  csTextureWrapper *tm = new csTextureWrapper (ith);
  Push (tm);
  return tm;
}
<commit_msg>Forgot to commit.<commit_after>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <math.h>

#include "cssysdef.h"
#include "csengine/texture.h"
#include "csengine/engine.h"
#include "iimage.h"
#include "itxtmgr.h"

//---------------------------------------------------------------------------

IMPLEMENT_CSOBJTYPE (csTextureWrapper,csPObject);

IMPLEMENT_IBASE (csTextureWrapper)
  IMPLEMENTS_INTERFACE (iTextureWrapper)
IMPLEMENT_IBASE_END

csTextureWrapper::csTextureWrapper (iImage* Image) :
  csPObject (), handle (NULL), flags (CS_TEXTURE_3D)
{
  CONSTRUCT_IBASE (NULL);
  (image = Image)->IncRef ();
  key_col_r = -1;
  if(image->HasKeycolor ())
    image->GetKeycolor( key_col_r, key_col_g, key_col_b );
  csEngine::current_engine->AddToCurrentRegion (this);
}

csTextureWrapper::csTextureWrapper (csTextureWrapper &th) :
  csPObject (), handle (NULL)
{
  CONSTRUCT_IBASE (NULL);
  flags = th.flags;
  (image = th.image)->IncRef ();
  key_col_r = th.key_col_r;
  key_col_g = th.key_col_g;
  key_col_b = th.key_col_b;
  handle = th.GetTextureHandle ();
  SetName (th.GetName ());
  if (handle)
    SetKeyColor (key_col_r, key_col_g, key_col_b);
  csEngine::current_engine->AddToCurrentRegion (this);
}

csTextureWrapper::csTextureWrapper (iTextureHandle *ith) :
  csPObject (), image (NULL)
{
  CONSTRUCT_IBASE (NULL);
  ith->IncRef ();
  flags = ith->GetFlags ();
  if (ith->GetKeyColor ())
  {
    UByte r, g, b;
    ith->GetKeyColor (r, g, b);
    SetKeyColor ((int)r, (int)g, (int)b);
  }
  handle = ith;
  csEngine::current_engine->AddToCurrentRegion (this);
}

csTextureWrapper::~csTextureWrapper ()
{
  if (handle)
    handle->DecRef ();
  if (image)
    image->DecRef ();
}

void csTextureWrapper::SetImageFile (iImage *Image)
{
  if (image)
    image->DecRef ();
  (image = Image)->IncRef ();
}

void csTextureWrapper::SetKeyColor (int red, int green, int blue)
{
  if (handle)
    if (red >= 0)
      handle->SetKeyColor (red, green, blue);
    else
      handle->SetKeyColor (false);
  key_col_r = red;
  key_col_g = green;
  key_col_b = blue;
}

void csTextureWrapper::Register (iTextureManager *txtmgr)
{
  // smgh 22/07/00
  //if (handle) handle->DecRef ();

  // Now we check the size of the loaded image. Having an image, that
  // is not a power of two will result in strange errors while
  // rendering. It is by far better to check the format of all textures
  // already while loading them.
  if (flags & CS_TEXTURE_3D)
  {
    int Width  = image->GetWidth ();
    int Height = image->GetHeight ();

    if (!IsPowerOf2 (Width) || !IsPowerOf2 (Height))
      CsPrintf (MSG_WARNING,
        "Inefficient texture image '%s' dimenstions!\n"
        "The width (%d) and height (%d) should be a power of two.\n",
        GetName (), Width, Height);
  }

  handle = txtmgr->RegisterTexture (image, flags);
  if (handle)
    SetKeyColor (key_col_r, key_col_g, key_col_b);
}

//-------------------------------------------------------- csTextureList -----//

csTextureList::~csTextureList ()
{
  DeleteAll ();
}

csTextureWrapper *csTextureList::NewTexture (iImage *image)
{
  csTextureWrapper *tm = new csTextureWrapper (image);
  Push (tm);
  return tm;
}

csTextureWrapper *csTextureList::NewTexture (iTextureHandle *ith)
{
  csTextureWrapper *tm = new csTextureWrapper (ith);
  Push (tm);
  return tm;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/experiments/alr_experiment.h"

#include <inttypes.h>
#include <stdio.h>
#include <string>

#include "api/transport/field_trial_based_config.h"
#include "rtc_base/logging.h"

namespace webrtc {

const char AlrExperimentSettings::kScreenshareProbingBweExperimentName[] =
    "WebRTC-ProbingScreenshareBwe";
const char AlrExperimentSettings::kStrictPacingAndProbingExperimentName[] =
    "WebRTC-StrictPacingAndProbing";
const char kDefaultProbingScreenshareBweSettings[] = "1.0,2875,80,40,-60,3";

bool AlrExperimentSettings::MaxOneFieldTrialEnabled() {
  return AlrExperimentSettings::MaxOneFieldTrialEnabled(
      FieldTrialBasedConfig());
}

bool AlrExperimentSettings::MaxOneFieldTrialEnabled(
    const WebRtcKeyValueConfig& key_value_config) {
  return key_value_config.Lookup(kStrictPacingAndProbingExperimentName)
             .empty() ||
         key_value_config.Lookup(kScreenshareProbingBweExperimentName).empty();
}

absl::optional<AlrExperimentSettings>
AlrExperimentSettings::CreateFromFieldTrial(const char* experiment_name) {
  return AlrExperimentSettings::CreateFromFieldTrial(FieldTrialBasedConfig(),
                                                     experiment_name);
}

absl::optional<AlrExperimentSettings>
AlrExperimentSettings::CreateFromFieldTrial(
    const WebRtcKeyValueConfig& key_value_config,
    const char* experiment_name) {
  absl::optional<AlrExperimentSettings> ret;
  std::string group_name = key_value_config.Lookup(experiment_name);

  const std::string kIgnoredSuffix = "_Dogfood";
  std::string::size_type suffix_pos = group_name.rfind(kIgnoredSuffix);
  if (suffix_pos != std::string::npos &&
      suffix_pos == group_name.length() - kIgnoredSuffix.length()) {
    group_name.resize(group_name.length() - kIgnoredSuffix.length());
  }

  if (group_name.empty()) {
    if (experiment_name == kScreenshareProbingBweExperimentName) {
      // This experiment is now default-on with fixed settings.
      // TODO(sprang): Remove this kill-switch and clean up experiment code.
      group_name = kDefaultProbingScreenshareBweSettings;
    } else {
      return ret;
    }
  }

  AlrExperimentSettings settings;
  if (sscanf(group_name.c_str(), "%f,%" PRId64 ",%d,%d,%d,%d",
             &settings.pacing_factor, &settings.max_paced_queue_time,
             &settings.alr_bandwidth_usage_percent,
             &settings.alr_start_budget_level_percent,
             &settings.alr_stop_budget_level_percent,
             &settings.group_id) == 6) {
    ret.emplace(settings);
    RTC_LOG(LS_INFO) << "Using ALR experiment settings: "
                        "pacing factor: "
                     << settings.pacing_factor << ", max pacer queue length: "
                     << settings.max_paced_queue_time
                     << ", ALR start bandwidth usage percent: "
                     << settings.alr_bandwidth_usage_percent
                     << ", ALR end budget level percent: "
                     << settings.alr_start_budget_level_percent
                     << ", ALR end budget level percent: "
                     << settings.alr_stop_budget_level_percent
                     << ", ALR experiment group ID: " << settings.group_id;
  } else {
    RTC_LOG(LS_INFO) << "Failed to parse ALR experiment: " << experiment_name;
  }

  return ret;
}

}  // namespace webrtc
<commit_msg>Fix text logging of ALR detector experiment settings.<commit_after>/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/experiments/alr_experiment.h"

#include <inttypes.h>
#include <stdio.h>
#include <string>

#include "api/transport/field_trial_based_config.h"
#include "rtc_base/logging.h"

namespace webrtc {

const char AlrExperimentSettings::kScreenshareProbingBweExperimentName[] =
    "WebRTC-ProbingScreenshareBwe";
const char AlrExperimentSettings::kStrictPacingAndProbingExperimentName[] =
    "WebRTC-StrictPacingAndProbing";
const char kDefaultProbingScreenshareBweSettings[] = "1.0,2875,80,40,-60,3";

bool AlrExperimentSettings::MaxOneFieldTrialEnabled() {
  return AlrExperimentSettings::MaxOneFieldTrialEnabled(
      FieldTrialBasedConfig());
}

bool AlrExperimentSettings::MaxOneFieldTrialEnabled(
    const WebRtcKeyValueConfig& key_value_config) {
  return key_value_config.Lookup(kStrictPacingAndProbingExperimentName)
             .empty() ||
         key_value_config.Lookup(kScreenshareProbingBweExperimentName).empty();
}

absl::optional<AlrExperimentSettings>
AlrExperimentSettings::CreateFromFieldTrial(const char* experiment_name) {
  return AlrExperimentSettings::CreateFromFieldTrial(FieldTrialBasedConfig(),
                                                     experiment_name);
}

absl::optional<AlrExperimentSettings>
AlrExperimentSettings::CreateFromFieldTrial(
    const WebRtcKeyValueConfig& key_value_config,
    const char* experiment_name) {
  absl::optional<AlrExperimentSettings> ret;
  std::string group_name = key_value_config.Lookup(experiment_name);

  const std::string kIgnoredSuffix = "_Dogfood";
  std::string::size_type suffix_pos = group_name.rfind(kIgnoredSuffix);
  if (suffix_pos != std::string::npos &&
      suffix_pos == group_name.length() - kIgnoredSuffix.length()) {
    group_name.resize(group_name.length() - kIgnoredSuffix.length());
  }

  if (group_name.empty()) {
    if (experiment_name == kScreenshareProbingBweExperimentName) {
      // This experiment is now default-on with fixed settings.
      // TODO(sprang): Remove this kill-switch and clean up experiment code.
      group_name = kDefaultProbingScreenshareBweSettings;
    } else {
      return ret;
    }
  }

  AlrExperimentSettings settings;
  if (sscanf(group_name.c_str(), "%f,%" PRId64 ",%d,%d,%d,%d",
             &settings.pacing_factor, &settings.max_paced_queue_time,
             &settings.alr_bandwidth_usage_percent,
             &settings.alr_start_budget_level_percent,
             &settings.alr_stop_budget_level_percent,
             &settings.group_id) == 6) {
    ret.emplace(settings);
    RTC_LOG(LS_INFO) << "Using ALR experiment settings: "
                        "pacing factor: "
                     << settings.pacing_factor << ", max pacer queue length: "
                     << settings.max_paced_queue_time
                     << ", ALR bandwidth usage percent: "
                     << settings.alr_bandwidth_usage_percent
                     << ", ALR start budget level percent: "
                     << settings.alr_start_budget_level_percent
                     << ", ALR end budget level percent: "
                     << settings.alr_stop_budget_level_percent
                     << ", ALR experiment group ID: " << settings.group_id;
  } else {
    RTC_LOG(LS_INFO) << "Failed to parse ALR experiment: " << experiment_name;
  }

  return ret;
}

}  // namespace webrtc
<|endoftext|>