<commit_before>#include "xchainer/python/array.h"

#include <algorithm>
#include <cstdint>

#include <pybind11/numpy.h>
#include <pybind11/operators.h>

#include "xchainer/array.h"
#include "xchainer/dtype.h"
#include "xchainer/error.h"

#include "xchainer/python/common.h"

namespace xchainer {

namespace py = pybind11;

namespace {

// TODO(beam2d): The current binding has an overhead on wrapping ArrayBodyPtr by Array, which copies shared_ptr. One
// simple way to avoid this overhead is to use reinterpret_cast<Array&>(ptr). This cast is valid if ArrayBodyPtr (i.e.,
// shared_ptr) satisfies "standard layout" conditions. We can test if ArrayBodyPtr satisfies these conditions by
// std::is_standard_layout (see http://en.cppreference.com/w/cpp/types/is_standard_layout#Notes).

using ArrayBodyPtr = std::shared_ptr<internal::ArrayBody>;
using ConstArrayBodyPtr = std::shared_ptr<const internal::ArrayBody>;

Dtype NumpyDtypeToDtype(const py::dtype& npdtype) {
    switch (npdtype.kind()) {
        case 'b':
            return Dtype::kBool;
        case 'i':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kInt8;
                case 2:
                    return Dtype::kInt16;
                case 4:
                    return Dtype::kInt32;
                case 8:
                    return Dtype::kInt64;
                default:
                    break;
            }
            break;
        case 'u':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kUInt8;
                default:
                    break;
            }
            break;
        case 'f':
            switch (npdtype.itemsize()) {
                case 4:
                    return Dtype::kFloat32;
                case 8:
                    return Dtype::kFloat64;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    throw DtypeError("unsupported NumPy dtype");
}

ArrayBodyPtr MakeArray(const Shape& shape, Dtype dtype, py::list list) {
    auto total_size = shape.total_size();
    auto bytes = GetElementSize(dtype) * total_size;
    if (static_cast<size_t>(total_size) != list.size()) {
        throw DimensionError("Invalid data length");
    }

    // Allocate a buffer and copy data
    std::shared_ptr<void> ptr = std::make_unique<uint8_t[]>(bytes);
    VisitDtype(dtype, [&](auto pt) {
        using T = typename decltype(pt)::type;
        std::transform(list.begin(), list.end(), static_cast<T*>(ptr.get()), [](auto& item) { return py::cast<T>(item); });
    });
    return Array::FromBuffer(shape, dtype, ptr).move_body();
}

ArrayBodyPtr MakeArray(py::array array) {
    if ((array.flags() & py::array::c_style) == 0) {
        throw DimensionError("cannot convert non-contiguous NumPy array to Array");
    }

    Dtype dtype = NumpyDtypeToDtype(array.dtype());
    py::buffer_info info = array.request();
    Shape shape(info.shape);

    // data holds the copy of py::array which in turn references the NumPy array and the buffer is therefore not released
    std::shared_ptr<void> data(std::make_shared<py::array>(std::move(array)), array.mutable_data());

    return Array::FromBuffer(shape, dtype, data).move_body();
}

py::buffer_info MakeNumpyArrayFromArray(internal::ArrayBody& self) {
    // Used as a temporary accessor
    Array array{std::move(ArrayBodyPtr(&self, [](internal::ArrayBody* ptr) {
        (void)ptr;  // unused
    }))};

    if (!array.is_contiguous()) {
        throw DimensionError("cannot convert non-contiguous Array to NumPy array");
    }

    int64_t itemsize{GetElementSize(array.dtype())};
    const Shape& shape = array.shape();

    // compute C-contiguous strides
    size_t ndim = array.ndim();
    std::vector<size_t> strides(ndim);
    if (ndim > 0) {
        std::partial_sum(shape.crbegin(), shape.crend() - 1, strides.rbegin() + 1, std::multiplies<size_t>());
        strides.back() = 1;
        std::transform(strides.crbegin(), strides.crend(), strides.rbegin(), [&itemsize](size_t item) { return item * itemsize; });
    }

    return py::buffer_info(array.data().get(), itemsize, std::string(1, GetCharCode(array.dtype())), ndim, shape, strides);
}

}  // namespace

void InitXchainerArray(pybind11::module& m) {
    py::class_<internal::ArrayBody, ArrayBodyPtr>{m, "Array", py::buffer_protocol()}
        .def(py::init(py::overload_cast<const Shape&, Dtype, py::list>(&MakeArray)))
        .def(py::init(py::overload_cast<py::array>(&MakeArray)))
        .def_buffer(&MakeNumpyArrayFromArray)
        .def("view",
             [](const ArrayBodyPtr& self) {
                 // Duplicate the array body
                 return std::make_shared<internal::ArrayBody>(*self);
             })
        .def("__iadd__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} += Array{rhs}).move_body(); })
        .def("__imul__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} *= Array{rhs}).move_body(); })
        .def("__add__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} + Array{rhs}).move_body(); })
        .def("__mul__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} * Array{rhs}).move_body(); })
        .def("__repr__", [](const ArrayBodyPtr& self) { return Array{self}.ToString(); })
        .def("copy", [](const ArrayBodyPtr& self) { return Array{self}.Copy().move_body(); })
        .def("as_constant", [](const ArrayBodyPtr& self,
                               bool copy) { return Array{self}.AsConstant(copy ? CopyKind::kCopy : CopyKind::kView).move_body(); },
             py::arg("copy") = true)
        .def("as_constant",
             [](const ArrayBodyPtr& self, const std::vector<GraphId>& graph_ids, bool copy) {
                 return Array{self}.AsConstant(graph_ids, copy ? CopyKind::kCopy : CopyKind::kView).move_body();
             },
             py::arg("graph_ids") = std::vector<GraphId>{}, py::arg("copy") = true)
        .def("require_grad",
             [](const ArrayBodyPtr& self, const GraphId& graph_id) { return Array{self}.RequireGrad(graph_id).move_body(); },
             py::arg("graph_id") = "")
        .def("is_grad_required", [](const ArrayBodyPtr& self, const GraphId& graph_id) { return Array{self}.IsGradRequired(graph_id); },
             py::arg("graph_id") = "")
        .def("get_grad",
             [](const ArrayBodyPtr& self, const GraphId& graph_id) -> ConstArrayBodyPtr {
                 const nonstd::optional<Array>& grad = Array{self}.GetGrad(graph_id);
                 if (grad.has_value()) {
                     return grad->body();
                 } else {
                     return nullptr;
                 }
             },
             py::arg("graph_id") = "")
        .def("set_grad",
             [](const ArrayBodyPtr& self, const ArrayBodyPtr& grad, const GraphId& graph_id) {
                 auto array = Array{self};
                 if (grad) {
                     array.SetGrad(Array{grad}, graph_id);
                 } else {
                     array.ClearGrad(graph_id);
                 }
             },
             py::arg("grad"), py::arg("graph_id") = "")
        .def_property_readonly("dtype", [](const ArrayBodyPtr& self) { return Array{self}.dtype(); })
        .def_property_readonly("element_bytes", [](const ArrayBodyPtr& self) { return Array{self}.element_bytes(); })
        .def_property_readonly("is_contiguous", [](const ArrayBodyPtr& self) { return Array{self}.is_contiguous(); })
        .def_property_readonly("ndim", [](const ArrayBodyPtr& self) { return Array{self}.ndim(); })
        .def_property_readonly("offset", [](const ArrayBodyPtr& self) { return Array{self}.offset(); })
        .def_property_readonly("shape", [](const ArrayBodyPtr& self) { return Array{self}.shape(); })
        .def_property_readonly("total_bytes", [](const ArrayBodyPtr& self) { return Array{self}.total_bytes(); })
        .def_property_readonly("total_size", [](const ArrayBodyPtr& self) { return Array{self}.total_size(); })
        .def_property_readonly("_debug_data_memory_address",  // These methods starting with `_debug_` are stubs for testing
                               [](const ArrayBodyPtr& self) { return reinterpret_cast<std::uintptr_t>(Array{self}.data().get()); })
        .def_property_readonly("_debug_flat_data", [](const ArrayBodyPtr& self) {
            py::list list;
            Array array{self};

            // Copy data into the list
            VisitDtype(array.dtype(), [&array, &list](auto pt) {
                using T = typename decltype(pt)::type;
                auto size = array.total_size();
                const T& data = *std::static_pointer_cast<const T>(array.data());
                for (int64_t i = 0; i < size; ++i) {
                    list.append((&data)[i]);
                }
            });

            return list;
        });
}

}  // namespace xchainer
<commit_msg>Remove unnecessary default parameter<commit_after>#include "xchainer/python/array.h"

#include <algorithm>
#include <cstdint>

#include <pybind11/numpy.h>
#include <pybind11/operators.h>

#include "xchainer/array.h"
#include "xchainer/dtype.h"
#include "xchainer/error.h"

#include "xchainer/python/common.h"

namespace xchainer {

namespace py = pybind11;

namespace {

// TODO(beam2d): The current binding has an overhead on wrapping ArrayBodyPtr by Array, which copies shared_ptr. One
// simple way to avoid this overhead is to use reinterpret_cast<Array&>(ptr). This cast is valid if ArrayBodyPtr (i.e.,
// shared_ptr) satisfies "standard layout" conditions. We can test if ArrayBodyPtr satisfies these conditions by
// std::is_standard_layout (see http://en.cppreference.com/w/cpp/types/is_standard_layout#Notes).

using ArrayBodyPtr = std::shared_ptr<internal::ArrayBody>;
using ConstArrayBodyPtr = std::shared_ptr<const internal::ArrayBody>;

Dtype NumpyDtypeToDtype(const py::dtype& npdtype) {
    switch (npdtype.kind()) {
        case 'b':
            return Dtype::kBool;
        case 'i':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kInt8;
                case 2:
                    return Dtype::kInt16;
                case 4:
                    return Dtype::kInt32;
                case 8:
                    return Dtype::kInt64;
                default:
                    break;
            }
            break;
        case 'u':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kUInt8;
                default:
                    break;
            }
            break;
        case 'f':
            switch (npdtype.itemsize()) {
                case 4:
                    return Dtype::kFloat32;
                case 8:
                    return Dtype::kFloat64;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    throw DtypeError("unsupported NumPy dtype");
}

ArrayBodyPtr MakeArray(const Shape& shape, Dtype dtype, py::list list) {
    auto total_size = shape.total_size();
    auto bytes = GetElementSize(dtype) * total_size;
    if (static_cast<size_t>(total_size) != list.size()) {
        throw DimensionError("Invalid data length");
    }

    // Allocate a buffer and copy data
    std::shared_ptr<void> ptr = std::make_unique<uint8_t[]>(bytes);
    VisitDtype(dtype, [&](auto pt) {
        using T = typename decltype(pt)::type;
        std::transform(list.begin(), list.end(), static_cast<T*>(ptr.get()), [](auto& item) { return py::cast<T>(item); });
    });
    return Array::FromBuffer(shape, dtype, ptr).move_body();
}

ArrayBodyPtr MakeArray(py::array array) {
    if ((array.flags() & py::array::c_style) == 0) {
        throw DimensionError("cannot convert non-contiguous NumPy array to Array");
    }

    Dtype dtype = NumpyDtypeToDtype(array.dtype());
    py::buffer_info info = array.request();
    Shape shape(info.shape);

    // data holds the copy of py::array which in turn references the NumPy array and the buffer is therefore not released
    std::shared_ptr<void> data(std::make_shared<py::array>(std::move(array)), array.mutable_data());

    return Array::FromBuffer(shape, dtype, data).move_body();
}

py::buffer_info MakeNumpyArrayFromArray(internal::ArrayBody& self) {
    // Used as a temporary accessor
    Array array{std::move(ArrayBodyPtr(&self, [](internal::ArrayBody* ptr) {
        (void)ptr;  // unused
    }))};

    if (!array.is_contiguous()) {
        throw DimensionError("cannot convert non-contiguous Array to NumPy array");
    }

    int64_t itemsize{GetElementSize(array.dtype())};
    const Shape& shape = array.shape();

    // compute C-contiguous strides
    size_t ndim = array.ndim();
    std::vector<size_t> strides(ndim);
    if (ndim > 0) {
        std::partial_sum(shape.crbegin(), shape.crend() - 1, strides.rbegin() + 1, std::multiplies<size_t>());
        strides.back() = 1;
        std::transform(strides.crbegin(), strides.crend(), strides.rbegin(), [&itemsize](size_t item) { return item * itemsize; });
    }

    return py::buffer_info(array.data().get(), itemsize, std::string(1, GetCharCode(array.dtype())), ndim, shape, strides);
}

}  // namespace

void InitXchainerArray(pybind11::module& m) {
    py::class_<internal::ArrayBody, ArrayBodyPtr>{m, "Array", py::buffer_protocol()}
        .def(py::init(py::overload_cast<const Shape&, Dtype, py::list>(&MakeArray)))
        .def(py::init(py::overload_cast<py::array>(&MakeArray)))
        .def_buffer(&MakeNumpyArrayFromArray)
        .def("view",
             [](const ArrayBodyPtr& self) {
                 // Duplicate the array body
                 return std::make_shared<internal::ArrayBody>(*self);
             })
        .def("__iadd__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} += Array{rhs}).move_body(); })
        .def("__imul__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} *= Array{rhs}).move_body(); })
        .def("__add__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} + Array{rhs}).move_body(); })
        .def("__mul__", [](const ArrayBodyPtr& self, const ArrayBodyPtr& rhs) { return (Array{self} * Array{rhs}).move_body(); })
        .def("__repr__", [](const ArrayBodyPtr& self) { return Array{self}.ToString(); })
        .def("copy", [](const ArrayBodyPtr& self) { return Array{self}.Copy().move_body(); })
        .def("as_constant", [](const ArrayBodyPtr& self,
                               bool copy) { return Array{self}.AsConstant(copy ? CopyKind::kCopy : CopyKind::kView).move_body(); },
             py::arg("copy") = true)
        .def("as_constant",
             [](const ArrayBodyPtr& self, const std::vector<GraphId>& graph_ids, bool copy) {
                 return Array{self}.AsConstant(graph_ids, copy ? CopyKind::kCopy : CopyKind::kView).move_body();
             },
             py::arg("copy") = true)
        .def("require_grad",
             [](const ArrayBodyPtr& self, const GraphId& graph_id) { return Array{self}.RequireGrad(graph_id).move_body(); },
             py::arg("graph_id") = "")
        .def("is_grad_required", [](const ArrayBodyPtr& self, const GraphId& graph_id) { return Array{self}.IsGradRequired(graph_id); },
             py::arg("graph_id") = "")
        .def("get_grad",
             [](const ArrayBodyPtr& self, const GraphId& graph_id) -> ConstArrayBodyPtr {
                 const nonstd::optional<Array>& grad = Array{self}.GetGrad(graph_id);
                 if (grad.has_value()) {
                     return grad->body();
                 } else {
                     return nullptr;
                 }
             },
             py::arg("graph_id") = "")
        .def("set_grad",
             [](const ArrayBodyPtr& self, const ArrayBodyPtr& grad, const GraphId& graph_id) {
                 auto array = Array{self};
                 if (grad) {
                     array.SetGrad(Array{grad}, graph_id);
                 } else {
                     array.ClearGrad(graph_id);
                 }
             },
             py::arg("grad"), py::arg("graph_id") = "")
        .def_property_readonly("dtype", [](const ArrayBodyPtr& self) { return Array{self}.dtype(); })
        .def_property_readonly("element_bytes", [](const ArrayBodyPtr& self) { return Array{self}.element_bytes(); })
        .def_property_readonly("is_contiguous", [](const ArrayBodyPtr& self) { return Array{self}.is_contiguous(); })
        .def_property_readonly("ndim", [](const ArrayBodyPtr& self) { return Array{self}.ndim(); })
        .def_property_readonly("offset", [](const ArrayBodyPtr& self) { return Array{self}.offset(); })
        .def_property_readonly("shape", [](const ArrayBodyPtr& self) { return Array{self}.shape(); })
        .def_property_readonly("total_bytes", [](const ArrayBodyPtr& self) { return Array{self}.total_bytes(); })
        .def_property_readonly("total_size", [](const ArrayBodyPtr& self) { return Array{self}.total_size(); })
        .def_property_readonly("_debug_data_memory_address",  // These methods starting with `_debug_` are stubs for testing
                               [](const ArrayBodyPtr& self) { return reinterpret_cast<std::uintptr_t>(Array{self}.data().get()); })
        .def_property_readonly("_debug_flat_data", [](const ArrayBodyPtr& self) {
            py::list list;
            Array array{self};

            // Copy data into the list
            VisitDtype(array.dtype(), [&array, &list](auto pt) {
                using T = typename decltype(pt)::type;
                auto size = array.total_size();
                const T& data = *std::static_pointer_cast<const T>(array.data());
                for (int64_t i = 0; i < size; ++i) {
                    list.append((&data)[i]);
                }
            });

            return list;
        });
}

}  // namespace xchainer
<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLInterface.h"

#include <OpenGL/gl.h>
#include <OpenGL/glext.h>

#include <mach-o/dyld.h>

// This uses deprecated functions, should rewrite using dlopen, dlsym, dlclose
void* GetProcAddress(const char* name) {
    NSSymbol symbol = NULL;
    if (NSIsSymbolNameDefined(name)) {
        symbol = NSLookupAndBindSymbol(name);
    }
    return NULL == symbol ? NULL : NSAddressOfSymbol(symbol);
}

#define GET_PROC(name) ((GrGL ## name ## Proc) GetProcAddress("_gl" #name))
#define GET_PROC_SUFFIX(name, suffix) ((GrGL ## name ## Proc) GetProcAddress("_gl" #name #suffix))

const GrGLInterface* GrGLCreateNativeInterface() {
    // The gl functions are not context-specific so we create one global
    // interface
    static SkAutoTUnref<GrGLInterface> glInterface;
    if (!glInterface.get()) {
        GrGLInterface* interface = new GrGLInterface;
        glInterface.reset(interface);
        const char* verStr = (const char*) glGetString(GL_VERSION);
        GrGLVersion ver = GrGLGetVersionFromString(verStr);
        const char* extStr = (const char*) glGetString(GL_EXTENSIONS);

        interface->fBindingsExported = kDesktop_GrGLBinding;
        interface->fActiveTexture = glActiveTexture;
        interface->fAttachShader = glAttachShader;
        interface->fBeginQuery = glBeginQuery;
        interface->fBindAttribLocation = glBindAttribLocation;
        interface->fBindBuffer = glBindBuffer;
        if (ver >= GR_GL_VER(3,0)) {
            #if GL_VERSION_3_0
                interface->fBindFragDataLocation = glBindFragDataLocation;
            #else
                interface->fBindFragDataLocation = GET_PROC(BindFragDataLocation);
            #endif
        }
        interface->fBindTexture = glBindTexture;
        interface->fBlendColor = glBlendColor;
        interface->fBlendFunc = glBlendFunc;
        interface->fBufferData = glBufferData;
        interface->fBufferSubData = glBufferSubData;
        interface->fClear = glClear;
        interface->fClearColor = glClearColor;
        interface->fClearStencil = glClearStencil;
        interface->fColorMask = glColorMask;
        interface->fColorPointer = glColorPointer;
        interface->fCompileShader = glCompileShader;
        interface->fCompressedTexImage2D = glCompressedTexImage2D;
        interface->fCreateProgram = glCreateProgram;
        interface->fCreateShader = glCreateShader;
        interface->fCullFace = glCullFace;
        interface->fDeleteBuffers = glDeleteBuffers;
        interface->fDeleteProgram = glDeleteProgram;
        interface->fDeleteQueries = glDeleteQueries;
        interface->fDeleteShader = glDeleteShader;
        interface->fDeleteTextures = glDeleteTextures;
        interface->fDepthMask = glDepthMask;
        interface->fDisable = glDisable;
        interface->fDisableVertexAttribArray =
                                            glDisableVertexAttribArray;
        interface->fDrawArrays = glDrawArrays;
        interface->fDrawBuffer = glDrawBuffer;
        interface->fDrawBuffers = glDrawBuffers;
        interface->fDrawElements = glDrawElements;
        interface->fEnable = glEnable;
        interface->fEnableVertexAttribArray = glEnableVertexAttribArray;
        interface->fEndQuery = glEndQuery;
        interface->fFinish = glFinish;
        interface->fFlush = glFlush;
        interface->fFrontFace = glFrontFace;
        interface->fGenBuffers = glGenBuffers;
        interface->fGenQueries = glGenQueries;
        interface->fGetBufferParameteriv = glGetBufferParameteriv;
        interface->fGetError = glGetError;
        interface->fGetIntegerv = glGetIntegerv;
        interface->fGetProgramInfoLog = glGetProgramInfoLog;
        interface->fGetProgramiv = glGetProgramiv;
        interface->fGetQueryiv = glGetQueryiv;
        interface->fGetQueryObjectiv = glGetQueryObjectiv;
        interface->fGetQueryObjectuiv = glGetQueryObjectuiv;
        interface->fGetShaderInfoLog = glGetShaderInfoLog;
        interface->fGetShaderiv = glGetShaderiv;
        interface->fGetString = glGetString;
        interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
        interface->fGenTextures = glGenTextures;
        interface->fGetUniformLocation = glGetUniformLocation;
        interface->fLineWidth = glLineWidth;
        interface->fLinkProgram = glLinkProgram;
        interface->fMapBuffer = glMapBuffer;
        interface->fPixelStorei = glPixelStorei;
        interface->fReadBuffer = glReadBuffer;
        interface->fReadPixels = glReadPixels;
        interface->fScissor = glScissor;
        interface->fShaderSource = glShaderSource;
        interface->fStencilFunc = glStencilFunc;
        interface->fStencilFuncSeparate = glStencilFuncSeparate;
        interface->fStencilMask = glStencilMask;
        interface->fStencilMaskSeparate = glStencilMaskSeparate;
        interface->fStencilOp = glStencilOp;
        interface->fStencilOpSeparate = glStencilOpSeparate;
        // mac uses GLenum for internalFormat param (non-standard)
        // amounts to int vs. uint.
        interface->fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
        interface->fTexParameteri = glTexParameteri;
    #if GL_ARB_texture_storage || GL_VERSION_4_2
        interface->fTexStorage2D = glTexStorage2D
    #elif GL_EXT_texture_storage
        interface->fTexStorage2D = glTexStorage2DEXT;
    #else
        if (glVer >= GR_GL_VER(4,2) ||
            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
            GR_GL_GET_PROC(TexStorage2D);
        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
            GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
        }
    #endif
        interface->fTexSubImage2D = glTexSubImage2D;
        interface->fUniform1f = glUniform1f;
        interface->fUniform1i = glUniform1i;
        interface->fUniform1fv = glUniform1fv;
        interface->fUniform1iv = glUniform1iv;
        interface->fUniform2f = glUniform2f;
        interface->fUniform2i = glUniform2i;
        interface->fUniform2fv = glUniform2fv;
        interface->fUniform2iv = glUniform2iv;
        interface->fUniform3f = glUniform3f;
        interface->fUniform3i = glUniform3i;
        interface->fUniform3fv = glUniform3fv;
        interface->fUniform3iv = glUniform3iv;
        interface->fUniform4f = glUniform4f;
        interface->fUniform4i = glUniform4i;
        interface->fUniform4fv = glUniform4fv;
        interface->fUniform4iv = glUniform4iv;
        interface->fUniform4fv = glUniform4fv;
        interface->fUniformMatrix2fv = glUniformMatrix2fv;
        interface->fUniformMatrix3fv = glUniformMatrix3fv;
        interface->fUniformMatrix4fv = glUniformMatrix4fv;
        interface->fUnmapBuffer = glUnmapBuffer;
        interface->fUseProgram = glUseProgram;
        interface->fVertexAttrib4fv = glVertexAttrib4fv;
        interface->fVertexAttribPointer = glVertexAttribPointer;
        interface->fViewport = glViewport;

        if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_timer_query", extStr)) {
            // ARB extension doesn't use the ARB suffix on the function name
            #if GL_ARB_timer_query || GL_VERSION_3_3
                interface->fQueryCounter = glQueryCounter;
                interface->fGetQueryObjecti64v = glGetQueryObjecti64v;
                interface->fGetQueryObjectui64v = glGetQueryObjectui64v;
            #else
                interface->fQueryCounter = GET_PROC(QueryCounter);
                interface->fGetQueryObjecti64v = GET_PROC(GetQueryObjecti64v);
                interface->fGetQueryObjectui64v = GET_PROC(GetQueryObjectui64v);
            #endif
        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extStr)) {
            #if GL_EXT_timer_query
                interface->fGetQueryObjecti64v = glGetQueryObjecti64vEXT;
                interface->fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
            #else
                interface->fGetQueryObjecti64v = GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
                interface->fGetQueryObjectui64v = GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
            #endif
        }

        if (ver >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extStr)) {
            // ARB extension doesn't use the ARB suffix on the function names
            #if GL_VERSION_3_0 || GL_ARB_framebuffer_object
                interface->fGenFramebuffers = glGenFramebuffers;
                interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
                interface->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
                interface->fBindFramebuffer = glBindFramebuffer;
                interface->fFramebufferTexture2D = glFramebufferTexture2D;
                interface->fCheckFramebufferStatus = glCheckFramebufferStatus;
                interface->fDeleteFramebuffers = glDeleteFramebuffers;
                interface->fRenderbufferStorage = glRenderbufferStorage;
                interface->fGenRenderbuffers = glGenRenderbuffers;
                interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
                interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
                interface->fBindRenderbuffer = glBindRenderbuffer;
                interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisample;
                interface->fBlitFramebuffer = glBlitFramebuffer;
            #else
                interface->fGenFramebuffers = GET_PROC(GenFramebuffers);
                interface->fGetFramebufferAttachmentParameteriv = GET_PROC(GetFramebufferAttachmentParameteriv);
                interface->fGetRenderbufferParameteriv = GET_PROC(GetRenderbufferParameteriv);
                interface->fBindFramebuffer = GET_PROC(BindFramebuffer);
                interface->fFramebufferTexture2D = GET_PROC(FramebufferTexture2D);
                interface->fCheckFramebufferStatus = GET_PROC(CheckFramebufferStatus);
                interface->fDeleteFramebuffers = GET_PROC(DeleteFramebuffers);
                interface->fRenderbufferStorage = GET_PROC(RenderbufferStorage);
                interface->fGenRenderbuffers = GET_PROC(GenRenderbuffers);
                interface->fDeleteRenderbuffers = GET_PROC(DeleteRenderbuffers);
                interface->fFramebufferRenderbuffer = GET_PROC(FramebufferRenderbuffer);
                interface->fBindRenderbuffer = GET_PROC(BindRenderbuffer);
                interface->fRenderbufferStorageMultisample = GET_PROC(RenderbufferStorageMultisample);
                interface->fBlitFramebuffer = GET_PROC(BlitFramebuffer);
            #endif
        } else {
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object", extStr)) {
                #if GL_EXT_framebuffer_object
                    interface->fGenFramebuffers = glGenFramebuffersEXT;
                    interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT;
                    interface->fGetRenderbufferParameteriv = glGetRenderbufferParameterivEXT;
                    interface->fBindFramebuffer = glBindFramebufferEXT;
                    interface->fFramebufferTexture2D = glFramebufferTexture2DEXT;
                    interface->fCheckFramebufferStatus = glCheckFramebufferStatusEXT;
                    interface->fDeleteFramebuffers = glDeleteFramebuffersEXT;
                    interface->fRenderbufferStorage = glRenderbufferStorageEXT;
                    interface->fGenRenderbuffers = glGenRenderbuffersEXT;
                    interface->fDeleteRenderbuffers = glDeleteRenderbuffersEXT;
                    interface->fFramebufferRenderbuffer = glFramebufferRenderbufferEXT;
                    interface->fBindRenderbuffer = glBindRenderbufferEXT;
                #else
                    interface->fGenFramebuffers = GET_PROC_SUFFIX(GenFramebuffers, EXT);
                    interface->fGetFramebufferAttachmentParameteriv = GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
                    interface->fGetRenderbufferParameteriv = GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
                    interface->fBindFramebuffer = GET_PROC_SUFFIX(BindFramebuffer, EXT);
                    interface->fFramebufferTexture2D = GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
                    interface->fCheckFramebufferStatus = GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
                    interface->fDeleteFramebuffers = GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
                    interface->fRenderbufferStorage = GET_PROC_SUFFIX(RenderbufferStorage, EXT);
                    interface->fGenRenderbuffers = GET_PROC_SUFFIX(GenRenderbuffers, EXT);
                    interface->fDeleteRenderbuffers = GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
                    interface->fFramebufferRenderbuffer = GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
                    interface->fBindRenderbuffer = GET_PROC_SUFFIX(BindRenderbuffer, EXT);
                #endif
            }
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extStr)) {
                #if GL_EXT_framebuffer_multisample
                    interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
                #else
                    interface->fRenderbufferStorageMultisample = GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
                #endif
            }
            if (GrGLHasExtensionFromString("", extStr)) {
                #if GL_EXT_framebuffer_blit
                    interface->fBlitFramebuffer = glBlitFramebufferEXT;
                #else
                    interface->fBlitFramebuffer = GET_PROC_SUFFIX(BlitFramebuffer, EXT);
                #endif
            }
        }
        if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_blend_func_extended", extStr)) {
            // ARB extension doesn't use the ARB suffix on the function name
            #if GL_VERSION_3_3 || GL_ARB_blend_func_extended
                interface->fBindFragDataLocationIndexed = glBindFragDataLocationIndexed;
            #else
                interface->fBindFragDataLocationIndexed = GET_PROC(BindFragDataLocationIndexed);
            #endif
        }

        interface->fBindingsExported = kDesktop_GrGLBinding;
    }
    glInterface.get()->ref();
    return glInterface.get();
}
<commit_msg>Fix Mac build<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLInterface.h"

