<commit_before>/*
 *  cam_QHY5IIbase.cpp
 *  PHD Guiding
 *
 *  Created by Craig Stark.
 *  Copyright (c) 2012 Craig Stark.
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *    Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *    Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *    Neither the name of Craig Stark, Stark Labs nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "phd.h"

#if defined(QHY5II) || defined(QHY5LII)

#include "cam_QHY5II.h"

static bool s_qhySdkInitDone = false;

static bool QHYSDKInit()
{
    if (s_qhySdkInitDone)
        return false;

    int ret;

#if defined (__APPLE__)
    wxFileName exeFile(wxStandardPaths::Get().GetExecutablePath());
    wxString exePath(exeFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR));

    const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(exePath);
    const char *temp = (const char *)tmp_buf;
    size_t const len = strlen(temp) + 1;
    char *destImgPath = new char[len];
    memcpy(destImgPath, temp, len);

    if ((ret = OSXInitQHYCCDFirmware(destImgPath)) != 0)
    {
        Debug.Write(wxString::Format("OSXInitQHYCCDFirmware(%s) failed: %d\n", destImgPath, ret));
        delete[] destImgPath;
        return true;
    }
    delete[] destImgPath;
#endif

    if ((ret = InitQHYCCDResource()) != 0)
    {
        Debug.Write(wxString::Format("InitQHYCCDResource failed: %d\n", ret));
        return true;
    }

    s_qhySdkInitDone = true;
    return false;
}

static void QHYSDKUninit()
{
    if (s_qhySdkInitDone)
    {
        ReleaseQHYCCDResource();
        s_qhySdkInitDone = false;
    }
}

Camera_QHY5IIBase::Camera_QHY5IIBase()
{
    Connected = false;
    m_hasGuideOutput = true;
    HasGainControl = true;
    RawBuffer = 0;
    Color = false;
#if 0 // Subframes do not work yet; lzr from QHY is investigating - ag 6/24/2015
    HasSubframes = true;
#endif
    m_camhandle = 0;
}

Camera_QHY5IIBase::~Camera_QHY5IIBase()
{
    delete[] RawBuffer;
    QHYSDKUninit();
}

bool Camera_QHY5IIBase::Connect()
{
    if (QHYSDKInit())
    {
        wxMessageBox(_("Failed to initialize QHY SDK"));
        return true;
    }

    int num_cams = ScanQHYCCD();
    if (num_cams <= 0)
    {
        wxMessageBox(_("No QHY cameras found"));
        return true;
    }

    for (int i = 0; i < num_cams; i++)
    {
        char camid[32];
        GetQHYCCDId(i, camid);
        if (camid[0] == 'Q' && camid[3] == '5' && camid[5] == 'I')
        {
            m_camhandle = OpenQHYCCD(camid);
            break;
        }
    }

    if (!m_camhandle)
    {
        wxMessageBox(_("Failed to connect to camera"));
        return true;
    }

    int ret = GetQHYCCDParamMinMaxStep(m_camhandle, CONTROL_GAIN, &m_gainMin, &m_gainMax, &m_gainStep);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Failed to get gain range"));
        return true;
    }

    double chipw, chiph, pixelw, pixelh;
    int imagew, imageh, bpp;
    ret = GetQHYCCDChipInfo(m_camhandle, &chipw, &chiph, &imagew, &imageh, &pixelw, &pixelh, &bpp);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Failed to connect to camera"));
        return true;
    }

    ret = SetQHYCCDBinMode(m_camhandle, 1, 1);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Failed to set camera binning"));
        return true;
    }

    FullSize = wxSize(imagew, imageh);

    delete[] RawBuffer;
    size_t size = imagew * imageh;
    RawBuffer = new unsigned char[size];

    PixelSize = sqrt(pixelw * pixelh);

    ret = InitQHYCCD(m_camhandle);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Init camera failed"));
        return true;
    }

    ret = SetQHYCCDResolution(m_camhandle, 0, 0, imagew, imageh);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Init camera failed"));
        return true;
    }

    m_curGain = -1;
    m_curExposure = -1;
    m_roi = wxRect(0, 0, imagew, imageh);

    Connected = true;
    return false;
}

bool Camera_QHY5IIBase::Disconnect()
{
    StopQHYCCDLive(m_camhandle);
    CloseQHYCCD(m_camhandle);
    m_camhandle = 0;
    Connected = false;
    delete[] RawBuffer;
    RawBuffer = 0;
    return false;
}

bool Camera_QHY5IIBase::ST4PulseGuideScope(int direction, int duration)
{
    int qdir;

    switch (direction)
    {
    case NORTH: qdir = 1; break;
    case SOUTH: qdir = 2; break;
    case EAST:  qdir = 0;  break;
    case WEST:  qdir = 3; break;
    default: return true; // bad direction passed in
    }
    ControlQHYCCDGuide(m_camhandle, qdir, duration);
    WorkerThread::MilliSleep(duration + 10);
    return false;
}

static bool StopExposure()
{
    Debug.AddLine("QHY5: cancel exposure");
    // todo
    return true;
}

bool Camera_QHY5IIBase::Capture(int duration, usImage& img, int options, const wxRect& subframe)
{
    if (img.Init(FullSize))
    {
        DisconnectWithAlert(CAPT_FAIL_MEMORY);
        return true;
    }

    bool useSubframe = !subframe.IsEmpty();
    wxRect frame = useSubframe ? subframe : wxRect(FullSize);
    if (useSubframe)
        img.Clear();

    int ret;

    // lzr from QHY says this needs to be set for every exposure
    ret = SetQHYCCDBinMode(m_camhandle, 1, 1);
    if (ret != QHYCCD_SUCCESS)
    {
        Debug.Write(wxString::Format("SetQHYCCDBinMode failed! ret = %d\n", ret));
    }

    if (m_roi != frame)
    {
        ret = SetQHYCCDResolution(m_camhandle, frame.GetLeft(), frame.GetTop(), frame.GetWidth(), frame.GetHeight());
        if (ret == QHYCCD_SUCCESS)
        {
            m_roi = frame;
        }
        else
        {
            Debug.Write(wxString::Format("SetQHYCCDResolution failed! ret = %d\n", ret));
        }
    }

    if (GuideCameraGain != m_curGain)
    {
        double gain = m_gainMin + GuideCameraGain * (m_gainMax - m_gainMin) / 100.0;
        gain = floor(gain / m_gainStep) * m_gainStep;
        Debug.Write(wxString::Format("QHY set gain %g (%g..%g incr %g)\n", gain, m_gainMin, m_gainMax, m_gainStep));
        ret = SetQHYCCDParam(m_camhandle, CONTROL_GAIN, gain);
        if (ret == QHYCCD_SUCCESS)
        {
            m_curGain = GuideCameraGain;
        }
        else
        {
            Debug.Write(wxString::Format("QHY set gain ret %d\n", ret));
            pFrame->Alert(_("Failed to set camera gain"));
        }
    }

    if (duration != m_curExposure)
    {
        ret = SetQHYCCDParam(m_camhandle, CONTROL_EXPOSURE, duration * 1000.0); // QHY duration is usec
        if (ret == QHYCCD_SUCCESS)
        {
            m_curExposure = duration;
        }
        else
        {
            Debug.Write(wxString::Format("QHY set exposure ret %d\n", ret));
            pFrame->Alert(_("Failed to set camera exposure"));
        }
    }

    ret = ExpQHYCCDSingleFrame(m_camhandle);
    if (ret != QHYCCD_SUCCESS)
    {
        Debug.Write(wxString::Format("QHY exp single frame ret %d\n", ret));
        DisconnectWithAlert(_("QHY exposure failed"));
        return true;
    }

    int w, h, bpp, channels;
    ret = GetQHYCCDSingleFrame(m_camhandle, &w, &h, &bpp, &channels, RawBuffer);
    if (ret != QHYCCD_SUCCESS)
    {
        Debug.Write(wxString::Format("QHY get single frame ret %d\n", ret));
        DisconnectWithAlert(_("QHY get frame failed"));
        return true;
    }

    if (useSubframe)
    {
        const unsigned char *src = RawBuffer;
        unsigned short *dst = img.ImageData + frame.GetTop() * FullSize.GetWidth() + frame.GetLeft();
        for (int y = 0; y < frame.GetHeight(); y++)
        {
            unsigned short *d = dst;
            for (int x = 0; x < frame.GetWidth(); x++)
                *d++ = (unsigned short) *src++;
            dst += FullSize.GetWidth();
        }
    }
    else
    {
        const unsigned char *src = RawBuffer;
        unsigned short *dst = img.ImageData;
        for (int y = 0; y < h; y++)
        {
            for (int x = 0;  x < w; x++)
            {
                *dst++ = (unsigned short) *src++;
            }
        }
    }

img.ImageData[200 * FullSize.GetWidth() + 400 + 0] = 22000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 1] = 32000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 2] = 35000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 3] = 35000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 4] = 32000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 5] = 22000;

    if (options & CAPTURE_SUBTRACT_DARK) SubtractDark(img);
    if (Color && (options & CAPTURE_RECON)) QuickLRecon(img);

    return false;
}

#endif
<commit_msg>disable subframe debug code<commit_after>/*
 *  cam_QHY5IIbase.cpp
 *  PHD Guiding
 *
 *  Created by Craig Stark.
 *  Copyright (c) 2012 Craig Stark.
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *    Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *    Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *    Neither the name of Craig Stark, Stark Labs nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "phd.h"

#if defined(QHY5II) || defined(QHY5LII)

#include "cam_QHY5II.h"

static bool s_qhySdkInitDone = false;

static bool QHYSDKInit()
{
    if (s_qhySdkInitDone)
        return false;

    int ret;

#if defined (__APPLE__)
    wxFileName exeFile(wxStandardPaths::Get().GetExecutablePath());
    wxString exePath(exeFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR));

    const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(exePath);
    const char *temp = (const char *)tmp_buf;
    size_t const len = strlen(temp) + 1;
    char *destImgPath = new char[len];
    memcpy(destImgPath, temp, len);

    if ((ret = OSXInitQHYCCDFirmware(destImgPath)) != 0)
    {
        Debug.Write(wxString::Format("OSXInitQHYCCDFirmware(%s) failed: %d\n", destImgPath, ret));
        delete[] destImgPath;
        return true;
    }
    delete[] destImgPath;
#endif

    if ((ret = InitQHYCCDResource()) != 0)
    {
        Debug.Write(wxString::Format("InitQHYCCDResource failed: %d\n", ret));
        return true;
    }

    s_qhySdkInitDone = true;
    return false;
}

static void QHYSDKUninit()
{
    if (s_qhySdkInitDone)
    {
        ReleaseQHYCCDResource();
        s_qhySdkInitDone = false;
    }
}

Camera_QHY5IIBase::Camera_QHY5IIBase()
{
    Connected = false;
    m_hasGuideOutput = true;
    HasGainControl = true;
    RawBuffer = 0;
    Color = false;
#if 0 // Subframes do not work yet; lzr from QHY is investigating - ag 6/24/2015
    HasSubframes = true;
#endif
    m_camhandle = 0;
}

Camera_QHY5IIBase::~Camera_QHY5IIBase()
{
    delete[] RawBuffer;
    QHYSDKUninit();
}

bool Camera_QHY5IIBase::Connect()
{
    if (QHYSDKInit())
    {
        wxMessageBox(_("Failed to initialize QHY SDK"));
        return true;
    }

    int num_cams = ScanQHYCCD();
    if (num_cams <= 0)
    {
        wxMessageBox(_("No QHY cameras found"));
        return true;
    }

    for (int i = 0; i < num_cams; i++)
    {
        char camid[32];
        GetQHYCCDId(i, camid);
        if (camid[0] == 'Q' && camid[3] == '5' && camid[5] == 'I')
        {
            m_camhandle = OpenQHYCCD(camid);
            break;
        }
    }

    if (!m_camhandle)
    {
        wxMessageBox(_("Failed to connect to camera"));
        return true;
    }

    int ret = GetQHYCCDParamMinMaxStep(m_camhandle, CONTROL_GAIN, &m_gainMin, &m_gainMax, &m_gainStep);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Failed to get gain range"));
        return true;
    }

    double chipw, chiph, pixelw, pixelh;
    int imagew, imageh, bpp;
    ret = GetQHYCCDChipInfo(m_camhandle, &chipw, &chiph, &imagew, &imageh, &pixelw, &pixelh, &bpp);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Failed to connect to camera"));
        return true;
    }

    ret = SetQHYCCDBinMode(m_camhandle, 1, 1);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Failed to set camera binning"));
        return true;
    }

    FullSize = wxSize(imagew, imageh);

    delete[] RawBuffer;
    size_t size = imagew * imageh;
    RawBuffer = new unsigned char[size];

    PixelSize = sqrt(pixelw * pixelh);

    ret = InitQHYCCD(m_camhandle);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Init camera failed"));
        return true;
    }

    ret = SetQHYCCDResolution(m_camhandle, 0, 0, imagew, imageh);
    if (ret != QHYCCD_SUCCESS)
    {
        CloseQHYCCD(m_camhandle);
        m_camhandle = 0;
        wxMessageBox(_("Init camera failed"));
        return true;
    }

    m_curGain = -1;
    m_curExposure = -1;
    m_roi = wxRect(0, 0, imagew, imageh);

    Connected = true;
    return false;
}

bool Camera_QHY5IIBase::Disconnect()
{
    StopQHYCCDLive(m_camhandle);
    CloseQHYCCD(m_camhandle);
    m_camhandle = 0;
    Connected = false;
    delete[] RawBuffer;
    RawBuffer = 0;
    return false;
}

bool Camera_QHY5IIBase::ST4PulseGuideScope(int direction, int duration)
{
    int qdir;

    switch (direction)
    {
    case NORTH: qdir = 1; break;
    case SOUTH: qdir = 2; break;
    case EAST:  qdir = 0;  break;
    case WEST:  qdir = 3; break;
    default: return true; // bad direction passed in
    }
    ControlQHYCCDGuide(m_camhandle, qdir, duration);
    WorkerThread::MilliSleep(duration + 10);
    return false;
}

static bool StopExposure()
{
    Debug.AddLine("QHY5: cancel exposure");
    // todo
    return true;
}

bool Camera_QHY5IIBase::Capture(int duration, usImage& img, int options, const wxRect& subframe)
{
    if (img.Init(FullSize))
    {
        DisconnectWithAlert(CAPT_FAIL_MEMORY);
        return true;
    }

    bool useSubframe = !subframe.IsEmpty();
    wxRect frame = useSubframe ? subframe : wxRect(FullSize);
    if (useSubframe)
        img.Clear();

    int ret;

    // lzr from QHY says this needs to be set for every exposure
    ret = SetQHYCCDBinMode(m_camhandle, 1, 1);
    if (ret != QHYCCD_SUCCESS)
    {
        Debug.Write(wxString::Format("SetQHYCCDBinMode failed! ret = %d\n", ret));
    }

    if (m_roi != frame)
    {
        ret = SetQHYCCDResolution(m_camhandle, frame.GetLeft(), frame.GetTop(), frame.GetWidth(), frame.GetHeight());
        if (ret == QHYCCD_SUCCESS)
        {
            m_roi = frame;
        }
        else
        {
            Debug.Write(wxString::Format("SetQHYCCDResolution failed! ret = %d\n", ret));
        }
    }

    if (GuideCameraGain != m_curGain)
    {
        double gain = m_gainMin + GuideCameraGain * (m_gainMax - m_gainMin) / 100.0;
        gain = floor(gain / m_gainStep) * m_gainStep;
        Debug.Write(wxString::Format("QHY set gain %g (%g..%g incr %g)\n", gain, m_gainMin, m_gainMax, m_gainStep));
        ret = SetQHYCCDParam(m_camhandle, CONTROL_GAIN, gain);
        if (ret == QHYCCD_SUCCESS)
        {
            m_curGain = GuideCameraGain;
        }
        else
        {
            Debug.Write(wxString::Format("QHY set gain ret %d\n", ret));
            pFrame->Alert(_("Failed to set camera gain"));
        }
    }

    if (duration != m_curExposure)
    {
        ret = SetQHYCCDParam(m_camhandle, CONTROL_EXPOSURE, duration * 1000.0); // QHY duration is usec
        if (ret == QHYCCD_SUCCESS)
        {
            m_curExposure = duration;
        }
        else
        {
            Debug.Write(wxString::Format("QHY set exposure ret %d\n", ret));
            pFrame->Alert(_("Failed to set camera exposure"));
        }
    }

    ret = ExpQHYCCDSingleFrame(m_camhandle);
    if (ret != QHYCCD_SUCCESS)
    {
        Debug.Write(wxString::Format("QHY exp single frame ret %d\n", ret));
        DisconnectWithAlert(_("QHY exposure failed"));
        return true;
    }

    int w, h, bpp, channels;
    ret = GetQHYCCDSingleFrame(m_camhandle, &w, &h, &bpp, &channels, RawBuffer);
    if (ret != QHYCCD_SUCCESS)
    {
        Debug.Write(wxString::Format("QHY get single frame ret %d\n", ret));
        DisconnectWithAlert(_("QHY get frame failed"));
        return true;
    }

    if (useSubframe)
    {
        const unsigned char *src = RawBuffer;
        unsigned short *dst = img.ImageData + frame.GetTop() * FullSize.GetWidth() + frame.GetLeft();
        for (int y = 0; y < frame.GetHeight(); y++)
        {
            unsigned short *d = dst;
            for (int x = 0; x < frame.GetWidth(); x++)
                *d++ = (unsigned short) *src++;
            dst += FullSize.GetWidth();
        }
    }
    else
    {
        const unsigned char *src = RawBuffer;
        unsigned short *dst = img.ImageData;
        for (int y = 0; y < h; y++)
        {
            for (int x = 0;  x < w; x++)
            {
                *dst++ = (unsigned short) *src++;
            }
        }
    }

#if 0 // for testing subframes on the bench
img.ImageData[200 * FullSize.GetWidth() + 400 + 0] = 22000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 1] = 32000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 2] = 35000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 3] = 35000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 4] = 32000;
img.ImageData[200 * FullSize.GetWidth() + 400 + 5] = 22000;
#endif

    if (options & CAPTURE_SUBTRACT_DARK) SubtractDark(img);
    if (Color && (options & CAPTURE_RECON)) QuickLRecon(img);

    return false;
}

#endif
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "fix4.2/Fix42.h"
#include "util.h"

TEST(TestFieldValue, CharFieldValue) {
    EXPECT_EQ('a', fromString<Fix42::kFieldType::kkChar>("a")->getValue());

    EXPECT_EQ("a\001", fromValue<Fix42::kFieldType::kkChar>('a')->toString());
}

TEST(TestFieldValue, IntFieldValue) {
    EXPECT_EQ(123, fromString<Fix42::kFieldType::kInt>("123")->getValue());
    EXPECT_NE(123, fromString<Fix42::kFieldType::kInt>("1234")->getValue());
    EXPECT_EQ(-123, fromString<Fix42::kFieldType::kInt>("-123")->getValue());

    EXPECT_EQ("123\001", fromValue<Fix42::kFieldType::kInt>(123)->toString());
}

TEST(TestFieldValue, FloatFieldValue) {
    EXPECT_DOUBLE_EQ(0.1, fromString<Fix42::kFieldType::kFloat>("0.10")->getValue());
    EXPECT_DOUBLE_EQ(0.1, fromString<Fix42::kFieldType::kFloat>("0.1")->getValue());
    EXPECT_DOUBLE_EQ(-0.1, fromString<Fix42::kFieldType::kFloat>("-0.1")->getValue());
    EXPECT_DOUBLE_EQ(1, fromString<Fix42::kFieldType::kFloat>("1")->getValue());
    EXPECT_DOUBLE_EQ(1, fromString<Fix42::kFieldType::kFloat>("1.0")->getValue());
}

TEST(TestFieldValue, StringFieldValue) {
    EXPECT_EQ(std::string("abc"), fromString<Fix42::kFieldType::kString>("abc")->getValue());

    EXPECT_EQ("abc\001", fromValue<Fix42::kFieldType::kString>("abc")->toString());
}

TEST(TestFieldValue, DataFieldValue) {
    char src[] = "0123456789";
    auto data = fromString<Fix42::kFieldType::kData>(src);
    EXPECT_EQ(10, data->getLength());
    const char *begin = data->getValue();
    for (int i = 0; i < data->getLength(); i++) {
        EXPECT_EQ(src[i], begin[i]);
    }

    auto expect = std::string(src) + '\001';
    EXPECT_EQ(expect, fromValue<Fix42::kFieldType::kData>(src, 10)->toString());
    EXPECT_EQ(expect, data->toString());
}

<commit_msg>Fix typo<commit_after>#include "gtest/gtest.h"
#include "fix4.2/Fix42.h"
#include "util.h"

TEST(TestFieldValue, CharFieldValue) {
    EXPECT_EQ('a', fromString<Fix42::kFieldType::kChar>("a")->getValue());

    EXPECT_EQ("a\001", fromValue<Fix42::kFieldType::kChar>('a')->toString());
}

TEST(TestFieldValue, IntFieldValue) {
    EXPECT_EQ(123, fromString<Fix42::kFieldType::kInt>("123")->getValue());
    EXPECT_NE(123, fromString<Fix42::kFieldType::kInt>("1234")->getValue());
    EXPECT_EQ(-123, fromString<Fix42::kFieldType::kInt>("-123")->getValue());

    EXPECT_EQ("123\001", fromValue<Fix42::kFieldType::kInt>(123)->toString());
}

TEST(TestFieldValue, FloatFieldValue) {
    EXPECT_DOUBLE_EQ(0.1, fromString<Fix42::kFieldType::kFloat>("0.10")->getValue());
    EXPECT_DOUBLE_EQ(0.1, fromString<Fix42::kFieldType::kFloat>("0.1")->getValue());
    EXPECT_DOUBLE_EQ(-0.1, fromString<Fix42::kFieldType::kFloat>("-0.1")->getValue());
    EXPECT_DOUBLE_EQ(1, fromString<Fix42::kFieldType::kFloat>("1")->getValue());
    EXPECT_DOUBLE_EQ(1, fromString<Fix42::kFieldType::kFloat>("1.0")->getValue());
}

TEST(TestFieldValue, StringFieldValue) {
    EXPECT_EQ(std::string("abc"), fromString<Fix42::kFieldType::kString>("abc")->getValue());

    EXPECT_EQ("abc\001", fromValue<Fix42::kFieldType::kString>("abc")->toString());
}

TEST(TestFieldValue, DataFieldValue) {
    char src[] = "0123456789";
    auto data = fromString<Fix42::kFieldType::kData>(src);
    EXPECT_EQ(10, data->getLength());
    const char *begin = data->getValue();
    for (int i = 0; i < data->getLength(); i++) {
        EXPECT_EQ(src[i], begin[i]);
    }

    auto expect = std::string(src) + '\001';
    EXPECT_EQ(expect, fromValue<Fix42::kFieldType::kData>(src, 10)->toString());
    EXPECT_EQ(expect, data->toString());
}

<|endoftext|>


<commit_before>/*
    Copyright (c) 2010-2011 Sune Vuorela <sune@vuorela.dk>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#include "qrcodebarcode.h"
#include <qrencode.h>
using namespace prison;
/**
@cond PRIVATE
*/
class QRCodeBarcode::Private {
  public:
};
/**
@endcond
*/

QRCodeBarcode::QRCodeBarcode() : AbstractBarcode(), d(0){

}

QRCodeBarcode::~QRCodeBarcode() {
  delete d;
}

QImage QRCodeBarcode::toImage(const QSizeF& size) {
  const int width = qRound(qMin(size.width(),size.height()));
  if(data().size()==0 || width==0) {
    return QImage();
  }
  const QByteArray trimmedData(data().trimmed().toUtf8());
  QRcode* code = QRcode_encodeString8bit(trimmedData.constData(), 0, QR_ECLEVEL_Q);
  const int margin = 2;
  /*32 bit colors, 8 bit pr byte*/
  uchar* img = new uchar[4 *sizeof(char*)*(2*margin + code->width)*(2*margin* + code->width)];
  uchar* p = img;
  const char white = 0xff;
  const char black = 0x00;
  for(int row = 0 ; row < code->width+2*margin ; row++) {
    for(int col = 0 ; col < code->width+2*margin ; col++) {
      if(row < margin || row >= (code->width+margin) || col < margin || col >= (code->width+margin)) {
        /*4 bytes for color*/
        for(int i =0 ; i<4 ; i++) {
          *p = white;
          p++;
        }
      } else {
        int  c= (row-margin)*code->width + (col-margin);
        /*it is bit 1 that is the interesting bit for us from libqrencode*/
        if(code->data[c] & 1) {
          /*4 bytes for color*/
          for(int i =0 ; i<4 ; i++) {
            *p = black;
            p++;
          }
        } else {
          /*4 bytes for color*/
          for(int i =0 ; i<4 ; i++) {
            *p = white;
            p++;
          }
        }
      }
    }
  }
  QImage tmp(img,code->width+2*margin,code->width+2*margin,QImage::Format_RGB32);
  setMinimumSize(QSizeF(tmp.width()*4,tmp.height()*4));
  QImage ret = tmp.convertToFormat(QImage::Format_Mono).scaled(qMax(tmp.width()*4,width),qMax(tmp.height()*4,width)); //4 is determined by trial and error.
  delete[] img;
  QRcode_free(code);
  return ret;
}
<commit_msg>QRcode_encodeString8bit can return a null pointer under some circumstances. Check for this and return a default constructed QImage in that case<commit_after>/*
    Copyright (c) 2010-2011 Sune Vuorela <sune@vuorela.dk>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#include "qrcodebarcode.h"
#include <qrencode.h>
using namespace prison;
/**
@cond PRIVATE
*/
class QRCodeBarcode::Private {
  public:
};
/**
@endcond
*/