#include <OpenGL/gl.h>
#include <OpenGL/glext.h>

#include <mach-o/dyld.h>

// This uses deprecated functions, should rewrite using dlopen, dlsym, dlclose
void* GetProcAddress(const char* name) {
    NSSymbol symbol = NULL;
    if (NSIsSymbolNameDefined(name)) {
        symbol = NSLookupAndBindSymbol(name);
    }
    return NULL == symbol ? NULL : NSAddressOfSymbol(symbol);
}

#define GET_PROC(name) ((GrGL ## name ## Proc) GetProcAddress("_gl" #name))
#define GET_PROC_SUFFIX(name, suffix) ((GrGL ## name ## Proc) GetProcAddress("_gl" #name #suffix))

const GrGLInterface* GrGLCreateNativeInterface() {
    // The gl functions are not context-specific so we create one global
    // interface
    static SkAutoTUnref<GrGLInterface> glInterface;
    if (!glInterface.get()) {
        GrGLInterface* interface = new GrGLInterface;
        glInterface.reset(interface);
        const char* verStr = (const char*) glGetString(GL_VERSION);
        GrGLVersion ver = GrGLGetVersionFromString(verStr);
        const char* extStr = (const char*) glGetString(GL_EXTENSIONS);

        interface->fBindingsExported = kDesktop_GrGLBinding;
        interface->fActiveTexture = glActiveTexture;
        interface->fAttachShader = glAttachShader;
        interface->fBeginQuery = glBeginQuery;
        interface->fBindAttribLocation = glBindAttribLocation;
        interface->fBindBuffer = glBindBuffer;
        if (ver >= GR_GL_VER(3,0)) {
            #if GL_VERSION_3_0
                interface->fBindFragDataLocation = glBindFragDataLocation;
            #else
                interface->fBindFragDataLocation = GET_PROC(BindFragDataLocation);
            #endif
        }
        interface->fBindTexture = glBindTexture;
        interface->fBlendColor = glBlendColor;
        interface->fBlendFunc = glBlendFunc;
        interface->fBufferData = glBufferData;
        interface->fBufferSubData = glBufferSubData;
        interface->fClear = glClear;
        interface->fClearColor = glClearColor;
        interface->fClearStencil = glClearStencil;
        interface->fColorMask = glColorMask;
        interface->fColorPointer = glColorPointer;
        interface->fCompileShader = glCompileShader;
        interface->fCompressedTexImage2D = glCompressedTexImage2D;
        interface->fCreateProgram = glCreateProgram;
        interface->fCreateShader = glCreateShader;
        interface->fCullFace = glCullFace;
        interface->fDeleteBuffers = glDeleteBuffers;
        interface->fDeleteProgram = glDeleteProgram;
        interface->fDeleteQueries = glDeleteQueries;
        interface->fDeleteShader = glDeleteShader;
        interface->fDeleteTextures = glDeleteTextures;
        interface->fDepthMask = glDepthMask;
        interface->fDisable = glDisable;
        interface->fDisableVertexAttribArray =
                                            glDisableVertexAttribArray;
        interface->fDrawArrays = glDrawArrays;
        interface->fDrawBuffer = glDrawBuffer;
        interface->fDrawBuffers = glDrawBuffers;
        interface->fDrawElements = glDrawElements;
        interface->fEnable = glEnable;
        interface->fEnableVertexAttribArray = glEnableVertexAttribArray;
        interface->fEndQuery = glEndQuery;
        interface->fFinish = glFinish;
        interface->fFlush = glFlush;
        interface->fFrontFace = glFrontFace;
        interface->fGenBuffers = glGenBuffers;
        interface->fGenQueries = glGenQueries;
        interface->fGetBufferParameteriv = glGetBufferParameteriv;
        interface->fGetError = glGetError;
        interface->fGetIntegerv = glGetIntegerv;
        interface->fGetProgramInfoLog = glGetProgramInfoLog;
        interface->fGetProgramiv = glGetProgramiv;
        interface->fGetQueryiv = glGetQueryiv;
        interface->fGetQueryObjectiv = glGetQueryObjectiv;
        interface->fGetQueryObjectuiv = glGetQueryObjectuiv;
        interface->fGetShaderInfoLog = glGetShaderInfoLog;
        interface->fGetShaderiv = glGetShaderiv;
        interface->fGetString = glGetString;
        interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
        interface->fGenTextures = glGenTextures;
        interface->fGetUniformLocation = glGetUniformLocation;
        interface->fLineWidth = glLineWidth;
        interface->fLinkProgram = glLinkProgram;
        interface->fMapBuffer = glMapBuffer;
        interface->fPixelStorei = glPixelStorei;
        interface->fReadBuffer = glReadBuffer;
        interface->fReadPixels = glReadPixels;
        interface->fScissor = glScissor;
        interface->fShaderSource = glShaderSource;
        interface->fStencilFunc = glStencilFunc;
        interface->fStencilFuncSeparate = glStencilFuncSeparate;
        interface->fStencilMask = glStencilMask;
        interface->fStencilMaskSeparate = glStencilMaskSeparate;
        interface->fStencilOp = glStencilOp;
        interface->fStencilOpSeparate = glStencilOpSeparate;
        // mac uses GLenum for internalFormat param (non-standard)
        // amounts to int vs. uint.
        interface->fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
        interface->fTexParameteri = glTexParameteri;
    #if GL_ARB_texture_storage || GL_VERSION_4_2
        interface->fTexStorage2D = glTexStorage2D
    #elif GL_EXT_texture_storage
        interface->fTexStorage2D = glTexStorage2DEXT;
    #else
        if (ver >= GR_GL_VER(4,2) ||
            GrGLHasExtensionFromString("GL_ARB_texture_storage", extStr)) {
            GET_PROC(TexStorage2D);
        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extStr)) {
            GET_PROC_SUFFIX(TexStorage2D, EXT);
        }
    #endif
        interface->fTexSubImage2D = glTexSubImage2D;
        interface->fUniform1f = glUniform1f;
        interface->fUniform1i = glUniform1i;
        interface->fUniform1fv = glUniform1fv;
        interface->fUniform1iv = glUniform1iv;
        interface->fUniform2f = glUniform2f;
        interface->fUniform2i = glUniform2i;
        interface->fUniform2fv = glUniform2fv;
        interface->fUniform2iv = glUniform2iv;
        interface->fUniform3f = glUniform3f;
        interface->fUniform3i = glUniform3i;
        interface->fUniform3fv = glUniform3fv;
        interface->fUniform3iv = glUniform3iv;
        interface->fUniform4f = glUniform4f;
        interface->fUniform4i = glUniform4i;
        interface->fUniform4fv = glUniform4fv;
        interface->fUniform4iv = glUniform4iv;
        interface->fUniform4fv = glUniform4fv;
        interface->fUniformMatrix2fv = glUniformMatrix2fv;
        interface->fUniformMatrix3fv = glUniformMatrix3fv;
        interface->fUniformMatrix4fv = glUniformMatrix4fv;
        interface->fUnmapBuffer = glUnmapBuffer;
        interface->fUseProgram = glUseProgram;
        interface->fVertexAttrib4fv = glVertexAttrib4fv;
        interface->fVertexAttribPointer = glVertexAttribPointer;
        interface->fViewport = glViewport;

        if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_timer_query", extStr)) {
            // ARB extension doesn't use the ARB suffix on the function name
            #if GL_ARB_timer_query || GL_VERSION_3_3
                interface->fQueryCounter = glQueryCounter;
                interface->fGetQueryObjecti64v = glGetQueryObjecti64v;
                interface->fGetQueryObjectui64v = glGetQueryObjectui64v;
            #else
                interface->fQueryCounter = GET_PROC(QueryCounter);
                interface->fGetQueryObjecti64v = GET_PROC(GetQueryObjecti64v);
                interface->fGetQueryObjectui64v = GET_PROC(GetQueryObjectui64v);
            #endif
        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extStr)) {
            #if GL_EXT_timer_query
                interface->fGetQueryObjecti64v = glGetQueryObjecti64vEXT;
                interface->fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
            #else
                interface->fGetQueryObjecti64v = GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
                interface->fGetQueryObjectui64v = GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
            #endif
        }

        if (ver >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extStr)) {
            // ARB extension doesn't use the ARB suffix on the function names
            #if GL_VERSION_3_0 || GL_ARB_framebuffer_object
                interface->fGenFramebuffers = glGenFramebuffers;
                interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
                interface->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
                interface->fBindFramebuffer = glBindFramebuffer;
                interface->fFramebufferTexture2D = glFramebufferTexture2D;
                interface->fCheckFramebufferStatus = glCheckFramebufferStatus;
                interface->fDeleteFramebuffers = glDeleteFramebuffers;
                interface->fRenderbufferStorage = glRenderbufferStorage;
                interface->fGenRenderbuffers = glGenRenderbuffers;
                interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
                interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
                interface->fBindRenderbuffer = glBindRenderbuffer;
                interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisample;
                interface->fBlitFramebuffer = glBlitFramebuffer;
            #else
                interface->fGenFramebuffers = GET_PROC(GenFramebuffers);
                interface->fGetFramebufferAttachmentParameteriv = GET_PROC(GetFramebufferAttachmentParameteriv);
                interface->fGetRenderbufferParameteriv = GET_PROC(GetRenderbufferParameteriv);
                interface->fBindFramebuffer = GET_PROC(BindFramebuffer);
                interface->fFramebufferTexture2D = GET_PROC(FramebufferTexture2D);
                interface->fCheckFramebufferStatus = GET_PROC(CheckFramebufferStatus);
                interface->fDeleteFramebuffers = GET_PROC(DeleteFramebuffers);
                interface->fRenderbufferStorage = GET_PROC(RenderbufferStorage);
                interface->fGenRenderbuffers = GET_PROC(GenRenderbuffers);
                interface->fDeleteRenderbuffers = GET_PROC(DeleteRenderbuffers);
                interface->fFramebufferRenderbuffer = GET_PROC(FramebufferRenderbuffer);
                interface->fBindRenderbuffer = GET_PROC(BindRenderbuffer);
                interface->fRenderbufferStorageMultisample = GET_PROC(RenderbufferStorageMultisample);
                interface->fBlitFramebuffer = GET_PROC(BlitFramebuffer);
            #endif
        } else {
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object", extStr)) {
                #if GL_EXT_framebuffer_object
                    interface->fGenFramebuffers = glGenFramebuffersEXT;
                    interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT;
                    interface->fGetRenderbufferParameteriv = glGetRenderbufferParameterivEXT;
                    interface->fBindFramebuffer = glBindFramebufferEXT;
                    interface->fFramebufferTexture2D = glFramebufferTexture2DEXT;
                    interface->fCheckFramebufferStatus = glCheckFramebufferStatusEXT;
                    interface->fDeleteFramebuffers = glDeleteFramebuffersEXT;
                    interface->fRenderbufferStorage = glRenderbufferStorageEXT;
                    interface->fGenRenderbuffers = glGenRenderbuffersEXT;
                    interface->fDeleteRenderbuffers = glDeleteRenderbuffersEXT;
                    interface->fFramebufferRenderbuffer = glFramebufferRenderbufferEXT;
                    interface->fBindRenderbuffer = glBindRenderbufferEXT;
                #else
                    interface->fGenFramebuffers = GET_PROC_SUFFIX(GenFramebuffers, EXT);
                    interface->fGetFramebufferAttachmentParameteriv = GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
                    interface->fGetRenderbufferParameteriv = GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
                    interface->fBindFramebuffer = GET_PROC_SUFFIX(BindFramebuffer, EXT);
                    interface->fFramebufferTexture2D = GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
                    interface->fCheckFramebufferStatus = GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
                    interface->fDeleteFramebuffers = GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
                    interface->fRenderbufferStorage = GET_PROC_SUFFIX(RenderbufferStorage, EXT);
                    interface->fGenRenderbuffers = GET_PROC_SUFFIX(GenRenderbuffers, EXT);
                    interface->fDeleteRenderbuffers = GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
                    interface->fFramebufferRenderbuffer = GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
                    interface->fBindRenderbuffer = GET_PROC_SUFFIX(BindRenderbuffer, EXT);
                #endif
            }
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extStr)) {
                #if GL_EXT_framebuffer_multisample
                    interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
                #else
                    interface->fRenderbufferStorageMultisample = GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
                #endif
            }
            if (GrGLHasExtensionFromString("", extStr)) {
                #if GL_EXT_framebuffer_blit
                    interface->fBlitFramebuffer = glBlitFramebufferEXT;
                #else
                    interface->fBlitFramebuffer = GET_PROC_SUFFIX(BlitFramebuffer, EXT);
                #endif
            }
        }
        if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_blend_func_extended", extStr)) {
            // ARB extension doesn't use the ARB suffix on the function name
            #if GL_VERSION_3_3 || GL_ARB_blend_func_extended
                interface->fBindFragDataLocationIndexed = glBindFragDataLocationIndexed;
            #else
                interface->fBindFragDataLocationIndexed = GET_PROC(BindFragDataLocationIndexed);
            #endif
        }

        interface->fBindingsExported = kDesktop_GrGLBinding;
    }
    glInterface.get()->ref();
    return glInterface.get();
}
<|endoftext|>


<commit_before>#include <QCoreApplication>
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QStringBuilder>
#include <QVector>
#include <functional>

#include "request.hpp"
#include "response.hpp"
#include "context.hpp"

//!
//! \brief The HttpServer class
//! Http (unsecure) server class
//!
class HttpServer : public QObject
{
    Q_OBJECT

public:
    HttpServer(QObject *parent = NULL);
    ~HttpServer();

    bool compose(quint64 port, QHostAddress address = QHostAddress::Any);

private:
    QTcpServer m_tcp_server;
    quint64 m_port;
    QHostAddress m_address;
    QObject *m_parent;

signals:
    void socketReady(QTcpSocket *socket);
};

inline HttpServer::HttpServer(QObject *parent)
{
    m_parent = parent;
};

inline HttpServer::~HttpServer()
{

};

inline bool HttpServer::compose(quint64 port, QHostAddress address)
{
    m_port = port;
    m_address = address;

    if (!m_tcp_server.listen(address, port)) {
        qDebug() << "failed to start listening";
        return false;
    }

    connect(&m_tcp_server, &QTcpServer::newConnection, [this] {
        qDebug() << "client connected";
        QTcpSocket *socket = m_tcp_server.nextPendingConnection();

        if (socket == 0) {
            qDebug() << "no connection?";
            delete socket;
            return;
        }

        emit socketReady(socket);
    });

    return true;
};