QRCodeBarcode::QRCodeBarcode() : AbstractBarcode(), d(0){

}

QRCodeBarcode::~QRCodeBarcode() {
  delete d;
}

QImage QRCodeBarcode::toImage(const QSizeF& size) {
  const int width = qRound(qMin(size.width(),size.height()));
  if(data().size()==0 || width==0) {
    return QImage();
  }
  const QByteArray trimmedData(data().trimmed().toUtf8());
  QRcode* code = QRcode_encodeString8bit(trimmedData.constData(), 0, QR_ECLEVEL_Q);
  if(!code) {
    return QImage();
  }
  const int margin = 2;
  /*32 bit colors, 8 bit pr byte*/
  uchar* img = new uchar[4 *sizeof(char*)*(2*margin + code->width)*(2*margin* + code->width)];
  uchar* p = img;
  const char white = 0xff;
  const char black = 0x00;
  for(int row = 0 ; row < code->width+2*margin ; row++) {
    for(int col = 0 ; col < code->width+2*margin ; col++) {
      if(row < margin || row >= (code->width+margin) || col < margin || col >= (code->width+margin)) {
        /*4 bytes for color*/
        for(int i =0 ; i<4 ; i++) {
          *p = white;
          p++;
        }
      } else {
        int  c= (row-margin)*code->width + (col-margin);
        /*it is bit 1 that is the interesting bit for us from libqrencode*/
        if(code->data[c] & 1) {
          /*4 bytes for color*/
          for(int i =0 ; i<4 ; i++) {
            *p = black;
            p++;
          }
        } else {
          /*4 bytes for color*/
          for(int i =0 ; i<4 ; i++) {
            *p = white;
            p++;
          }
        }
      }
    }
  }
  QImage tmp(img,code->width+2*margin,code->width+2*margin,QImage::Format_RGB32);
  setMinimumSize(QSizeF(tmp.width()*4,tmp.height()*4));
  QImage ret = tmp.convertToFormat(QImage::Format_Mono).scaled(qMax(tmp.width()*4,width),qMax(tmp.height()*4,width)); //4 is determined by trial and error.
  delete[] img;
  QRcode_free(code);
  return ret;
}
<|endoftext|>


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

#include <folly/io/async/HHWheelTimer.h>

#include <cassert>

#include <folly/Memory.h>
#include <folly/Optional.h>
#include <folly/ScopeGuard.h>
#include <folly/container/BitIterator.h>
#include <folly/io/async/Request.h>
#include <folly/lang/Bits.h>

using std::chrono::milliseconds;