//!
//! \brief The Recurse class
//! main class of the app
//!
class Recurse : public QObject
{
    Q_OBJECT

    using void_f = std::function<void()>;
    using void_ff = std::function<void(void_f prev)>;
    using next_prev_f = std::function<void(Context &ctx, void_ff next, void_f prev)>;
    using next_f = std::function<void(Context &ctx, void_f next)>;
    using final_f =  std::function<void(Context &ctx)>;

public:
    Recurse(int & argc, char ** argv, QObject *parent = NULL);
    ~Recurse();

    bool listen(quint64 port, QHostAddress address = QHostAddress::Any);
    bool listen(HttpServer *server);

    void use(next_f next);
    void use(next_prev_f next);

    void use(QVector<next_f> nexts);
    void use(QVector<next_prev_f> nexts);

    void use(final_f next);

public slots:
    bool handleConnection(QTcpSocket *socket);

private:
    QCoreApplication app;
    HttpServer *http;

    QVector<next_prev_f> m_middleware_next;

    void m_end(QVector<void_f> *middleware_prev);
    void m_send(Context *ctx);
    void m_next(void_f prev, Context *ctx, int current_middleware, QVector<void_f> *middleware_prev);
};

inline Recurse::Recurse(int & argc, char ** argv, QObject *parent) : app(argc, argv)
{
    Q_UNUSED(parent);
};

inline Recurse::~Recurse()
{
    delete http;
};

//!
//! \brief Recurse::handleConnection
//! creates new recurse context for a tcp session
//!
//! \return true on success
//!
inline bool Recurse::handleConnection(QTcpSocket *socket)
{
    qDebug() << "handling new connection";

    auto middleware_prev = new QVector<void_f>;
    auto ctx = new Context;
    ctx->request.socket = socket;

    connect(socket, &QTcpSocket::readyRead, [this, ctx, middleware_prev] {
        QString data(ctx->request.socket->readAll());

        ctx->request.parse(data);

        if (ctx->request.length < ctx->request.get("content-length").toLongLong()) {
            return;
        }

        qDebug() << ctx->request.body;

        /*
        if (m_middleware_next.count() > 0) {
            ctx->response.end = std::bind(&Recurse::m_end, this, middleware_prev);

            m_middleware_next[0](
                *ctx,
                std::bind(&Recurse::m_next, this, std::placeholders::_1, ctx, 0, middleware_prev),
                std::bind(&Recurse::m_send, this, ctx));
        }
        */

    });

    return true;
};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! \param port tcp server port
//! \param address tcp server listening address
//!
//! \return true on success
//!
inline bool Recurse::listen(quint64 port, QHostAddress address)
{
    // set HttpServer instance, send reference to this object and prepare http connection
    http = new HttpServer(this);
    http->compose(port, address);

    // connect HttpServer signal 'socketReady' to this class' 'handleConnection' slot
    connect(http, &HttpServer::socketReady, this, &Recurse::handleConnection);
    return app.exec();
};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! overloaded function
//!
//! \param server pointer to the HttpServer instance
//!
//! \return true on success
//!
inline bool Recurse::listen(HttpServer *server)
{
    http = server;

    // connect HttpServer signal 'socketReady' to this class' 'handleConnection' slot
    connect(http, &HttpServer::socketReady, this, &Recurse::handleConnection);
    return app.exec();
};

<commit_msg>add https server skeleton; move app.exec to a private startEventLoop function<commit_after>#include <QCoreApplication>
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QStringBuilder>
#include <QVector>
#include <functional>

#include "request.hpp"
#include "response.hpp"
#include "context.hpp"

//!
//! \brief The HttpServer class
//! Http (unsecure) server class
//!
class HttpServer : public QObject
{
    Q_OBJECT

public:
    HttpServer(QObject *parent = NULL);
    ~HttpServer();

    bool compose(quint64 port, QHostAddress address = QHostAddress::Any);

private:
    QTcpServer m_tcp_server;
    quint64 m_port;
    QHostAddress m_address;
    QObject *m_parent;

signals:
    void socketReady(QTcpSocket *socket);
};

inline HttpServer::HttpServer(QObject *parent)
{
    m_parent = parent;
};

inline HttpServer::~HttpServer()
{

};

inline bool HttpServer::compose(quint64 port, QHostAddress address)
{
    m_port = port;
    m_address = address;

    if (!m_tcp_server.listen(address, port)) {
        qDebug() << "failed to start listening";
        return false;
    }

    connect(&m_tcp_server, &QTcpServer::newConnection, [this] {
        qDebug() << "client connected";
        QTcpSocket *socket = m_tcp_server.nextPendingConnection();

        if (socket == 0) {
            qDebug() << "no connection?";
            delete socket;
            return;
        }

        emit socketReady(socket);
    });

    return true;
};

//!
//! \brief The HttpsServer class
//! Https (secure) server class
//!
class HttpsServer : public QObject
{
    Q_OBJECT

public:
    HttpsServer(QObject *parent = NULL);
    ~HttpsServer();

    bool compose(quint64 port, QHostAddress address = QHostAddress::Any);

private:
    QTcpServer m_tcp_server;
    quint64 m_port;
    QHostAddress m_address;
    QObject *m_parent;

signals:
    void socketReady(QTcpSocket *socket);
};

inline HttpsServer::HttpsServer(QObject *parent)
{
    m_parent = parent;
};

inline HttpsServer::~HttpsServer()
{

};

inline bool HttpsServer::compose(quint64 port, QHostAddress address)
{
    m_port = port;
    m_address = address;

    return true;
};

//!
//! \brief The Recurse class
//! main class of the app
//!
class Recurse : public QObject
{
    Q_OBJECT

    using void_f = std::function<void()>;
    using void_ff = std::function<void(void_f prev)>;
    using next_prev_f = std::function<void(Context &ctx, void_ff next, void_f prev)>;
    using next_f = std::function<void(Context &ctx, void_f next)>;
    using final_f =  std::function<void(Context &ctx)>;

public:
    Recurse(int & argc, char ** argv, QObject *parent = NULL);
    ~Recurse();

    bool listen(quint64 port, QHostAddress address = QHostAddress::Any);
    bool listen(HttpServer *server);
    bool listen(HttpsServer *server);

    void use(next_f next);
    void use(next_prev_f next);

    void use(QVector<next_f> nexts);
    void use(QVector<next_prev_f> nexts);

    void use(final_f next);

public slots:
    bool handleConnection(QTcpSocket *socket);

private:
    QCoreApplication app;
    HttpServer *http;
    HttpsServer *https;

    QVector<next_prev_f> m_middleware_next;

    void m_end(QVector<void_f> *middleware_prev);
    void m_send(Context *ctx);
    void m_next(void_f prev, Context *ctx, int current_middleware, QVector<void_f> *middleware_prev);
    bool startEventLoop();
};

inline Recurse::Recurse(int & argc, char ** argv, QObject *parent) : app(argc, argv)
{
    Q_UNUSED(parent);
};

inline Recurse::~Recurse()
{
    delete http;
};

inline bool Recurse::startEventLoop()
{
    return app.exec();
};

//!
//! \brief Recurse::handleConnection
//! creates new recurse context for a tcp session
//!
//! \return true on success
//!
inline bool Recurse::handleConnection(QTcpSocket *socket)
{
    qDebug() << "handling new connection";

    auto middleware_prev = new QVector<void_f>;
    auto ctx = new Context;
    ctx->request.socket = socket;

    connect(socket, &QTcpSocket::readyRead, [this, ctx, middleware_prev] {
        QString data(ctx->request.socket->readAll());

        ctx->request.parse(data);

        if (ctx->request.length < ctx->request.get("content-length").toLongLong()) {
            return;
        }

        qDebug() << ctx->request.body;

        /*
        if (m_middleware_next.count() > 0) {
            ctx->response.end = std::bind(&Recurse::m_end, this, middleware_prev);

            m_middleware_next[0](
                *ctx,
                std::bind(&Recurse::m_next, this, std::placeholders::_1, ctx, 0, middleware_prev),
                std::bind(&Recurse::m_send, this, ctx));
        }
        */

    });

    return true;
};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! \param port tcp server port
//! \param address tcp server listening address
//!
//! \return true on success
//!
inline bool Recurse::listen(quint64 port, QHostAddress address)
{
    // set HttpServer instance, send reference to this object and prepare http connection
    http = new HttpServer(this);
    http->compose(port, address);

    // connect HttpServer signal 'socketReady' to this class' 'handleConnection' slot
    connect(http, &HttpServer::socketReady, this, &Recurse::handleConnection);
    return startEventLoop();
};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! overloaded function
//!
//! \param server pointer to the HttpServer instance
//!
//! \return true on success
//!
inline bool Recurse::listen(HttpServer *server)
{
    http = server;

    // connect HttpServer signal 'socketReady' to this class' 'handleConnection' slot
    connect(http, &HttpServer::socketReady, this, &Recurse::handleConnection);
    return startEventLoop();
};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! overloaded function
//!
//! \param server pointer to the HttpServer instance
//!
//! \return true on success
//!
inline bool Recurse::listen(HttpsServer *server)
{
    https = server;

    // connect HttpServer signal 'socketReady' to this class' 'handleConnection' slot
    // connect(http, &HttpServer::socketReady, this, &Recurse::handleConnection);
    return startEventLoop();
};

<|endoftext|>


<commit_before>// Copyright 2016-2017 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <cmath>
#include <cstddef>
#include <gmp.h>
#include <limits>
#include <random>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>

#include <mp++/mp++.hpp>

#include "test_utils.hpp"

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

static int ntries = 1000;

using namespace mppp;
using namespace mppp_test;

using sizes = std::tuple<std::integral_constant<std::size_t, 1>, std::integral_constant<std::size_t, 2>,
                         std::integral_constant<std::size_t, 3>, std::integral_constant<std::size_t, 6>,
                         std::integral_constant<std::size_t, 10>>;

static std::mt19937 rng;

template <typename T, typename U>
using pow_t = decltype(pow(std::declval<const T &>(), std::declval<const U &>()));

template <typename T, typename U>
using has_pow = is_detected<pow_t, T, U>;

static inline void mpq_pow(::mpq_t rop, const ::mpq_t base, long exp)
{
    if (exp >= 0) {
        ::mpz_pow_ui(mpq_numref(rop), mpq_numref(base), static_cast<unsigned long>(exp));
        ::mpz_pow_ui(mpq_denref(rop), mpq_denref(base), static_cast<unsigned long>(exp));
    } else {
        ::mpz_pow_ui(mpq_numref(rop), mpq_denref(base), static_cast<unsigned long>(-exp));
        ::mpz_pow_ui(mpq_denref(rop), mpq_numref(base), static_cast<unsigned long>(-exp));
        if (mpz_sgn(mpq_denref(rop)) < 0) {
            ::mpz_neg(mpq_numref(rop), mpq_numref(rop));
            ::mpz_neg(mpq_denref(rop), mpq_denref(rop));
        }
    }
}