namespace folly {

/**
 * We want to select the default interval carefully.
 * An interval of 10ms will give us 10ms * WHEEL_SIZE^WHEEL_BUCKETS
 * for the largest timeout possible, or about 497 days.
 *
 * For a lower bound, we want a reasonable limit on local IO, 10ms
 * seems short enough
 *
 * A shorter interval also has CPU implications, less than 1ms might
 * start showing up in cpu perf.  Also, it might not be possible to set
 * tick interval less than 10ms on older kernels.
 */
int HHWheelTimer::DEFAULT_TICK_INTERVAL = 10;

HHWheelTimer::Callback::~Callback() {
  if (isScheduled()) {
    cancelTimeout();
  }
}

void HHWheelTimer::Callback::setScheduled(
    HHWheelTimer* wheel,
    std::chrono::milliseconds timeout) {
  assert(wheel_ == nullptr);
  assert(expiration_ == decltype(expiration_){});

  wheel_ = wheel;

  expiration_ = getCurTime() + timeout;
}

void HHWheelTimer::Callback::cancelTimeoutImpl() {
  if (--wheel_->count_ <= 0) {
    assert(wheel_->count_ == 0);
    wheel_->AsyncTimeout::cancelTimeout();
  }
  unlink();
  if ((-1 != bucket_) && (wheel_->buckets_[0][bucket_].empty())) {
    auto bi = makeBitIterator(wheel_->bitmap_.begin());
    *(bi + bucket_) = false;
  }

  wheel_ = nullptr;
  expiration_ = {};
}

HHWheelTimer::HHWheelTimer(
    folly::TimeoutManager* timeoutMananger,
    std::chrono::milliseconds intervalMS,
    AsyncTimeout::InternalEnum internal,
    std::chrono::milliseconds defaultTimeoutMS)
    : AsyncTimeout(timeoutMananger, internal),
      interval_(intervalMS),
      defaultTimeout_(defaultTimeoutMS),
      lastTick_(1),
      expireTick_(1),
      count_(0),
      startTime_(getCurTime()),
      processingCallbacksGuard_(nullptr) {
  bitmap_.resize((WHEEL_SIZE / sizeof(std::size_t)) / 8, 0);
}

HHWheelTimer::~HHWheelTimer() {
  // Ensure this gets done, but right before destruction finishes.
  auto destructionPublisherGuard = folly::makeGuard([&] {
    // Inform the subscriber that this instance is doomed.
    if (processingCallbacksGuard_) {
      *processingCallbacksGuard_ = true;
    }
  });
  cancelAll();
}

void HHWheelTimer::scheduleTimeoutImpl(
    Callback* callback,
    std::chrono::milliseconds timeout,
    int64_t nextTickToProcess,
    int64_t nextTick) {
  int64_t due = timeToWheelTicks(timeout) + nextTick;
  int64_t diff = due - nextTickToProcess;
  CallbackList* list;

  auto bi = makeBitIterator(bitmap_.begin());

  if (diff < 0) {
    list = &buckets_[0][nextTick & WHEEL_MASK];
    *(bi + (nextTick & WHEEL_MASK)) = true;
    callback->bucket_ = nextTick & WHEEL_MASK;
  } else if (diff < WHEEL_SIZE) {
    list = &buckets_[0][due & WHEEL_MASK];
    *(bi + (due & WHEEL_MASK)) = true;
    callback->bucket_ = due & WHEEL_MASK;
  } else if (diff < 1 << (2 * WHEEL_BITS)) {
    list = &buckets_[1][(due >> WHEEL_BITS) & WHEEL_MASK];
  } else if (diff < 1 << (3 * WHEEL_BITS)) {
    list = &buckets_[2][(due >> 2 * WHEEL_BITS) & WHEEL_MASK];
  } else {
    /* in largest slot */
    if (diff > LARGEST_SLOT) {
      diff = LARGEST_SLOT;
      due = diff + nextTickToProcess;
    }
    list = &buckets_[3][(due >> 3 * WHEEL_BITS) & WHEEL_MASK];
  }
  list->push_back(*callback);
}

void HHWheelTimer::scheduleTimeout(
    Callback* callback,
    std::chrono::milliseconds timeout) {
  // Cancel the callback if it happens to be scheduled already.
  callback->cancelTimeout();
  callback->requestContext_ = RequestContext::saveContext();

  count_++;

  callback->setScheduled(this, timeout);
  auto nextTick = calcNextTick();

  // It's possible that the wheel timeout is already scheduled for earlier
  // tick, but it didn't run yet. In such case, we must use the lowest of them
  // to avoid using the wrong slot.
  int64_t baseTick = nextTick;
  if (isScheduled()) {
    baseTick = std::min(expireTick_, nextTick);
  }
  scheduleTimeoutImpl(callback, timeout, baseTick, nextTick);

  /* If we're calling callbacks, timer will be reset after all
   * callbacks are called.
   */
  if (!processingCallbacksGuard_) {
    scheduleNextTimeout(nextTick);
  }
}

void HHWheelTimer::scheduleTimeout(Callback* callback) {
  CHECK(std::chrono::milliseconds(-1) != defaultTimeout_)
      << "Default timeout was not initialized";
  scheduleTimeout(callback, defaultTimeout_);
}

bool HHWheelTimer::cascadeTimers(int bucket, int tick) {
  CallbackList cbs;
  cbs.swap(buckets_[bucket][tick]);
  while (!cbs.empty()) {
    auto* cb = &cbs.front();
    cbs.pop_front();
    scheduleTimeoutImpl(
        cb, cb->getTimeRemaining(getCurTime()), lastTick_, calcNextTick());
  }

  // If tick is zero, timeoutExpired will cascade the next bucket.
  return tick == 0;
}

void HHWheelTimer::timeoutExpired() noexcept {
  auto nextTick = calcNextTick();

  // If the last smart pointer for "this" is reset inside the callback's
  // timeoutExpired(), then the guard will detect that it is time to bail from
  // this method.
  auto isDestroyed = false;
  // If scheduleTimeout is called from a callback in this function, it may
  // cause inconsistencies in the state of this object. As such, we need
  // to treat these calls slightly differently.
  CHECK(!processingCallbacksGuard_);
  processingCallbacksGuard_ = &isDestroyed;
  auto reEntryGuard = folly::makeGuard([&] {
    if (!isDestroyed) {
      processingCallbacksGuard_ = nullptr;
    }
  });

  // timeoutExpired() can only be invoked directly from the event base loop.
  // It should never be invoked recursively.
  //
  lastTick_ = expireTick_;
  while (lastTick_ < nextTick) {
    int idx = lastTick_ & WHEEL_MASK;

    auto bi = makeBitIterator(bitmap_.begin());
    *(bi + idx) = false;

    lastTick_++;
    CallbackList* cbs = &buckets_[0][idx];
    while (!cbs->empty()) {
      auto* cb = &cbs->front();
      cbs->pop_front();
      timeoutsToRunNow_.push_back(*cb);
    }

    if (idx == 0) {
      // Cascade timers
      if (cascadeTimers(1, (lastTick_ >> WHEEL_BITS) & WHEEL_MASK) &&
          cascadeTimers(2, (lastTick_ >> (2 * WHEEL_BITS)) & WHEEL_MASK)) {
        cascadeTimers(3, (lastTick_ >> (3 * WHEEL_BITS)) & WHEEL_MASK);
      }
    }
  }

  while (!timeoutsToRunNow_.empty()) {
    auto* cb = &timeoutsToRunNow_.front();
    timeoutsToRunNow_.pop_front();
    count_--;
    cb->wheel_ = nullptr;
    cb->expiration_ = {};
    RequestContextScopeGuard rctx(cb->requestContext_);
    cb->timeoutExpired();
    if (isDestroyed) {
      // The HHWheelTimer itself has been destroyed. The other callbacks
      // will have been cancelled from the destructor. Bail before causing
      // damage.
      return;
    }
  }
  scheduleNextTimeout(calcNextTick());
}

size_t HHWheelTimer::cancelAll() {
  size_t count = 0;

  if (count_ != 0) {
    const std::size_t numElements = WHEEL_BUCKETS * WHEEL_SIZE;
    auto maxBuckets = std::min(numElements, count_);
    auto buckets = std::make_unique<CallbackList[]>(maxBuckets);
    size_t countBuckets = 0;
    for (auto& tick : buckets_) {
      for (auto& bucket : tick) {
        if (bucket.empty()) {
          continue;
        }
        count += bucket.size();
        std::swap(bucket, buckets[countBuckets++]);
        if (count >= count_) {
          break;
        }
      }
    }

    for (size_t i = 0; i < countBuckets; ++i) {
      cancelTimeoutsFromList(buckets[i]);
    }
    // Swap the list to prevent potential recursion if cancelAll is called by
    // one of the callbacks.
    CallbackList timeoutsToRunNow;
    timeoutsToRunNow.swap(timeoutsToRunNow_);
    count += cancelTimeoutsFromList(timeoutsToRunNow);
  }

  return count;
}

void HHWheelTimer::scheduleNextTimeout(int64_t nextTick) {
  int64_t tick = 1;

  if (nextTick & WHEEL_MASK) {
    auto bi = makeBitIterator(bitmap_.begin());
    auto bi_end = makeBitIterator(bitmap_.end());
    auto it = folly::findFirstSet(bi + (nextTick & WHEEL_MASK), bi_end);
    if (it == bi_end) {
      tick = WHEEL_SIZE - ((nextTick - 1) & WHEEL_MASK);
    } else {
      tick = std::distance(bi + (nextTick & WHEEL_MASK), it) + 1;
    }
  }

  if (count_ > 0) {
    if (!this->AsyncTimeout::isScheduled() ||
        (expireTick_ > tick + nextTick - 1)) {
      this->AsyncTimeout::scheduleTimeout(interval_ * tick);
      expireTick_ = tick + nextTick - 1;
    }
  } else {
    this->AsyncTimeout::cancelTimeout();
  }
}

size_t HHWheelTimer::cancelTimeoutsFromList(CallbackList& timeouts) {
  size_t count = 0;
  while (!timeouts.empty()) {
    ++count;
    auto& cb = timeouts.front();
    cb.cancelTimeout();
    cb.callbackCanceled();
  }
  return count;
}

int64_t HHWheelTimer::calcNextTick() {
  auto intervals = (getCurTime() - startTime_) / interval_;
  // Slow eventbases will have skew between the actual time and the
  // callback time.  To avoid racing the next scheduleNextTimeout()
  // call, always schedule new timeouts against the actual
  // timeoutExpired() time.
  if (!processingCallbacksGuard_) {
    return intervals;
  } else {
    return lastTick_;
  }
}

} // namespace folly
<commit_msg>Allow cascading into the current tick<commit_after>/*
 * Copyright 2014-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/io/async/HHWheelTimer.h>

#include <cassert>

#include <folly/Memory.h>
#include <folly/Optional.h>
#include <folly/ScopeGuard.h>
#include <folly/container/BitIterator.h>
#include <folly/io/async/Request.h>
#include <folly/lang/Bits.h>

using std::chrono::milliseconds;

namespace folly {

/**
 * We want to select the default interval carefully.
 * An interval of 10ms will give us 10ms * WHEEL_SIZE^WHEEL_BUCKETS
 * for the largest timeout possible, or about 497 days.
 *
 * For a lower bound, we want a reasonable limit on local IO, 10ms
 * seems short enough
 *
 * A shorter interval also has CPU implications, less than 1ms might
 * start showing up in cpu perf.  Also, it might not be possible to set
 * tick interval less than 10ms on older kernels.
 */
int HHWheelTimer::DEFAULT_TICK_INTERVAL = 10;

HHWheelTimer::Callback::~Callback() {
  if (isScheduled()) {
    cancelTimeout();
  }
}

void HHWheelTimer::Callback::setScheduled(
    HHWheelTimer* wheel,
    std::chrono::milliseconds timeout) {
  assert(wheel_ == nullptr);
  assert(expiration_ == decltype(expiration_){});

  wheel_ = wheel;

  expiration_ = getCurTime() + timeout;
}

void HHWheelTimer::Callback::cancelTimeoutImpl() {
  if (--wheel_->count_ <= 0) {
    assert(wheel_->count_ == 0);
    wheel_->AsyncTimeout::cancelTimeout();
  }
  unlink();
  if ((-1 != bucket_) && (wheel_->buckets_[0][bucket_].empty())) {
    auto bi = makeBitIterator(wheel_->bitmap_.begin());
    *(bi + bucket_) = false;
  }

  wheel_ = nullptr;
  expiration_ = {};
}

HHWheelTimer::HHWheelTimer(
    folly::TimeoutManager* timeoutMananger,
    std::chrono::milliseconds intervalMS,
    AsyncTimeout::InternalEnum internal,
    std::chrono::milliseconds defaultTimeoutMS)
    : AsyncTimeout(timeoutMananger, internal),
      interval_(intervalMS),
      defaultTimeout_(defaultTimeoutMS),
      lastTick_(1),
      expireTick_(1),
      count_(0),
      startTime_(getCurTime()),
      processingCallbacksGuard_(nullptr) {
  bitmap_.resize((WHEEL_SIZE / sizeof(std::size_t)) / 8, 0);
}

HHWheelTimer::~HHWheelTimer() {
  // Ensure this gets done, but right before destruction finishes.
  auto destructionPublisherGuard = folly::makeGuard([&] {
    // Inform the subscriber that this instance is doomed.
    if (processingCallbacksGuard_) {
      *processingCallbacksGuard_ = true;
    }
  });
  cancelAll();
}

void HHWheelTimer::scheduleTimeoutImpl(
    Callback* callback,
    std::chrono::milliseconds timeout,
    int64_t nextTickToProcess,
    int64_t nextTick) {
  int64_t due = timeToWheelTicks(timeout) + nextTick;
  int64_t diff = due - nextTickToProcess;
  CallbackList* list;

  auto bi = makeBitIterator(bitmap_.begin());

  if (diff < 0) {
    list = &buckets_[0][nextTick & WHEEL_MASK];
    *(bi + (nextTick & WHEEL_MASK)) = true;
    callback->bucket_ = nextTick & WHEEL_MASK;
  } else if (diff < WHEEL_SIZE) {
    list = &buckets_[0][due & WHEEL_MASK];
    *(bi + (due & WHEEL_MASK)) = true;
    callback->bucket_ = due & WHEEL_MASK;
  } else if (diff < 1 << (2 * WHEEL_BITS)) {
    list = &buckets_[1][(due >> WHEEL_BITS) & WHEEL_MASK];
  } else if (diff < 1 << (3 * WHEEL_BITS)) {
    list = &buckets_[2][(due >> 2 * WHEEL_BITS) & WHEEL_MASK];
  } else {
    /* in largest slot */
    if (diff > LARGEST_SLOT) {
      diff = LARGEST_SLOT;
      due = diff + nextTickToProcess;
    }
    list = &buckets_[3][(due >> 3 * WHEEL_BITS) & WHEEL_MASK];
  }
  list->push_back(*callback);
}