struct pow_tester {
    template <typename S>
    inline void operator()(const S &) const
    {
        using rational = rational<S::value>;
        using integer = typename rational::int_t;
        REQUIRE((has_pow<rational, rational>::value));
        REQUIRE((has_pow<rational, integer>::value));
        REQUIRE((has_pow<rational, int>::value));
        REQUIRE((has_pow<rational, char>::value));
        REQUIRE((has_pow<rational, unsigned>::value));
        REQUIRE((has_pow<rational, double>::value));
        REQUIRE((has_pow<integer, rational>::value));
        REQUIRE((has_pow<int, rational>::value));
        REQUIRE((has_pow<char, rational>::value));
        REQUIRE((has_pow<unsigned, rational>::value));
        REQUIRE((has_pow<float, rational>::value));
        REQUIRE((!has_pow<std::string, rational>::value));
        REQUIRE((!has_pow<rational, std::string>::value));
        // Start with all zeroes.
        mpq_raii m1, m2;
        rational n1, n2, ret;
        REQUIRE((std::is_same<rational, decltype(pow(n1, n2))>::value));
        ret = pow(n1, n2);
        ::mpq_pow(&m1.m_mpq, &m2.m_mpq, 0);
        REQUIRE((lex_cast(ret) == lex_cast(m1)));
        REQUIRE(ret.get_num().is_static());
        REQUIRE(ret.get_den().is_static());
        mpq_raii tmp;
        std::uniform_int_distribution<int> sdist(0, 1);
        std::uniform_int_distribution<long> edist(-20, 20);
        // Run a variety of tests with operands with x number of limbs.
        auto random_xy = [&](unsigned x) {
            for (int i = 0; i < ntries; ++i) {
                random_rational(tmp, x, rng);
                ::mpq_set(&m2.m_mpq, &tmp.m_mpq);
                n2 = rational(&tmp.m_mpq);
                if (sdist(rng)) {
                    ::mpq_neg(&m2.m_mpq, &m2.m_mpq);
                    n2.neg();
                }
                if (n2.get_num().is_static() && sdist(rng)) {
                    // Promote sometimes, if possible.
                    n2._get_num().promote();
                }
                if (n2.get_den().is_static() && sdist(rng)) {
                    // Promote sometimes, if possible.
                    n2._get_den().promote();
                }
                const auto ex = edist(rng);
                if (mpq_sgn(&m2.m_mpq) == 0 && ex < 0) {
                    REQUIRE_THROWS_PREDICATE(pow(n2, ex), zero_division_error, [&ex](const zero_division_error &zde) {
                        return zde.what()
                               == "Cannot raise rational zero to the negative exponent " + std::to_string(ex);
                    });
                    continue;
                }
                ::mpq_pow(&m1.m_mpq, &m2.m_mpq, ex);
                n1 = pow(n2, ex);
                REQUIRE((lex_cast(n1) == lex_cast(m1)));
                REQUIRE((std::is_same<rational, decltype(pow(n1, ex))>::value));
                REQUIRE((std::is_same<rational, decltype(pow(n1, integer{ex}))>::value));
                REQUIRE((std::is_same<rational, decltype(pow(n1, rational{ex}))>::value));
                REQUIRE(n1 == pow(n2, integer{ex}));
                REQUIRE(n1 == pow(n2, rational{ex}));
                if (ex != 0 && ex != 1 && ex != -1 && !is_zero(n2) && !is_one(n2)) {
                    rational tmp_exp{integer{ex} + 1, ex};
                    REQUIRE_THROWS_PREDICATE(pow(n2, tmp_exp), std::domain_error, ([&](const std::domain_error &de) {
                                                 return de.what()
                                                        == "Cannot raise the rational base " + n2.to_string()
                                                               + " to the non-integral exponent " + tmp_exp.to_string();
                                             }));
                }
            }
        };

        random_xy(0);
        random_xy(1);
        random_xy(2);
        random_xy(3);
        random_xy(4);

        // Integral base, rational power.
        REQUIRE(pow(2, rational{2}) == rational{4});
        REQUIRE(pow(2, rational{-2}) == (rational{1, 4}));
        REQUIRE_THROWS_PREDICATE(
            pow(2, rational(1, 2)), std::domain_error, ([&](const std::domain_error &de) {
                return de.what() == std::string("Cannot raise the rational base 2 to the non-integral exponent 1/2");
            }));
        REQUIRE_THROWS_PREDICATE(
            pow(2ull, rational(-1, 2)), std::domain_error, ([&](const std::domain_error &de) {
                return de.what() == std::string("Cannot raise the rational base 2 to the non-integral exponent -1/2");
            }));
        REQUIRE((std::is_same<rational, decltype(pow(2, rational(1, 2)))>::value));
        REQUIRE((std::is_same<rational, decltype(pow(2ull, rational(1, 2)))>::value));

        // Some floating point tests.
        REQUIRE((std::is_same<float, decltype(pow(2.f, rational(1, 2)))>::value));
        REQUIRE((std::is_same<double, decltype(pow(rational(1, 2), 2.))>::value));
#if defined(MPPP_WITH_MPFR)
        REQUIRE((std::is_same<long double, decltype(pow(rational(1, 2), 2.l))>::value));
#endif
        REQUIRE(std::abs(pow(2.f, rational{1, 2}) - std::sqrt(2.f)) < 1E-8);
        REQUIRE(std::abs(pow(rational{2}, .5f) - std::sqrt(2.f)) < 1E-8);
        REQUIRE(std::abs(pow(2., rational{1, 2}) - std::sqrt(2.)) < 1E-8);
        REQUIRE(std::abs(pow(rational{2}, .5) - std::sqrt(2.)) < 1E-8);
#if defined(MPPP_WITH_MPFR)
        REQUIRE(std::abs(pow(2.l, rational{1, 2}) - std::sqrt(2.l)) < 1E-8);
        REQUIRE(std::abs(pow(rational{2}, .5l) - std::sqrt(2.l)) < 1E-8);
#endif
    }
};

TEST_CASE("pow")
{
    tuple_for_each(sizes{}, pow_tester{});
}
<commit_msg>Small test additions.<commit_after>// Copyright 2016-2017 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <cmath>
#include <cstddef>
#include <gmp.h>
#include <limits>
#include <random>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>

#include <mp++/mp++.hpp>

#include "test_utils.hpp"

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

static int ntries = 1000;

using namespace mppp;
using namespace mppp_test;

using sizes = std::tuple<std::integral_constant<std::size_t, 1>, std::integral_constant<std::size_t, 2>,
                         std::integral_constant<std::size_t, 3>, std::integral_constant<std::size_t, 6>,
                         std::integral_constant<std::size_t, 10>>;

static std::mt19937 rng;

template <typename T, typename U>
using pow_t = decltype(pow(std::declval<const T &>(), std::declval<const U &>()));

template <typename T, typename U>
using has_pow = is_detected<pow_t, T, U>;

static inline void mpq_pow(::mpq_t rop, const ::mpq_t base, long exp)
{
    if (exp >= 0) {
        ::mpz_pow_ui(mpq_numref(rop), mpq_numref(base), static_cast<unsigned long>(exp));
        ::mpz_pow_ui(mpq_denref(rop), mpq_denref(base), static_cast<unsigned long>(exp));
    } else {
        ::mpz_pow_ui(mpq_numref(rop), mpq_denref(base), static_cast<unsigned long>(-exp));
        ::mpz_pow_ui(mpq_denref(rop), mpq_numref(base), static_cast<unsigned long>(-exp));
        if (mpz_sgn(mpq_denref(rop)) < 0) {
            ::mpz_neg(mpq_numref(rop), mpq_numref(rop));
            ::mpz_neg(mpq_denref(rop), mpq_denref(rop));
        }
    }
}

struct pow_tester {
    template <typename S>
    inline void operator()(const S &) const
    {
        using rational = rational<S::value>;
        using integer = typename rational::int_t;
        REQUIRE((has_pow<rational, rational>::value));
        REQUIRE((has_pow<rational, integer>::value));
        REQUIRE((has_pow<rational, int>::value));
        REQUIRE((has_pow<rational, char>::value));
        REQUIRE((has_pow<rational, unsigned>::value));
        REQUIRE((has_pow<rational, double>::value));
        REQUIRE((has_pow<integer, rational>::value));
        REQUIRE((has_pow<int, rational>::value));
        REQUIRE((has_pow<char, rational>::value));
        REQUIRE((has_pow<unsigned, rational>::value));
        REQUIRE((has_pow<float, rational>::value));
        REQUIRE((!has_pow<std::string, rational>::value));
        REQUIRE((!has_pow<rational, std::string>::value));
        // Start with all zeroes.
        mpq_raii m1, m2;
        rational n1, n2, ret;
        REQUIRE((std::is_same<rational, decltype(pow(n1, n2))>::value));
        ret = pow(n1, n2);
        ::mpq_pow(&m1.m_mpq, &m2.m_mpq, 0);
        REQUIRE((lex_cast(ret) == lex_cast(m1)));
        REQUIRE(ret.get_num().is_static());
        REQUIRE(ret.get_den().is_static());
        mpq_raii tmp;
        std::uniform_int_distribution<int> sdist(0, 1);
        std::uniform_int_distribution<long> edist(-20, 20);
        // Run a variety of tests with operands with x number of limbs.
        auto random_xy = [&](unsigned x) {
            for (int i = 0; i < ntries; ++i) {
                random_rational(tmp, x, rng);
                ::mpq_set(&m2.m_mpq, &tmp.m_mpq);
                n2 = rational(&tmp.m_mpq);
                if (sdist(rng)) {
                    ::mpq_neg(&m2.m_mpq, &m2.m_mpq);
                    n2.neg();
                }
                if (n2.get_num().is_static() && sdist(rng)) {
                    // Promote sometimes, if possible.
                    n2._get_num().promote();
                }
                if (n2.get_den().is_static() && sdist(rng)) {
                    // Promote sometimes, if possible.
                    n2._get_den().promote();
                }
                const auto ex = edist(rng);
                if (mpq_sgn(&m2.m_mpq) == 0 && ex < 0) {
                    REQUIRE_THROWS_PREDICATE(pow(n2, ex), zero_division_error, [&ex](const zero_division_error &zde) {
                        return zde.what()
                               == "Cannot raise rational zero to the negative exponent " + std::to_string(ex);
                    });
                    continue;
                }
                ::mpq_pow(&m1.m_mpq, &m2.m_mpq, ex);
                n1 = pow(n2, ex);
                REQUIRE((lex_cast(n1) == lex_cast(m1)));
                REQUIRE((std::is_same<rational, decltype(pow(n1, ex))>::value));
                REQUIRE((std::is_same<rational, decltype(pow(n1, integer{ex}))>::value));
                REQUIRE((std::is_same<rational, decltype(pow(n1, rational{ex}))>::value));
                REQUIRE(n1 == pow(n2, integer{ex}));
                REQUIRE(n1 == pow(n2, rational{ex}));
                if (ex != 0 && ex != 1 && ex != -1 && !is_zero(n2) && !is_one(n2)) {
                    rational tmp_exp{integer{ex} + 1, ex};
                    REQUIRE_THROWS_PREDICATE(pow(n2, tmp_exp), std::domain_error, ([&](const std::domain_error &de) {
                                                 return de.what()
                                                        == "Cannot raise the rational base " + n2.to_string()
                                                               + " to the non-integral exponent " + tmp_exp.to_string();
                                             }));
                }
            }
        };

        random_xy(0);
        random_xy(1);
        random_xy(2);
        random_xy(3);
        random_xy(4);

        // Integral base, rational power.
        REQUIRE(pow(2, rational{2}) == rational{4});
        REQUIRE(pow(2, rational{-2}) == (rational{1, 4}));
        REQUIRE_THROWS_PREDICATE(
            pow(2, rational(1, 2)), std::domain_error, ([&](const std::domain_error &de) {
                return de.what() == std::string("Cannot raise the rational base 2 to the non-integral exponent 1/2");
            }));
        REQUIRE_THROWS_PREDICATE(
            pow(2ull, rational(-1, 2)), std::domain_error, ([&](const std::domain_error &de) {
                return de.what() == std::string("Cannot raise the rational base 2 to the non-integral exponent -1/2");
            }));
        REQUIRE((std::is_same<rational, decltype(pow(2, rational(1, 2)))>::value));
        REQUIRE((std::is_same<rational, decltype(pow(2ull, rational(1, 2)))>::value));

        // Some floating point tests.
        REQUIRE((std::is_same<float, decltype(pow(2.f, rational(1, 2)))>::value));
        REQUIRE((std::is_same<double, decltype(pow(rational(1, 2), 2.))>::value));
#if defined(MPPP_WITH_MPFR)
        REQUIRE((std::is_same<long double, decltype(pow(rational(1, 2), 2.l))>::value));
#endif
        REQUIRE(std::abs(pow(2.f, rational{1, 2}) - std::sqrt(2.f)) < 1E-8);
        REQUIRE(std::abs(pow(rational{2}, .5f) - std::sqrt(2.f)) < 1E-8);
        REQUIRE(std::abs(pow(2., rational{1, 2}) - std::sqrt(2.)) < 1E-8);
        REQUIRE(std::abs(pow(rational{2}, .5) - std::sqrt(2.)) < 1E-8);
#if defined(MPPP_WITH_MPFR)
        REQUIRE(std::abs(pow(2.l, rational{1, 2}) - std::sqrt(2.l)) < 1E-8);
        REQUIRE(std::abs(pow(rational{2}, .5l) - std::sqrt(2.l)) < 1E-8);
#endif

        // Some special casing with base 1.
        REQUIRE((pow(rational{1}, rational{1, 2}) == rational{1}));
        REQUIRE((pow(rational{1}, integer{-2}) == rational{1}));
        REQUIRE((pow(rational{1}, 2ull) == rational{1}));
        REQUIRE((pow(rational{1}, (signed char)(-1)) == rational{1}));
        REQUIRE((pow(1, rational{3, 4}) == rational{1}));
        REQUIRE((pow(1, rational{-3, 4}) == rational{1}));
    }
};