void HHWheelTimer::scheduleTimeout(
    Callback* callback,
    std::chrono::milliseconds timeout) {
  // Cancel the callback if it happens to be scheduled already.
  callback->cancelTimeout();
  callback->requestContext_ = RequestContext::saveContext();

  count_++;

  callback->setScheduled(this, timeout);
  auto nextTick = calcNextTick();

  // It's possible that the wheel timeout is already scheduled for earlier
  // tick, but it didn't run yet. In such case, we must use the lowest of them
  // to avoid using the wrong slot.
  int64_t baseTick = nextTick;
  if (isScheduled()) {
    baseTick = std::min(expireTick_, nextTick);
  }
  scheduleTimeoutImpl(callback, timeout, baseTick, nextTick);

  /* If we're calling callbacks, timer will be reset after all
   * callbacks are called.
   */
  if (!processingCallbacksGuard_) {
    scheduleNextTimeout(nextTick);
  }
}

void HHWheelTimer::scheduleTimeout(Callback* callback) {
  CHECK(std::chrono::milliseconds(-1) != defaultTimeout_)
      << "Default timeout was not initialized";
  scheduleTimeout(callback, defaultTimeout_);
}

bool HHWheelTimer::cascadeTimers(int bucket, int tick) {
  CallbackList cbs;
  cbs.swap(buckets_[bucket][tick]);
  while (!cbs.empty()) {
    auto* cb = &cbs.front();
    cbs.pop_front();
    scheduleTimeoutImpl(
        cb, cb->getTimeRemaining(getCurTime()), lastTick_, calcNextTick());
  }

  // If tick is zero, timeoutExpired will cascade the next bucket.
  return tick == 0;
}

void HHWheelTimer::timeoutExpired() noexcept {
  auto nextTick = calcNextTick();

  // If the last smart pointer for "this" is reset inside the callback's
  // timeoutExpired(), then the guard will detect that it is time to bail from
  // this method.
  auto isDestroyed = false;
  // If scheduleTimeout is called from a callback in this function, it may
  // cause inconsistencies in the state of this object. As such, we need
  // to treat these calls slightly differently.
  CHECK(!processingCallbacksGuard_);
  processingCallbacksGuard_ = &isDestroyed;
  auto reEntryGuard = folly::makeGuard([&] {
    if (!isDestroyed) {
      processingCallbacksGuard_ = nullptr;
    }
  });

  // timeoutExpired() can only be invoked directly from the event base loop.
  // It should never be invoked recursively.
  //
  lastTick_ = expireTick_;
  while (lastTick_ < nextTick) {
    int idx = lastTick_ & WHEEL_MASK;

    if (idx == 0) {
      // Cascade timers
      if (cascadeTimers(1, (lastTick_ >> WHEEL_BITS) & WHEEL_MASK) &&
          cascadeTimers(2, (lastTick_ >> (2 * WHEEL_BITS)) & WHEEL_MASK)) {
        cascadeTimers(3, (lastTick_ >> (3 * WHEEL_BITS)) & WHEEL_MASK);
      }
    }

    auto bi = makeBitIterator(bitmap_.begin());
    *(bi + idx) = false;

    lastTick_++;
    CallbackList* cbs = &buckets_[0][idx];
    while (!cbs->empty()) {
      auto* cb = &cbs->front();
      cbs->pop_front();
      timeoutsToRunNow_.push_back(*cb);
    }
  }

  while (!timeoutsToRunNow_.empty()) {
    auto* cb = &timeoutsToRunNow_.front();
    timeoutsToRunNow_.pop_front();
    count_--;
    cb->wheel_ = nullptr;
    cb->expiration_ = {};
    RequestContextScopeGuard rctx(cb->requestContext_);
    cb->timeoutExpired();
    if (isDestroyed) {
      // The HHWheelTimer itself has been destroyed. The other callbacks
      // will have been cancelled from the destructor. Bail before causing
      // damage.
      return;
    }
  }
  scheduleNextTimeout(calcNextTick());
}

size_t HHWheelTimer::cancelAll() {
  size_t count = 0;

  if (count_ != 0) {
    const std::size_t numElements = WHEEL_BUCKETS * WHEEL_SIZE;
    auto maxBuckets = std::min(numElements, count_);
    auto buckets = std::make_unique<CallbackList[]>(maxBuckets);
    size_t countBuckets = 0;
    for (auto& tick : buckets_) {
      for (auto& bucket : tick) {
        if (bucket.empty()) {
          continue;
        }
        count += bucket.size();
        std::swap(bucket, buckets[countBuckets++]);
        if (count >= count_) {
          break;
        }
      }
    }

    for (size_t i = 0; i < countBuckets; ++i) {
      cancelTimeoutsFromList(buckets[i]);
    }
    // Swap the list to prevent potential recursion if cancelAll is called by
    // one of the callbacks.
    CallbackList timeoutsToRunNow;
    timeoutsToRunNow.swap(timeoutsToRunNow_);
    count += cancelTimeoutsFromList(timeoutsToRunNow);
  }

  return count;
}

void HHWheelTimer::scheduleNextTimeout(int64_t nextTick) {
  int64_t tick = 1;

  if (nextTick & WHEEL_MASK) {
    auto bi = makeBitIterator(bitmap_.begin());
    auto bi_end = makeBitIterator(bitmap_.end());
    auto it = folly::findFirstSet(bi + (nextTick & WHEEL_MASK), bi_end);
    if (it == bi_end) {
      tick = WHEEL_SIZE - ((nextTick - 1) & WHEEL_MASK);
    } else {
      tick = std::distance(bi + (nextTick & WHEEL_MASK), it) + 1;
    }
  }

  if (count_ > 0) {
    if (!this->AsyncTimeout::isScheduled() ||
        (expireTick_ > tick + nextTick - 1)) {
      this->AsyncTimeout::scheduleTimeout(interval_ * tick);
      expireTick_ = tick + nextTick - 1;
    }
  } else {
    this->AsyncTimeout::cancelTimeout();
  }
}

size_t HHWheelTimer::cancelTimeoutsFromList(CallbackList& timeouts) {
  size_t count = 0;
  while (!timeouts.empty()) {
    ++count;
    auto& cb = timeouts.front();
    cb.cancelTimeout();
    cb.callbackCanceled();
  }
  return count;
}

int64_t HHWheelTimer::calcNextTick() {
  auto intervals = (getCurTime() - startTime_) / interval_;
  // Slow eventbases will have skew between the actual time and the
  // callback time.  To avoid racing the next scheduleNextTimeout()
  // call, always schedule new timeouts against the actual
  // timeoutExpired() time.
  if (!processingCallbacksGuard_) {
    return intervals;
  } else {
    return lastTick_;
  }
}

} // namespace folly
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: Edit.hxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-01 14:54:45 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _FORMS_EDIT_HXX_
#define _FORMS_EDIT_HXX_

#include "EditBase.hxx"

#include <cppuhelper/implbase3.hxx>

namespace dbtools { class FormattedColumnValue; }

//.........................................................................
namespace frm
{

//==================================================================
//= OEditModel
//==================================================================
class OEditModel
                :public OEditBaseModel
{
    ::rtl::OUString             m_aSaveValue;
    ::std::auto_ptr< ::dbtools::FormattedColumnValue >
                                m_pValueFormatter;
    sal_Bool                    m_bMaxTextLenModified : 1;  // set to <TRUE/> when we change the MaxTextLen of the aggregate

    sal_Bool                    m_bWritingFormattedFake : 1;
        // are we writing something which should be interpreted as formatted upon reading?

protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

    DECLARE_DEFAULT_LEAF_XTOR( OEditModel );

    void enableFormattedWriteFake() { m_bWritingFormattedFake = sal_True; }
    void disableFormattedWriteFake() { m_bWritingFormattedFake = sal_False; }
    sal_Bool lastReadWasFormattedFake() const { return (getLastReadVersion() & PF_FAKE_FORMATTED_FIELD) != 0; }

    friend InterfaceRef SAL_CALL OEditModel_CreateInstance(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);
    friend class OFormattedFieldWrapper;
    friend class OFormattedModel;   // temporary

public:
    virtual void SAL_CALL disposing();

    // XPropertySet
    virtual void SAL_CALL getFastPropertyValue(::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const;

    // XPersistObject
    virtual void SAL_CALL write(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL read(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun::star::uno::RuntimeException);

    // XPropertySet
    using OBoundControlModel::getFastPropertyValue;

    // XReset
    virtual void SAL_CALL reset(  ) throw(::com::sun::star::uno::RuntimeException);

    // XServiceInfo
    IMPLEMENTATION_NAME(OEditModel);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

    // OControlModel's property handling
    virtual void describeFixedProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps
    ) const;
    virtual void describeAggregateProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rAggregateProps
    ) const;

    // XEventListener
    using OBoundControlModel::disposing;

protected:
    // OControlModel overridables
    virtual void writeAggregate( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream >& _rxOutStream ) const;
    virtual void readAggregate( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream >& _rxInStream );

    // OBoundControlModel overridables
    virtual ::com::sun::star::uno::Any
                            translateDbColumnToControlValue( );
    virtual sal_Bool        commitControlValueToDbColumn( bool _bPostReset );

    virtual ::com::sun::star::uno::Any
                            getDefaultForReset() const;

    virtual void            onConnectedDbColumn( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxForm );
    virtual void            onDisconnectedDbColumn();

    virtual sal_Bool        approveValueBinding( const ::com::sun::star::uno::Reference< ::com::sun::star::form::binding::XValueBinding >& _rxBinding );
    virtual sal_Bool        approveDbColumnType( sal_Int32 _nColumnType );

protected:
    virtual sal_uInt16 getPersistenceFlags() const;

    DECLARE_XCLONEABLE();

private:
    bool    implActsAsRichText( ) const;
};

//==================================================================
//= OEditControl
//==================================================================
typedef ::cppu::ImplHelper3<    ::com::sun::star::awt::XFocusListener,
                                ::com::sun::star::awt::XKeyListener,
                                ::com::sun::star::form::XChangeBroadcaster > OEditControl_BASE;

class OEditControl : public OBoundControl
                      ,public OEditControl_BASE
{
    ::cppu::OInterfaceContainerHelper
                        m_aChangeListeners;

    ::rtl::OUString         m_aHtmlChangeValue;
    sal_uInt32              m_nKeyEvent;

public:
    OEditControl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);
    virtual ~OEditControl();

    DECLARE_UNO3_AGG_DEFAULTS(OEditControl, OBoundControl);
    virtual ::com::sun::star::uno::Any SAL_CALL queryAggregation(const ::com::sun::star::uno::Type& _rType) throw(::com::sun::star::uno::RuntimeException);

    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

// OComponentHelper
    virtual void SAL_CALL disposing();

// ::com::sun::star::lang::XEventListener
    virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& _rSource) throw(::com::sun::star::uno::RuntimeException);

// ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OEditControl);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

// ::com::sun::star::form::XChangeBroadcaster
    virtual void SAL_CALL addChangeListener(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XChangeListener>& _rxListener) throw ( ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeChangeListener(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XChangeListener>& _rxListener) throw ( ::com::sun::star::uno::RuntimeException);

// ::com::sun::star::awt::XFocusListener
    virtual void SAL_CALL focusGained( const ::com::sun::star::awt::FocusEvent& e ) throw ( ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL focusLost( const ::com::sun::star::awt::FocusEvent& e ) throw ( ::com::sun::star::uno::RuntimeException);

// ::com::sun::star::awt::XKeyListener
    virtual void SAL_CALL keyPressed(const ::com::sun::star::awt::KeyEvent& e) throw ( ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL keyReleased(const ::com::sun::star::awt::KeyEvent& e) throw ( ::com::sun::star::uno::RuntimeException);

    // XControl
    virtual void SAL_CALL createPeer( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit >& _rxToolkit, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer >& _rxParent ) throw ( ::com::sun::star::uno::RuntimeException );

private:
    DECL_LINK( OnKeyPressed, void* );
};

//.........................................................................
}
//.........................................................................

#endif // _FORMS_EDIT_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.16.42); FILE MERGED 2008/03/31 13:11:32 rt 1.16.42.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: Edit.hxx,v $
 * $Revision: 1.17 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _FORMS_EDIT_HXX_
#define _FORMS_EDIT_HXX_

#include "EditBase.hxx"

#include <cppuhelper/implbase3.hxx>

namespace dbtools { class FormattedColumnValue; }

//.........................................................................
namespace frm
{

//==================================================================
//= OEditModel
//==================================================================
class OEditModel
                :public OEditBaseModel
{
    ::rtl::OUString             m_aSaveValue;
    ::std::auto_ptr< ::dbtools::FormattedColumnValue >
                                m_pValueFormatter;
    sal_Bool                    m_bMaxTextLenModified : 1;  // set to <TRUE/> when we change the MaxTextLen of the aggregate

    sal_Bool                    m_bWritingFormattedFake : 1;
        // are we writing something which should be interpreted as formatted upon reading?

protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

    DECLARE_DEFAULT_LEAF_XTOR( OEditModel );

    void enableFormattedWriteFake() { m_bWritingFormattedFake = sal_True; }
    void disableFormattedWriteFake() { m_bWritingFormattedFake = sal_False; }
    sal_Bool lastReadWasFormattedFake() const { return (getLastReadVersion() & PF_FAKE_FORMATTED_FIELD) != 0; }

    friend InterfaceRef SAL_CALL OEditModel_CreateInstance(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);
    friend class OFormattedFieldWrapper;
    friend class OFormattedModel;   // temporary

public:
    virtual void SAL_CALL disposing();

    // XPropertySet
    virtual void SAL_CALL getFastPropertyValue(::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const;

    // XPersistObject
    virtual void SAL_CALL write(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL read(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun::star::uno::RuntimeException);

    // XPropertySet
    using OBoundControlModel::getFastPropertyValue;

    // XReset
    virtual void SAL_CALL reset(  ) throw(::com::sun::star::uno::RuntimeException);

    // XServiceInfo
    IMPLEMENTATION_NAME(OEditModel);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

    // OControlModel's property handling
    virtual void describeFixedProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps
    ) const;
    virtual void describeAggregateProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rAggregateProps
    ) const;

    // XEventListener
    using OBoundControlModel::disposing;

protected:
    // OControlModel overridables
    virtual void writeAggregate( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream >& _rxOutStream ) const;
    virtual void readAggregate( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream >& _rxInStream );

    // OBoundControlModel overridables
    virtual ::com::sun::star::uno::Any
                            translateDbColumnToControlValue( );
    virtual sal_Bool        commitControlValueToDbColumn( bool _bPostReset );

    virtual ::com::sun::star::uno::Any
                            getDefaultForReset() const;

    virtual void            onConnectedDbColumn( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxForm );
    virtual void            onDisconnectedDbColumn();

    virtual sal_Bool        approveValueBinding( const ::com::sun::star::uno::Reference< ::com::sun::star::form::binding::XValueBinding >& _rxBinding );
    virtual sal_Bool        approveDbColumnType( sal_Int32 _nColumnType );

protected:
    virtual sal_uInt16 getPersistenceFlags() const;

    DECLARE_XCLONEABLE();

private:
    bool    implActsAsRichText( ) const;
};

//==================================================================
//= OEditControl
//==================================================================
typedef ::cppu::ImplHelper3<    ::com::sun::star::awt::XFocusListener,
                                ::com::sun::star::awt::XKeyListener,
                                ::com::sun::star::form::XChangeBroadcaster > OEditControl_BASE;

class OEditControl : public OBoundControl
                      ,public OEditControl_BASE
{
    ::cppu::OInterfaceContainerHelper
                        m_aChangeListeners;

    ::rtl::OUString         m_aHtmlChangeValue;
    sal_uInt32              m_nKeyEvent;

public:
    OEditControl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);
    virtual ~OEditControl();

    DECLARE_UNO3_AGG_DEFAULTS(OEditControl, OBoundControl);
    virtual ::com::sun::star::uno::Any SAL_CALL queryAggregation(const ::com::sun::star::uno::Type& _rType) throw(::com::sun::star::uno::RuntimeException);

    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

// OComponentHelper
    virtual void SAL_CALL disposing();

// ::com::sun::star::lang::XEventListener
    virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& _rSource) throw(::com::sun::star::uno::RuntimeException);

// ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OEditControl);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

// ::com::sun::star::form::XChangeBroadcaster
    virtual void SAL_CALL addChangeListener(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XChangeListener>& _rxListener) throw ( ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeChangeListener(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XChangeListener>& _rxListener) throw ( ::com::sun::star::uno::RuntimeException);

// ::com::sun::star::awt::XFocusListener
    virtual void SAL_CALL focusGained( const ::com::sun::star::awt::FocusEvent& e ) throw ( ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL focusLost( const ::com::sun::star::awt::FocusEvent& e ) throw ( ::com::sun::star::uno::RuntimeException);

// ::com::sun::star::awt::XKeyListener
    virtual void SAL_CALL keyPressed(const ::com::sun::star::awt::KeyEvent& e) throw ( ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL keyReleased(const ::com::sun::star::awt::KeyEvent& e) throw ( ::com::sun::star::uno::RuntimeException);

    // XControl
    virtual void SAL_CALL createPeer( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit >& _rxToolkit, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer >& _rxParent ) throw ( ::com::sun::star::uno::RuntimeException );

private:
    DECL_LINK( OnKeyPressed, void* );
};

//.........................................................................
}
//.........................................................................

#endif // _FORMS_EDIT_HXX_

<|endoftext|>


<commit_before><commit_msg>fixed a typeo<commit_after><|endoftext|>


<commit_before>//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that aims to be a dropin replacement for
// Darwin's dsymutil.
//
//===----------------------------------------------------------------------===//

#include "DebugMap.h"
#include "dsymutil.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <string>

using namespace llvm::dsymutil;

namespace {
using namespace llvm::cl;

static opt<std::string> InputFile(Positional, desc("<input file>"),
                                  init("a.out"));

static opt<std::string> OsoPrependPath("oso-prepend-path",
                                       desc("Specify a directory to prepend "
                                            "to the paths of object files."),
                                       value_desc("path"));

static opt<bool> Verbose("v", desc("Verbosity level"), init(false));

static opt<bool>
    ParseOnly("parse-only",
              desc("Only parse the debug map, do not actaully link "
                   "the DWARF."),
              init(false));
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
  llvm::llvm_shutdown_obj Shutdown;

  llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n");
  auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose);

  if (auto EC = DebugMapPtrOrErr.getError()) {
    llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
                 << "\": " << EC.message() << '\n';
    return 1;
  }

  if (Verbose)
    (*DebugMapPtrOrErr)->print(llvm::outs());

  if (ParseOnly)
    return 0;

  std::string OutputBasename(InputFile);
  if (OutputBasename == "-")
    OutputBasename = "a.out";

  return !linkDwarf(OutputBasename + ".dwarf", **DebugMapPtrOrErr, Verbose);
}
<commit_msg>[dsymutil] Add -o option to select ouptut filename<commit_after>//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that aims to be a dropin replacement for
// Darwin's dsymutil.
//
//===----------------------------------------------------------------------===//

#include "DebugMap.h"
#include "dsymutil.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <string>

using namespace llvm::dsymutil;

namespace {
using namespace llvm::cl;

static opt<std::string> InputFile(Positional, desc("<input file>"),
                                  init("a.out"));

static opt<std::string> OutputFileOpt("o", desc("Specify the output file."
                                                " default: <input file>.dwarf"),
                                      value_desc("filename"));

static opt<std::string> OsoPrependPath("oso-prepend-path",
                                       desc("Specify a directory to prepend "
                                            "to the paths of object files."),
                                       value_desc("path"));

static opt<bool> Verbose("v", desc("Verbosity level"), init(false));

static opt<bool>
    ParseOnly("parse-only",
              desc("Only parse the debug map, do not actaully link "
                   "the DWARF."),
              init(false));
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
  llvm::llvm_shutdown_obj Shutdown;

  llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n");
  auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose);

  if (auto EC = DebugMapPtrOrErr.getError()) {
    llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
                 << "\": " << EC.message() << '\n';
    return 1;
  }

  if (Verbose)
    (*DebugMapPtrOrErr)->print(llvm::outs());

  if (ParseOnly)
    return 0;

  std::string OutputFile;
  if (OutputFileOpt.empty()) {
    if (InputFile == "-")
      OutputFile = "a.out.dwarf";
    else
      OutputFile = InputFile + ".dwarf";
  } else {
    OutputFile = OutputFileOpt;
  }

  return !linkDwarf(OutputFile, **DebugMapPtrOrErr, Verbose);
}
<|endoftext|>


<commit_before>#include <experimental/filesystem>
#include <fstream>
#include <string>
#include <vector>

#include "glog/logging.h"
#include "google/protobuf/descriptor.h"
#include "serialization/journal.pb.h"

namespace principia {

using ::google::protobuf::Descriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::FieldOptions;
using ::google::protobuf::FileDescriptor;

namespace tools {

namespace {
char const kIn[] = "In";
char const kReturn[] = "Return";
char const kOut[] = "Out";

class Generator {
 public:
  void ProcessMethods();

  std::vector<std::string> GetCppMethodTypes() const;

 private:
  void ProcessRepeatedMessageField(FieldDescriptor const* descriptor);

  void ProcessOptionalInt32Field(FieldDescriptor const* descriptor);

  void ProcessRequiredFixed64Field(FieldDescriptor const* descriptor);

  void ProcessRequiredMessageField(FieldDescriptor const* descriptor);

  void ProcessRequiredBoolField(FieldDescriptor const* descriptor);

  void ProcessRequiredDoubleField(FieldDescriptor const* descriptor);

  void ProcessRequiredInt32Field(FieldDescriptor const* descriptor);