TEST_CASE("pow")
{
    tuple_for_each(sizes{}, pow_tester{});
}
<|endoftext|>


<commit_before>#pragma once
/*
** Author(s):
**  - Chris Kilner <ckilner@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/
#ifndef COMMON_MUTEXEDNAMELOOKUP_HPP_
#define COMMON_MUTEXEDNAMELOOKUP_HPP_

#include <map>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

namespace AL {
  namespace Common {

    template<typename T>
    class MutexedNameLookup {
    private:
      std::map<std::string, T> fMap;
      T fInvalidValue;
      boost::mutex fMutex;
    public:
      MutexedNameLookup() {};

      void replace(std::map<std::string, T>& other) {
        boost::mutex::scoped_lock lock(fMutex);
        fMap = other;
      }

      const std::map<std::string, T>& getMap() {
        boost::mutex::scoped_lock lock(fMutex);
        return fMap;
      }

      const T& get(std::string key) {
        boost::mutex::scoped_lock lock(fMutex);
        typename std::map<std::string, T>::const_iterator it = fMap.find(key);
        if (it != fMap.end()) {
          return it->second;
        }
        return fInvalidValue;
      }

      void insert(const std::string key, const T& val) {
        if (get(key).nodeName == "") {
          remove(key);
        }

        {
          boost::mutex::scoped_lock lock(fMutex);
          fMap.insert(make_pair(key, val));
        }
      }

      void remove(const std::string key) {
        boost::mutex::scoped_lock lock(fMutex);
        fMap.erase(key);
      }

    };
  }
}

#endif  // COMMON_MUTEXEDNAMELOOKUP_HPP_

<commit_msg>Fixed mutexednamelookup  ( removed nodeName )<commit_after>#pragma once
/*
** Author(s):
**  - Chris Kilner <ckilner@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/
#ifndef COMMON_MUTEXEDNAMELOOKUP_HPP_
#define COMMON_MUTEXEDNAMELOOKUP_HPP_

#include <map>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

namespace AL {
  namespace Common {

    template<typename T>
    class MutexedNameLookup {
    private:
      std::map<std::string, T> fMap;
      T fInvalidValue;
      boost::mutex fMutex;
    public:
      MutexedNameLookup() {};

      void replace(std::map<std::string, T>& other) {
        boost::mutex::scoped_lock lock(fMutex);
        fMap = other;
      }

      const std::map<std::string, T>& getMap() {
        boost::mutex::scoped_lock lock(fMutex);
        return fMap;
      }

      const T& get(std::string key) {
        boost::mutex::scoped_lock lock(fMutex);
        typename std::map<std::string, T>::const_iterator it = fMap.find(key);
        if (it != fMap.end()) {
          return it->second;
        }
        return fInvalidValue;
      }

      void insert(const std::string key, const T& val) {
        boost::mutex::scoped_lock lock(fMutex);
        typename std::map<std::string, T>::const_iterator it = fMap.find(key);
        if (it != fMap.end()) {
          fMap.erase(key);
        }
        fMap.insert(make_pair(key, val));
      }

      void remove(const std::string key) {
        boost::mutex::scoped_lock lock(fMutex);
        fMap.erase(key);
      }

    };
  }
}

#endif  // COMMON_MUTEXEDNAMELOOKUP_HPP_

<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "generic_merge.h"
#include <vespa/eval/eval/inline_operation.h>
#include <vespa/eval/eval/wrap_param.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/typify.h>
#include <cassert>
#include <typeindex>

using namespace vespalib::eval::tensor_function;

namespace vespalib::eval::instruction {

using State = InterpretedFunction::State;
using Instruction = InterpretedFunction::Instruction;

MergeParam::~MergeParam() = default;

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

template <typename LCT, typename RCT, typename OCT, typename Fun>
std::unique_ptr<Value>
generic_mixed_merge(const Value &a, const Value &b,
                    const MergeParam &params)
{
    Fun fun(params.function);
    auto lhs_cells = a.cells().typify<LCT>();
    auto rhs_cells = b.cells().typify<RCT>();
    const size_t num_mapped = params.num_mapped_dimensions;
    const size_t subspace_size = params.dense_subspace_size;
    size_t guess_subspaces = std::max(a.index().size(), b.index().size());
    auto builder = params.factory.create_transient_value_builder<OCT>(params.res_type, num_mapped, subspace_size, guess_subspaces);
    SmallVector<string_id> address(num_mapped);
    SmallVector<const string_id *> addr_cref;
    SmallVector<string_id *> addr_ref;
    for (auto & ref : address) {
        addr_cref.push_back(&ref);
        addr_ref.push_back(&ref);
    }
    size_t lhs_subspace;
    size_t rhs_subspace;
    auto inner = b.index().create_view(params.all_view_dims);
    auto outer = a.index().create_view({});
    outer->lookup({});
    while (outer->next_result(addr_ref, lhs_subspace)) {
        OCT *dst = builder->add_subspace(address).begin();
        inner->lookup(addr_cref);
        if (inner->next_result({}, rhs_subspace)) {
            const LCT *lhs_src = &lhs_cells[lhs_subspace * subspace_size];
            const RCT *rhs_src = &rhs_cells[rhs_subspace * subspace_size];
            for (size_t i = 0; i < subspace_size; ++i) {
                *dst++ = fun(*lhs_src++, *rhs_src++);
            }
        } else {
            const LCT *src = &lhs_cells[lhs_subspace * subspace_size];
            for (size_t i = 0; i < subspace_size; ++i) {
                *dst++ = *src++;
            }
        }
    }
    inner = a.index().create_view(params.all_view_dims);
    outer = b.index().create_view({});
    outer->lookup({});
    while (outer->next_result(addr_ref, rhs_subspace)) {
        inner->lookup(addr_cref);
        if (! inner->next_result({}, lhs_subspace)) {
            OCT *dst = builder->add_subspace(address).begin();
            const RCT *src = &rhs_cells[rhs_subspace * subspace_size];
            for (size_t i = 0; i < subspace_size; ++i) {
                *dst++ = *src++;
            }
        }
    }
    return builder->build(std::move(builder));
}

namespace {

template <typename LCT, typename RCT, typename OCT, typename Fun>
void my_mixed_merge_op(State &state, uint64_t param_in) {
    const auto &param = unwrap_param<MergeParam>(param_in);
    const Value &lhs = state.peek(1);
    const Value &rhs = state.peek(0);
    auto up = generic_mixed_merge<LCT, RCT, OCT, Fun>(lhs, rhs, param);
    auto &result = state.stash.create<std::unique_ptr<Value>>(std::move(up));
    const Value &result_ref = *(result.get());
    state.pop_pop_push(result_ref);
};

struct SelectGenericMergeOp {
    template <typename LCT, typename RCT, typename OCT, typename Fun> static auto invoke() {
        return my_mixed_merge_op<LCT,RCT,OCT,Fun>;
    }
};

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

} // namespace <unnamed>

using MergeTypify = TypifyValue<TypifyCellType,operation::TypifyOp2>;

Instruction
GenericMerge::make_instruction(const ValueType &result_type,
                               const ValueType &lhs_type, const ValueType &rhs_type, join_fun_t function,
                               const ValueBuilderFactory &factory, Stash &stash)
{
    const auto &param = stash.create<MergeParam>(result_type, lhs_type, rhs_type, function, factory);
    assert(result_type == ValueType::merge(lhs_type, rhs_type));
    auto fun = typify_invoke<4,MergeTypify,SelectGenericMergeOp>(lhs_type.cell_type(), rhs_type.cell_type(), param.res_type.cell_type(), function);
    return Instruction(fun, wrap_param<MergeParam>(param));
}

} // namespace
<commit_msg>use TypifyCellMeta in GenericMerge<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "generic_merge.h"
#include <vespa/eval/eval/inline_operation.h>
#include <vespa/eval/eval/wrap_param.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/typify.h>
#include <cassert>
#include <typeindex>

using namespace vespalib::eval::tensor_function;

namespace vespalib::eval::instruction {

using State = InterpretedFunction::State;
using Instruction = InterpretedFunction::Instruction;

MergeParam::~MergeParam() = default;

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

template <typename LCT, typename RCT, typename OCT, typename Fun>
std::unique_ptr<Value>
generic_mixed_merge(const Value &a, const Value &b,
                    const MergeParam &params)
{
    Fun fun(params.function);
    auto lhs_cells = a.cells().typify<LCT>();
    auto rhs_cells = b.cells().typify<RCT>();
    const size_t num_mapped = params.num_mapped_dimensions;
    const size_t subspace_size = params.dense_subspace_size;
    size_t guess_subspaces = std::max(a.index().size(), b.index().size());
    auto builder = params.factory.create_transient_value_builder<OCT>(params.res_type, num_mapped, subspace_size, guess_subspaces);
    SmallVector<string_id> address(num_mapped);
    SmallVector<const string_id *> addr_cref;
    SmallVector<string_id *> addr_ref;
    for (auto & ref : address) {
        addr_cref.push_back(&ref);
        addr_ref.push_back(&ref);
    }
    size_t lhs_subspace;
    size_t rhs_subspace;
    auto inner = b.index().create_view(params.all_view_dims);
    auto outer = a.index().create_view({});
    outer->lookup({});
    while (outer->next_result(addr_ref, lhs_subspace)) {
        OCT *dst = builder->add_subspace(address).begin();
        inner->lookup(addr_cref);
        if (inner->next_result({}, rhs_subspace)) {
            const LCT *lhs_src = &lhs_cells[lhs_subspace * subspace_size];
            const RCT *rhs_src = &rhs_cells[rhs_subspace * subspace_size];
            for (size_t i = 0; i < subspace_size; ++i) {
                *dst++ = fun(*lhs_src++, *rhs_src++);
            }
        } else {
            const LCT *src = &lhs_cells[lhs_subspace * subspace_size];
            for (size_t i = 0; i < subspace_size; ++i) {
                *dst++ = *src++;
            }
        }
    }
    inner = a.index().create_view(params.all_view_dims);
    outer = b.index().create_view({});
    outer->lookup({});
    while (outer->next_result(addr_ref, rhs_subspace)) {
        inner->lookup(addr_cref);
        if (! inner->next_result({}, lhs_subspace)) {
            OCT *dst = builder->add_subspace(address).begin();
            const RCT *src = &rhs_cells[rhs_subspace * subspace_size];
            for (size_t i = 0; i < subspace_size; ++i) {
                *dst++ = *src++;
            }
        }
    }
    return builder->build(std::move(builder));
}

namespace {

template <typename LCT, typename RCT, typename OCT, typename Fun>
void my_mixed_merge_op(State &state, uint64_t param_in) {
    const auto &param = unwrap_param<MergeParam>(param_in);
    const Value &lhs = state.peek(1);
    const Value &rhs = state.peek(0);
    auto up = generic_mixed_merge<LCT, RCT, OCT, Fun>(lhs, rhs, param);
    auto &result = state.stash.create<std::unique_ptr<Value>>(std::move(up));
    const Value &result_ref = *(result.get());
    state.pop_pop_push(result_ref);
};

struct SelectGenericMergeOp {
    template <typename LCM, typename RCM, typename Fun> static auto invoke() {
        using LCT = CellValueType<LCM::value.cell_type>;
        using RCT = CellValueType<RCM::value.cell_type>;
        constexpr CellMeta ocm = CellMeta::merge(LCM::value, RCM::value);
        using OCT = CellValueType<ocm.cell_type>;
        return my_mixed_merge_op<LCT,RCT,OCT,Fun>;
    }
};

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

} // namespace <unnamed>

using MergeTypify = TypifyValue<TypifyCellMeta,operation::TypifyOp2>;

Instruction
GenericMerge::make_instruction(const ValueType &result_type,
                               const ValueType &lhs_type, const ValueType &rhs_type, join_fun_t function,
                               const ValueBuilderFactory &factory, Stash &stash)
{
    const auto &param = stash.create<MergeParam>(result_type, lhs_type, rhs_type, function, factory);
    assert(result_type == ValueType::merge(lhs_type, rhs_type));
    auto fun = typify_invoke<3,MergeTypify,SelectGenericMergeOp>(lhs_type.cell_meta(), rhs_type.cell_meta(), function);
    return Instruction(fun, wrap_param<MergeParam>(param));
}

} // namespace
<|endoftext|>


<commit_before>/**
 * @file
 *      exercise_03_05_part_a.cpp
 * @author
 *      Henrik Samuelsson, henrik.somuelsson(at)gmail.com
 */