  void ProcessSingleStringField(FieldDescriptor const* descriptor);

  void ProcessOptionalField(FieldDescriptor const* descriptor);

  void ProcessRepeatedField(FieldDescriptor const* descriptor);

  void ProcessRequiredField(FieldDescriptor const* descriptor);

  void ProcessField(FieldDescriptor const* descriptor);

  void ProcessInOut(Descriptor const* descriptor,
                    std::vector<FieldDescriptor const*>* field_descriptors);

  void ProcessReturn(Descriptor const* descriptor);

  void ProcessMethodExtension(Descriptor const* descriptor);

 private:
  std::map<Descriptor const*, std::string> cpp_method_type_;
  std::map<FieldDescriptor const*, std::string> size_field_;
  std::set<FieldDescriptor const*> in_out_field_;
  std::map<Descriptor const*, std::string> cpp_nested_type_;
  std::map<FieldDescriptor const*, std::string> cpp_field_type_;
};

void Generator::ProcessMethods() {
  // Get the file containing |Method|.
  Descriptor const* method_descriptor = serialization::Method::descriptor();
  FileDescriptor const* file_descriptor = method_descriptor->file();

  // Process all the messages in that file.
  for (int i = 0; i < file_descriptor->message_type_count(); ++i) {
    Descriptor const* message_descriptor = file_descriptor->message_type(i);
    switch (message_descriptor->extension_count()) {
    case 0: {
      // An auxiliary message that is not an extension.  Nothing to do.
      break;
    }
    case 1: {
      // An extension.  Check that it extends |Method|.
      FieldDescriptor const* extension = message_descriptor->extension(0);
      CHECK(extension->is_extension());
      Descriptor const* containing_type = extension->containing_type();
      CHECK_EQ(method_descriptor, containing_type)
        << message_descriptor->name() << " extends a message other than "
        << method_descriptor->name() << ": " << containing_type->name();
      ProcessMethodExtension(message_descriptor);
      break;
    }
    default: {
      LOG(FATAL) << message_descriptor->name() << " has "
        << message_descriptor->extension_count() << " extensions";
    }
    }
  }
}

std::vector<std::string> Generator::GetCppMethodTypes() const {
  std::vector<std::string> result;
  for (auto const& pair : cpp_method_type_) {
    result.push_back(pair.second);
  }
  return result;
}

void Generator::ProcessRepeatedMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name() +
    " const*";
}

void Generator::ProcessOptionalInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int const*";
}

void Generator::ProcessRequiredFixed64Field(FieldDescriptor const* descriptor) {
  FieldOptions const& options = descriptor->options();
  CHECK(options.HasExtension(serialization::pointer_to))
    << descriptor->full_name() << " is missing a pointer_to option";
  std::string const& pointer_to =
    options.GetExtension(serialization::pointer_to);
  cpp_field_type_[descriptor] = pointer_to + "*";
}

void Generator::ProcessRequiredMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name();
}

void Generator::ProcessRequiredBoolField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
}

void Generator::ProcessRequiredDoubleField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
}

void Generator::ProcessRequiredInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int";
}

void Generator::ProcessSingleStringField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "char const*";
}

void Generator::ProcessOptionalField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
  case FieldDescriptor::TYPE_INT32:
    ProcessOptionalInt32Field(descriptor);
    break;
  case FieldDescriptor::TYPE_STRING:
    ProcessSingleStringField(descriptor);
    break;
  default:
    LOG(FATAL) << descriptor->full_name() << " has unexpected type "
      << descriptor->type_name();
  }
}

void Generator::ProcessRepeatedField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
  case FieldDescriptor::TYPE_MESSAGE:
    ProcessRepeatedMessageField(descriptor);
    break;
  default:
    LOG(FATAL) << descriptor->full_name() << " has unexpected type "
      << descriptor->type_name();
  }
}

void Generator::ProcessRequiredField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
  case FieldDescriptor::TYPE_BOOL:
    ProcessRequiredBoolField(descriptor);
    break;
  case FieldDescriptor::TYPE_DOUBLE:
    ProcessRequiredDoubleField(descriptor);
    break;
  case FieldDescriptor::TYPE_FIXED64:
    ProcessRequiredFixed64Field(descriptor);
    break;
  case FieldDescriptor::TYPE_INT32:
    ProcessRequiredInt32Field(descriptor);
    break;
  case FieldDescriptor::TYPE_MESSAGE:
    ProcessRequiredMessageField(descriptor);
    break;
  case FieldDescriptor::TYPE_STRING:
    ProcessSingleStringField(descriptor);
    break;
  default:
    LOG(FATAL) << descriptor->full_name() << " has unexpected type "
      << descriptor->type_name();
  }

  // For in-out fields the data is actually passed with an extra level of
  // indirection.
  if (in_out_field_.find(descriptor) != in_out_field_.end()) {
    cpp_field_type_[descriptor] += "*";
  }
}

void Generator::ProcessField(FieldDescriptor const* descriptor) {
  switch (descriptor->label()) {
  case FieldDescriptor::LABEL_OPTIONAL:
    ProcessOptionalField(descriptor);
    break;
  case FieldDescriptor::LABEL_REPEATED:
    ProcessRepeatedField(descriptor);
    break;
  case FieldDescriptor::LABEL_REQUIRED:
    ProcessRequiredField(descriptor);
    break;
  }
  FieldOptions const& options = descriptor->options();
  if (options.HasExtension(serialization::size)) {
    size_field_[descriptor] = options.GetExtension(serialization::size);
  }
}

void Generator::ProcessInOut(Descriptor const* descriptor,
                  std::vector<FieldDescriptor const*>* field_descriptors) {
  cpp_nested_type_[descriptor] = "  struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->field_count(); ++i) {
    FieldDescriptor const* field_descriptor = descriptor->field(i);
    if (field_descriptors != nullptr) {
      field_descriptors->push_back(field_descriptor);
    }
    ProcessField(field_descriptor);
    cpp_nested_type_[descriptor] += "    " +
      cpp_field_type_[field_descriptor] +
      " const " +
      field_descriptor->name() + ";\n";

    // This this field has a size, generate it now.
    if (size_field_.find(field_descriptor) != size_field_.end()) {
      cpp_nested_type_[descriptor] += "    int const " +
        size_field_[field_descriptor] + ";\n";
    }
  }
  cpp_nested_type_[descriptor] += "  };\n";
}

void Generator::ProcessReturn(Descriptor const* descriptor) {
  CHECK_EQ(1, descriptor->field_count())
    << descriptor->full_name() << " must have exactly one field";
  FieldDescriptor const* field_descriptor = descriptor->field(0);
  ProcessField(field_descriptor);
  cpp_nested_type_[descriptor] =
    "  using Return = " + cpp_field_type_[field_descriptor] + ";\n";
}

void Generator::ProcessMethodExtension(Descriptor const* descriptor) {
  bool has_in = false;
  bool has_out = false;
  bool has_return = false;

  // Do a first pass to determine which fields are in-out.  The data produced
  // here will be overwritten by the next pass.
  std::vector<FieldDescriptor const*> field_descriptors;
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      has_in = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kOut) {
      has_out = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kReturn) {
      has_return = true;
    } else {
      LOG(FATAL) << "Unexpected nested message "
        << nested_descriptor->full_name();
    }
  }

  // Now mark the fields that have the same name in In and Out as in-out.
  if (has_in || has_out) {
    std::sort(field_descriptors.begin(),
              field_descriptors.end(),
              [](FieldDescriptor const* left,
                 FieldDescriptor const* right) {
      return left->name() < right->name();
    });
    for (int i = 0; i < field_descriptors.size() - 1; ++i) {
      if (field_descriptors[i]->name() == field_descriptors[i + 1]->name()) {
        in_out_field_.insert(field_descriptors[i]);
        in_out_field_.insert(field_descriptors[i + 1]);
      }
    }
  }

  // The second pass that produces the actual output.
  cpp_method_type_[descriptor] = "struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kOut) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kReturn) {
      ProcessReturn(nested_descriptor);
    }
    cpp_method_type_[descriptor] += cpp_nested_type_[nested_descriptor];
  }
  if (has_in || has_out || has_return) {
    cpp_method_type_[descriptor] += "\n";
  }
  cpp_method_type_[descriptor] +=
    std::string("  using Message = serialization::") +
    descriptor->name() + ";\n";
  if (has_in) {
    cpp_method_type_[descriptor] += "  static void Generator::Fill(In const& in, "
      "not_null<Message*> const message);\n";
  }
  if (has_out) {
    cpp_method_type_[descriptor] += "  static void Generator::Fill(Out const& out, "
      "not_null<Message*> const message);\n";
  }
  if (has_return) {
    cpp_method_type_[descriptor] += "  static void Generator::Fill("
      "Return const& result, "
      "not_null<Message*> const message);\n";
  }
  cpp_method_type_[descriptor] += "  static void Generator::Run("
    "Message const& message,\n"
    "                  not_null<"
    "Player::PointerMap*> const pointer_map);"
    "\n";
  cpp_method_type_[descriptor] += "};\n\n";
}

}  // namespace

void GenerateProfiles() {
  Generator generator;
  generator.ProcessMethods();

  // Now write the output.
  std::experimental::filesystem::path const directory =
      SOLUTION_DIR / "journal";
  std::ofstream profiles_hpp(directory / "profiles.hpp");
  CHECK(profiles_hpp.good());

  profiles_hpp << "#pragma once\n";
  profiles_hpp << "\n";
  profiles_hpp << "#include \"base/not_null.hpp\"\n";
  profiles_hpp << "#include \"journal/player.hpp\"\n";
  profiles_hpp << "#include \"ksp_plugin/interface.hpp\"\n";
  profiles_hpp << "#include \"serialization/journal.pb.h\"\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace principia {\n";
  profiles_hpp << "\n";
  profiles_hpp << "using base::not_null;\n";
  profiles_hpp << "using ksp_plugin::KSPPart;\n";
  profiles_hpp << "using ksp_plugin::LineAndIterator;\n";
  profiles_hpp << "using ksp_plugin::NavigationFrame;\n";
  profiles_hpp << "using ksp_plugin::Plugin;\n";
  profiles_hpp << "using ksp_plugin::QP;\n";
  profiles_hpp << "using ksp_plugin::WXYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZSegment;\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace journal {\n";
  profiles_hpp << "\n";

  for (auto const& cpp_method_type : generator.GetCppMethodTypes()) {
    profiles_hpp << cpp_method_type;
  }

  profiles_hpp << "}  // namespace journal\n";
  profiles_hpp << "}  // namespace principia\n";
}

}  // namespace tools
}  // namespace principia
<commit_msg>Cleanup.<commit_after>#include <experimental/filesystem>
#include <fstream>
#include <string>
#include <vector>

#include "glog/logging.h"
#include "google/protobuf/descriptor.h"
#include "serialization/journal.pb.h"

namespace principia {

using ::google::protobuf::Descriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::FieldOptions;
using ::google::protobuf::FileDescriptor;

namespace tools {

namespace {
char const kIn[] = "In";
char const kReturn[] = "Return";
char const kOut[] = "Out";

class Generator {
 public:
  void ProcessMethods();

  std::vector<std::string> GetCppMethodTypes() const;

 private:
  void ProcessRepeatedMessageField(FieldDescriptor const* descriptor);

  void ProcessOptionalInt32Field(FieldDescriptor const* descriptor);

  void ProcessRequiredFixed64Field(FieldDescriptor const* descriptor);

  void ProcessRequiredMessageField(FieldDescriptor const* descriptor);

  void ProcessRequiredBoolField(FieldDescriptor const* descriptor);

  void ProcessRequiredDoubleField(FieldDescriptor const* descriptor);

  void ProcessRequiredInt32Field(FieldDescriptor const* descriptor);

  void ProcessSingleStringField(FieldDescriptor const* descriptor);

  void ProcessOptionalField(FieldDescriptor const* descriptor);

  void ProcessRepeatedField(FieldDescriptor const* descriptor);

  void ProcessRequiredField(FieldDescriptor const* descriptor);

  void ProcessField(FieldDescriptor const* descriptor);

  void ProcessInOut(Descriptor const* descriptor,
                    std::vector<FieldDescriptor const*>* field_descriptors);

  void ProcessReturn(Descriptor const* descriptor);

  void ProcessMethodExtension(Descriptor const* descriptor);

 private:
  std::map<Descriptor const*, std::string> cpp_method_type_;
  std::map<FieldDescriptor const*, std::string> size_field_;
  std::set<FieldDescriptor const*> in_out_field_;
  std::map<Descriptor const*, std::string> cpp_nested_type_;
  std::map<FieldDescriptor const*, std::string> cpp_field_type_;
};

void Generator::ProcessMethods() {
  // Get the file containing |Method|.
  Descriptor const* method_descriptor = serialization::Method::descriptor();
  FileDescriptor const* file_descriptor = method_descriptor->file();

  // Process all the messages in that file.
  for (int i = 0; i < file_descriptor->message_type_count(); ++i) {
    Descriptor const* message_descriptor = file_descriptor->message_type(i);
    switch (message_descriptor->extension_count()) {
      case 0: {
        // An auxiliary message that is not an extension.  Nothing to do.
        break;
    }
    case 1: {
      // An extension.  Check that it extends |Method|.
      FieldDescriptor const* extension = message_descriptor->extension(0);
      CHECK(extension->is_extension());
      Descriptor const* containing_type = extension->containing_type();
      CHECK_EQ(method_descriptor, containing_type)
          << message_descriptor->name() << " extends a message other than "
          << method_descriptor->name() << ": " << containing_type->name();
      ProcessMethodExtension(message_descriptor);
      break;
    }
    default: {
      LOG(FATAL) << message_descriptor->name() << " has "
          << message_descriptor->extension_count() << " extensions";
    }
    }
  }
}

std::vector<std::string> Generator::GetCppMethodTypes() const {
  std::vector<std::string> result;
  for (auto const& pair : cpp_method_type_) {
    result.push_back(pair.second);
  }
  return result;
}

void Generator::ProcessRepeatedMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name() +
                                " const*";
}

void Generator::ProcessOptionalInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int const*";
}

void Generator::ProcessRequiredFixed64Field(FieldDescriptor const* descriptor) {
  FieldOptions const& options = descriptor->options();
  CHECK(options.HasExtension(serialization::pointer_to))
      << descriptor->full_name() << " is missing a pointer_to option";
  std::string const& pointer_to =
      options.GetExtension(serialization::pointer_to);
  cpp_field_type_[descriptor] = pointer_to + "*";
}

void Generator::ProcessRequiredMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name();
}

void Generator::ProcessRequiredBoolField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
}

void Generator::ProcessRequiredDoubleField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
}

void Generator::ProcessRequiredInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int";
}

void Generator::ProcessSingleStringField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "char const*";
}

void Generator::ProcessOptionalField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_INT32:
      ProcessOptionalInt32Field(descriptor);
      break;
    case FieldDescriptor::TYPE_STRING:
      ProcessSingleStringField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }
}

void Generator::ProcessRepeatedField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_MESSAGE:
      ProcessRepeatedMessageField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }
}

void Generator::ProcessRequiredField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_BOOL:
      ProcessRequiredBoolField(descriptor);
      break;
    case FieldDescriptor::TYPE_DOUBLE:
      ProcessRequiredDoubleField(descriptor);
      break;
    case FieldDescriptor::TYPE_FIXED64:
      ProcessRequiredFixed64Field(descriptor);
      break;
    case FieldDescriptor::TYPE_INT32:
      ProcessRequiredInt32Field(descriptor);
      break;
    case FieldDescriptor::TYPE_MESSAGE:
      ProcessRequiredMessageField(descriptor);
      break;
    case FieldDescriptor::TYPE_STRING:
      ProcessSingleStringField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }

  // For in-out fields the data is actually passed with an extra level of
  // indirection.
  if (in_out_field_.find(descriptor) != in_out_field_.end()) {
    cpp_field_type_[descriptor] += "*";
  }
}

void Generator::ProcessField(FieldDescriptor const* descriptor) {
  switch (descriptor->label()) {
    case FieldDescriptor::LABEL_OPTIONAL:
      ProcessOptionalField(descriptor);
      break;
    case FieldDescriptor::LABEL_REPEATED:
      ProcessRepeatedField(descriptor);
      break;
    case FieldDescriptor::LABEL_REQUIRED:
      ProcessRequiredField(descriptor);
      break;
  }
  FieldOptions const& options = descriptor->options();
  if (options.HasExtension(serialization::size)) {
    size_field_[descriptor] = options.GetExtension(serialization::size);
  }
}

void Generator::ProcessInOut(Descriptor const* descriptor,
                  std::vector<FieldDescriptor const*>* field_descriptors) {
  cpp_nested_type_[descriptor] = "  struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->field_count(); ++i) {
    FieldDescriptor const* field_descriptor = descriptor->field(i);
    if (field_descriptors != nullptr) {
      field_descriptors->push_back(field_descriptor);
    }
    ProcessField(field_descriptor);
    cpp_nested_type_[descriptor] += "    " +
                                    cpp_field_type_[field_descriptor] +
                                    " const " +
                                    field_descriptor->name() + ";\n";

    // This this field has a size, generate it now.
    if (size_field_.find(field_descriptor) != size_field_.end()) {
      cpp_nested_type_[descriptor] += "    int const " +
                                      size_field_[field_descriptor] + ";\n";
    }
  }
  cpp_nested_type_[descriptor] += "  };\n";
}

void Generator::ProcessReturn(Descriptor const* descriptor) {
  CHECK_EQ(1, descriptor->field_count())
    << descriptor->full_name() << " must have exactly one field";
  FieldDescriptor const* field_descriptor = descriptor->field(0);
  ProcessField(field_descriptor);
  cpp_nested_type_[descriptor] =
      "  using Return = " + cpp_field_type_[field_descriptor] + ";\n";
}

void Generator::ProcessMethodExtension(Descriptor const* descriptor) {
  bool has_in = false;
  bool has_out = false;
  bool has_return = false;

  // Do a first pass to determine which fields are in-out.  The data produced
  // here will be overwritten by the next pass.
  std::vector<FieldDescriptor const*> field_descriptors;
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      has_in = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kOut) {
      has_out = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kReturn) {
      has_return = true;
    } else {
      LOG(FATAL) << "Unexpected nested message "
                 << nested_descriptor->full_name();
    }
  }

  // Now mark the fields that have the same name in In and Out as in-out.
  if (has_in || has_out) {
    std::sort(field_descriptors.begin(),
              field_descriptors.end(),
              [](FieldDescriptor const* left,
                 FieldDescriptor const* right) {
      return left->name() < right->name();
    });
    for (int i = 0; i < field_descriptors.size() - 1; ++i) {
      if (field_descriptors[i]->name() == field_descriptors[i + 1]->name()) {
        in_out_field_.insert(field_descriptors[i]);
        in_out_field_.insert(field_descriptors[i + 1]);
      }
    }
  }

  // The second pass that produces the actual output.
  cpp_method_type_[descriptor] = "struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kOut) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kReturn) {
      ProcessReturn(nested_descriptor);
    }
    cpp_method_type_[descriptor] += cpp_nested_type_[nested_descriptor];
  }
  if (has_in || has_out || has_return) {
    cpp_method_type_[descriptor] += "\n";
  }
  cpp_method_type_[descriptor] +=
      "  using Message = serialization::" +
      descriptor->name() + ";\n";
  if (has_in) {
    cpp_method_type_[descriptor] += "  static void Fill(In const& in, "
                                    "not_null<Message*> const message);\n";
  }
  if (has_out) {
    cpp_method_type_[descriptor] += "  static void Fill(Out const& out, "
                                    "not_null<Message*> const message);\n";
  }
  if (has_return) {
    cpp_method_type_[descriptor] += "  static void Fill("
                                    "Return const& result, "
                                    "not_null<Message*> const message);\n";
  }
  cpp_method_type_[descriptor] += "  static void Run("
                                  "Message const& message,\n"
                                  "                  not_null<"
                                  "Player::PointerMap*> const pointer_map);"
                                  "\n";
  cpp_method_type_[descriptor] += "};\n\n";
}

}  // namespace

void GenerateProfiles() {
  Generator generator;
  generator.ProcessMethods();

  // Now write the output.
  std::experimental::filesystem::path const directory =
      SOLUTION_DIR / "journal";
  std::ofstream profiles_hpp(directory / "profiles.hpp");
  CHECK(profiles_hpp.good());

  profiles_hpp << "#pragma once\n";
  profiles_hpp << "\n";
  profiles_hpp << "#include \"base/not_null.hpp\"\n";
  profiles_hpp << "#include \"journal/player.hpp\"\n";
  profiles_hpp << "#include \"ksp_plugin/interface.hpp\"\n";
  profiles_hpp << "#include \"serialization/journal.pb.h\"\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace principia {\n";
  profiles_hpp << "\n";
  profiles_hpp << "using base::not_null;\n";
  profiles_hpp << "using ksp_plugin::KSPPart;\n";
  profiles_hpp << "using ksp_plugin::LineAndIterator;\n";
  profiles_hpp << "using ksp_plugin::NavigationFrame;\n";
  profiles_hpp << "using ksp_plugin::Plugin;\n";
  profiles_hpp << "using ksp_plugin::QP;\n";
  profiles_hpp << "using ksp_plugin::WXYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZSegment;\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace journal {\n";
  profiles_hpp << "\n";

  for (auto const& cpp_method_type : generator.GetCppMethodTypes()) {
    profiles_hpp << cpp_method_type;
  }

  profiles_hpp << "}  // namespace journal\n";
  profiles_hpp << "}  // namespace principia\n";
}

}  // namespace tools
}  // namespace principia
<|endoftext|>