#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::string;

int main() {
    string temp, result;
    while(cin >> temp) {
        result.append(temp);
    }
    cout << result;
    return 0;
}
<commit_msg>Delete exercise_03_05_part1.cpp<commit_after><|endoftext|>


<commit_before>#pragma once

#include <boost/noncopyable.hpp>

#include "error_checked.hpp"
#include "type_traits.hpp"

namespace rusql { namespace mysql {
	struct TooFewBoundParameters : SQLError { TooFewBoundParameters(std::string const msg) : SQLError(msg) {} };
	struct TooManyBoundParameters : SQLError { TooManyBoundParameters(std::string const msg) : SQLError(msg) {} };

	template <typename T>
	MYSQL_BIND get_mysql_bind(T const& x){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::type::get(x);
		b.buffer = type_traits<T>::data::get(const_cast<T&>(x));
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		return b;
	}

	template <typename T>
	std::pair<MYSQL_BIND, OutputProcessor> get_mysql_output_bind(T& x, my_bool &is_null){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::output_type::get(x);
		b.buffer = type_traits<T>::data::get(x);
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		b.is_null = &is_null;
		return std::make_pair(b, type_traits<T>::output_processor::get(x));
	}

	struct Statement : boost::noncopyable {
		Connection& connection;
		MYSQL_STMT* statement;

		//TODO: Rename to input_parameters
		std::vector<MYSQL_BIND> parameters;
		std::vector<MYSQL_BIND> output_parameters;
		std::vector<OutputProcessor> output_processors;
		std::vector<my_bool> output_is_null;

		Statement(Connection& connection_, std::string const query)
		: connection(connection_)
		, statement(connection.stmt_init())
		{
			prepare(query);
		}

		Statement(Statement&& x)
		: connection(x.connection)
		, statement(std::move(x.statement))
		, parameters(std::move(x.parameters))
		, output_parameters(std::move(x.output_parameters))
		, output_processors(std::move(x.output_processors))
		, output_is_null(std::move(x.output_is_null))
		{
			x.statement = nullptr;
		}

		Statement& operator=(Statement&& x){
			std::swap(*this, x);
			return *this;
		}

		~Statement(){
			if(statement != nullptr){
				close();
			}
		}

		inline void check_and_throw(std::string const & function) {
			char const * const error = mysql_stmt_error(statement);
			if(error[0]){
				throw SQLError(function, error);
			}
		}

		template<typename T>
		void bind_parameter(T const & v) {
			parameters.emplace_back(get_mysql_bind(v));
			//auto const& b = parameters.back();
			//auto length = b.buffer_length;
			//char* begin = (char*)b.buffer;
			//char* end = &((char*)b.buffer)[length];
			//COUT << "Bound arg: type: " << b.buffer_type << " data (length: " << length << " ): " << std::string(begin, end) <<  std::endl;
		}

		template<typename T, typename... Tail>
		void bind(T const & v, Tail const &... tail) {
			bind_parameter(v);
			bind(tail...);
		}

		//! Base case for bind
		void bind(){
			if(param_count() < parameters.size()){
				throw TooManyBoundParameters("You've bound too many parameters");
			} else if(param_count() > parameters.size()){
				throw TooFewBoundParameters("You've bound too few parameters");
			}
			bind_param(parameters.data());
		}

		template <typename T>
		void bind_result_element(T& v){
			output_is_null.emplace_back(0);
			auto res = get_mysql_output_bind(v, output_is_null.back());
			output_parameters.emplace_back(res.first);
			output_processors.emplace_back(res.second);
			assert(output_parameters.size() == output_processors.size());
			assert(output_parameters.size() == output_is_null.size());
		}

		template <typename T, typename ... Tail>
		void bind_results(T& v, Tail& ... tail){
			bind_result_element(v);
			bind_results(tail ...);
		}

		void bind_results(){
			bind_result(output_parameters.data());
		}

		int prepare(std::string const q){
			return rusql::mysql::stmt_prepare(statement, q);
		}

		size_t param_count(){
			return rusql::mysql::stmt_param_count(statement);
		}

		my_bool bind_param(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_param(statement, binds);
		}

		my_bool bind_result(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_result(statement, binds);
		}

		int fetch(){
			int res = rusql::mysql::stmt_fetch(statement);
			if(res != MYSQL_NO_DATA) {
				// post-process the bind results
				assert(output_parameters.size() == output_processors.size());
				for(unsigned i = 0; i < output_parameters.size(); ++i) {
					MYSQL_BIND &bound = output_parameters.at(i);
					OutputProcessor &func = output_processors.at(i);
					func(bound);
				}
			}
			return res;
		}

		int execute(){
			return rusql::mysql::stmt_execute(statement);
		}

		unsigned long long insert_id() {
			return rusql::mysql::stmt_insert_id(statement);
		}

		void store_result() {
			rusql::mysql::stmt_store_result(statement);
		}

		/*! You need to call store_result() before this function returns anything other than 0. This
		 * is a MySQL limitation. */
		unsigned long long num_rows() {
			return rusql::mysql::stmt_num_rows(statement);
		}

		my_bool close(){
			auto const result = rusql::mysql::stmt_close(statement);
			statement = nullptr;
			return result;
		}
	};
}}
<commit_msg>Slightly clean up code by putting the OutputProcessor and is_null bool in the same struct.<commit_after>#pragma once

#include <boost/noncopyable.hpp>

#include "error_checked.hpp"
#include "type_traits.hpp"

namespace rusql { namespace mysql {
	struct TooFewBoundParameters : SQLError { TooFewBoundParameters(std::string const msg) : SQLError(msg) {} };
	struct TooManyBoundParameters : SQLError { TooManyBoundParameters(std::string const msg) : SQLError(msg) {} };

	template <typename T>
	MYSQL_BIND get_mysql_bind(T const& x){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::type::get(x);
		b.buffer = type_traits<T>::data::get(const_cast<T&>(x));
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		return b;
	}

	template <typename T>
	std::pair<MYSQL_BIND, OutputProcessor> get_mysql_output_bind(T& x, my_bool &is_null){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::output_type::get(x);
		b.buffer = type_traits<T>::data::get(x);
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		b.is_null = &is_null;
		return std::make_pair(b, type_traits<T>::output_processor::get(x));
	}

	struct Statement : boost::noncopyable {
		Connection& connection;
		MYSQL_STMT* statement;

		struct OutputHelper {
			OutputProcessor post_process;
			my_bool is_null;
		};

		//TODO: Rename to input_parameters
		std::vector<MYSQL_BIND> parameters;
		std::vector<MYSQL_BIND> output_parameters;
		std::vector<OutputHelper> output_helpers;

		Statement(Connection& connection_, std::string const query)
		: connection(connection_)
		, statement(connection.stmt_init())
		{
			prepare(query);
		}

		Statement(Statement&& x)
		: connection(x.connection)
		, statement(std::move(x.statement))
		, parameters(std::move(x.parameters))
		, output_parameters(std::move(x.output_parameters))
		, output_helpers(std::move(x.output_helpers))
		{
			x.statement = nullptr;
		}

		Statement& operator=(Statement&& x){
			std::swap(*this, x);
			return *this;
		}

		~Statement(){
			if(statement != nullptr){
				close();
			}
		}

		inline void check_and_throw(std::string const & function) {
			char const * const error = mysql_stmt_error(statement);
			if(error[0]){
				throw SQLError(function, error);
			}
		}

		template<typename T>
		void bind_parameter(T const & v) {
			parameters.emplace_back(get_mysql_bind(v));
			//auto const& b = parameters.back();
			//auto length = b.buffer_length;
			//char* begin = (char*)b.buffer;
			//char* end = &((char*)b.buffer)[length];
			//COUT << "Bound arg: type: " << b.buffer_type << " data (length: " << length << " ): " << std::string(begin, end) <<  std::endl;
		}

		template<typename T, typename... Tail>
		void bind(T const & v, Tail const &... tail) {
			bind_parameter(v);
			bind(tail...);
		}

		//! Base case for bind
		void bind(){
			if(param_count() < parameters.size()){
				throw TooManyBoundParameters("You've bound too many parameters");
			} else if(param_count() > parameters.size()){
				throw TooFewBoundParameters("You've bound too few parameters");
			}
			bind_param(parameters.data());
		}

		template <typename T>
		void bind_result_element(T& v){
			OutputHelper helper;
			auto res = get_mysql_output_bind(v, helper.is_null);

			output_parameters.emplace_back(res.first);
			helper.post_process = res.second;
			output_helpers.emplace_back(helper);
			assert(output_parameters.size() == output_helpers.size());
		}

		template <typename T, typename ... Tail>
		void bind_results(T& v, Tail& ... tail){
			bind_result_element(v);
			bind_results(tail ...);
		}

		void bind_results(){
			bind_result(output_parameters.data());
		}

		int prepare(std::string const q){
			return rusql::mysql::stmt_prepare(statement, q);
		}

		size_t param_count(){
			return rusql::mysql::stmt_param_count(statement);
		}

		my_bool bind_param(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_param(statement, binds);
		}

		my_bool bind_result(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_result(statement, binds);
		}

		int fetch(){
			int res = rusql::mysql::stmt_fetch(statement);
			if(res != MYSQL_NO_DATA) {
				// post-process the bind results
				for(unsigned i = 0; i < output_parameters.size(); ++i) {
					MYSQL_BIND &bound = output_parameters.at(i);
					auto &helper = output_helpers.at(i);
					helper.post_process(bound);
				}
			}
			return res;
		}

		int execute(){
			return rusql::mysql::stmt_execute(statement);
		}

		unsigned long long insert_id() {
			return rusql::mysql::stmt_insert_id(statement);
		}

		void store_result() {
			rusql::mysql::stmt_store_result(statement);
		}

		/*! You need to call store_result() before this function returns anything other than 0. This
		 * is a MySQL limitation. */
		unsigned long long num_rows() {
			return rusql::mysql::stmt_num_rows(statement);
		}

		my_bool close(){
			auto const result = rusql::mysql::stmt_close(statement);
			statement = nullptr;
			return result;
		}
	};
}}
<|endoftext|>