<commit_before>/*
 * Copyright (c) 2010 Eduard Burtescu
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <machine/HidInputManager.h>
#include <usb/UsbHub.h>
#include <usb/UsbDevice.h>
#include "UsbHumanInterfaceDevice.h"

#define undefined -0xffffffff

#define _sign(x) (x>=0?"+":"- ")<<(x>=0?x:-x)

static inline uint64_t _getField(uint8_t *pBuffer, size_t nStart, size_t nLength)
{
    uint64_t nValue = 0;
    size_t i = 0;
    while(i < nLength)
    {
        uint8_t nBits = ((nStart % 8) + nLength - i) < 8 ? nLength % 8 : 8 - (nStart % 8);
        nValue |= ((pBuffer[nStart / 8] >> (nStart % 8)) & ((1 << nBits) - 1)) << i;
        i += nBits;
        nStart += nBits;
    }
    return nValue;
}

static inline int64_t _uint2int(uint64_t val, uint8_t len)
{
    // Check for the most significant bit, it shows the sign
    if(val & (1 << (len - 1)))
        return -((1 << len) - val); // Negative value
    return val; // Positive value
}

UsbHumanInterfaceDevice::UsbHumanInterfaceDevice(UsbDevice *pDev) : Device(pDev), UsbDevice(pDev)
{
    HidDescriptor *pHidDescriptor = 0;
    for(size_t i = 0;i < m_pInterface->pOtherDescriptors.count();i++)
    {
        UnknownDescriptor *pDescriptor = m_pInterface->pOtherDescriptors[i];
        if(pDescriptor->nType == 0x21)
        {
            pHidDescriptor = new HidDescriptor(pDescriptor);
            break;
        }
    }
    if(!pHidDescriptor)
    {
        ERROR("USB: HID: No HID descriptor");
        return;
    }

    /// \bug WMware's mouse's second interface is known to cause problems
    if(m_pDescriptor->pDescriptor->nVendorId == 0x0e0f && m_pInterface->pDescriptor->nInterface)
        return;

    // Disable BIOS stuff
    //controlRequest(RequestType::Class | RequestRecipient::Interface, Request::SetInterface, 0, m_pInterface->pDescriptor->nInterface);
    // Set Idle Rate to 0
    controlRequest(RequestType::Class | RequestRecipient::Interface, Request::GetInterface, 0, 0);

    uint16_t nHidSize = pHidDescriptor->pDescriptor->nDescriptorLength;
    uint8_t *pHidReportDescriptor = static_cast<uint8_t*>(getDescriptor(0x22, 0, nHidSize, RequestRecipient::Interface));
    int64_t nLogMin = undefined, nLogMax = undefined, nPhysMin = undefined, nPhysMax = undefined, nUsagePage = undefined,
            nUsageMin = undefined, nUsageMax = undefined, nReportSize = undefined, nReportCount = undefined;
    uint8_t nLogSize = 0;
    uint32_t nBits = 0;
    m_pReport = new HidReport();
    Vector<size_t> *pUsages = new Vector<size_t>();
    for(size_t i = 0; i < nHidSize; i++)
    {
        union
        {
            struct
            {
                uint8_t size : 2;
                uint8_t type : 2;
                uint8_t tag : 4;
            } PACKED;
            uint8_t raw;
        } item;
        item.raw = pHidReportDescriptor[i];
        uint8_t size = item.size == 3 ? 4 : item.size;
        uint32_t value = 0;
        if(size == 1)
            value = pHidReportDescriptor[i + 1];
        else if(size == 2)
            value = pHidReportDescriptor[i + 1] | (pHidReportDescriptor[i + 2] << 8);
        else if(size == 4)
            value = pHidReportDescriptor[i + 1] | (pHidReportDescriptor[i + 2] << 8) | (pHidReportDescriptor[i + 3] << 16) | (pHidReportDescriptor[i + 4] << 24);
#ifdef USB_VERBOSE_DEBUG
        DEBUG_LOG("USB: HID: Item tag=" << item.tag << " type=" << Dec << item.type << " size=" << size << Hex);
#endif
        switch(item.type)
        {
            case 0:
                switch(item.tag)
                {
                    case 0x8:
                        HidReportBlock *pBlock = new HidReportBlock();
                        pBlock->nCount = nReportCount;
                        pBlock->nSize = nReportSize;
                        if(value & 1)
                        {
                            pBlock->type = HidReportBlock::Ignore;
                        }
                        else
                        {
                            pBlock->nUsagePage = nUsagePage;
                            pBlock->nLogSize = nLogSize;
                            if(value & 2)
                            {
                                for(size_t j = 0; pUsages->count() < nReportCount; j++)
                                    pUsages->pushBack(nUsageMin + j);
                                pBlock->pUsages = pUsages;
                                if(value & 4)
                                    pBlock->type = HidReportBlock::Relative;
                                else
                                    pBlock->type = HidReportBlock::Absolute;
                            }
                            else
                            {
                                pBlock->type = HidReportBlock::Array;
                                pBlock->nUsageBase = nUsageMin;
                            }
                        }
                        m_pReport->pBlockList.pushBack(pBlock);
                        nBits += nReportSize * nReportCount;
                        nUsageMin = undefined;
                        nUsageMax = undefined;
                        pUsages = new Vector<size_t>();
                        break;
                }
                break;
            case 1:
                switch(item.tag)
                {
                    case 0x0:
                        nUsagePage = value;
                        pUsages->clear();
                        break;
                    case 0x1:
                        nLogMin = value;
                        break;
                    case 0x2:
                        nLogMax = value;
                        nLogSize = size;
                        break;
                    case 0x3:
                        nPhysMin = value;
                        break;
                    case 0x4:
                        nPhysMax = value;
                        break;
                    case 0x7:
                        nReportSize = value;
                        break;
                    case 0x9:
                        nReportCount = value;
                        break;
                }
                break;
            case 2:
                switch(item.tag)
                {
                    case 0x0:
                        pUsages->pushBack(value);
                        break;
                    case 0x1:
                        nUsageMin = value;
                        break;
                    case 0x2:
                        nUsageMax = value;
                        break;
                }
                break;
        }
        i += size;
    }
    delete pUsages;
    m_pReport->nBytes = nBits / 8;

    // Allocate the report buffers
    m_pReportBuffer = new uint8_t[m_pReport->nBytes];
    m_pOldReportBuffer = new uint8_t[m_pReport->nBytes];
    memset(m_pOldReportBuffer, 0, m_pReport->nBytes);

    Endpoint *pInEndpoint = 0;

    for(size_t i = 0; i < m_pInterface->pEndpoints.count(); i++)
    {
        Endpoint *pEndpoint = m_pInterface->pEndpoints[i];
        if(pEndpoint->nTransferType == Endpoint::Interrupt && pEndpoint->bIn)
        {
            pInEndpoint = pEndpoint;
            break;
        }
    }

    if(!pInEndpoint)
    {
        ERROR("USB: HID: No Interrupt IN endpoint");
        return;
    }

    // Add the input handler
    addInterruptInHandler(pInEndpoint, reinterpret_cast<uintptr_t>(m_pReportBuffer), m_pReport->nBytes, callback, reinterpret_cast<uintptr_t>(this));

    m_bHasDriver = true;
}

UsbHumanInterfaceDevice::~UsbHumanInterfaceDevice()
{
}

void UsbHumanInterfaceDevice::callback(uintptr_t pParam, ssize_t ret)
{
    UsbHumanInterfaceDevice *pHid = reinterpret_cast<UsbHumanInterfaceDevice*>(pParam);
    pHid->inputHandler();
}

void UsbHumanInterfaceDevice::inputHandler()
{
    //NOTICE("USB: HID: Handling input on interface " << Dec << m_pInterface->pDescriptor->nInterface << Hex);

    size_t nCurrentBit = 0;
    for(List<HidReportBlock*>::Iterator it = m_pReport->pBlockList.begin(); it != m_pReport->pBlockList.end(); it++)
    {
        HidReportBlock *pBlock = *it;
        for(size_t i = 0; pBlock->type != HidReportBlock::Ignore && i < pBlock->nCount; i++)
        {
            uint64_t nValue = _getField(m_pReportBuffer, nCurrentBit + i * pBlock->nSize, pBlock->nSize);
            int64_t nSignedValue;
            switch(pBlock->type)
            {
                case HidReportBlock::Absolute:
                    nSignedValue = nValue - _getField(m_pOldReportBuffer, nCurrentBit + i * pBlock->nSize, pBlock->nSize);

                    if(nSignedValue)
                    {
                        if(pBlock->nUsagePage == 7)
                        {
                            if(nSignedValue > 0)
                                HidInputManager::instance().keyDown((*pBlock->pUsages)[i]);
                            else
                                HidInputManager::instance().keyUp((*pBlock->pUsages)[i]);
                        }
                        else if(pBlock->nUsagePage == 9)
                        {
                            if(nSignedValue > 0)
                                NOTICE("    Button " << Dec << ((*pBlock->pUsages)[i]) << Hex << " down");
                            else
                                NOTICE("    Button " << Dec << ((*pBlock->pUsages)[i]) << Hex << " up");
                        }
                        else
                            NOTICE("    Absolute input, usage " << Dec << pBlock->nUsagePage << ":" << ((*pBlock->pUsages)[i]) << ", value " << _sign(nSignedValue) << " " << pBlock->nSize << Hex);
                    }
                    break;
                case HidReportBlock::Relative:
                    nSignedValue = _uint2int(nValue, pBlock->nLogSize * 8);

                    if(nSignedValue)
                        NOTICE("    Relative input, usage " << Dec << pBlock->nUsagePage << ":" << ((*pBlock->pUsages)[i]) << ", value " << _sign(nSignedValue) << Hex);
                    break;
                case HidReportBlock::Array:

                    if(nValue)
                    {
                        NOTICE("    Array input, usage entry " << Dec << pBlock->nUsagePage << ":" << (pBlock->nUsageBase + nValue) << Hex);

                        // Check if this array entry is new
                        bool bNew = true;
                        for(size_t j = 0; j < pBlock->nCount; j++)
                        {
                            if(_getField(m_pOldReportBuffer, nCurrentBit + j * pBlock->nSize, pBlock->nSize) == nValue)
                            {
                                bNew = false;
                                break;
                            }
                        }
                        if(bNew)
                            if(pBlock->nUsagePage == 7)
                                HidInputManager::instance().keyDown(pBlock->nUsageBase + nValue);
                    }
                case HidReportBlock::Ignore:
                default:
                    break;
            }
        }

        // Special case here: check for array entries that disapeared
        if(pBlock->type == HidReportBlock::Array)
        {
            for(size_t i = 0; i < pBlock->nCount; i++)
            {
                uint64_t nOldValue = _getField(m_pOldReportBuffer, nCurrentBit + i * pBlock->nSize, pBlock->nSize);
                if(nOldValue)
                {
                    // Check if this array entry disapeared
                    bool bDisapeared = true;
                    for(size_t j = 0; j < pBlock->nCount; j++)
                    {
                        if(_getField(m_pReportBuffer, nCurrentBit + j * pBlock->nSize, pBlock->nSize) == nOldValue)
                        {
                            bDisapeared = false;
                            break;
                        }
                    }
                    if(bDisapeared)
                        if(pBlock->nUsagePage == 7)
                            HidInputManager::instance().keyUp(pBlock->nUsageBase + nOldValue);
                }
            }
        }

        nCurrentBit += pBlock->nCount * pBlock->nSize;
    }
    memcpy(m_pOldReportBuffer, m_pReportBuffer, m_pReport->nBytes);
}
<commit_msg>Fix a memory leak in usb-hid.<commit_after>/*
 * Copyright (c) 2010 Eduard Burtescu
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <machine/HidInputManager.h>
#include <usb/UsbHub.h>
#include <usb/UsbDevice.h>
#include "UsbHumanInterfaceDevice.h"

#include <utilities/PointerGuard.h>

#define undefined -0xffffffff

#define _sign(x) (x>=0?"+":"- ")<<(x>=0?x:-x)

static inline uint64_t _getField(uint8_t *pBuffer, size_t nStart, size_t nLength)
{
    uint64_t nValue = 0;
    size_t i = 0;
    while(i < nLength)
    {
        uint8_t nBits = ((nStart % 8) + nLength - i) < 8 ? nLength % 8 : 8 - (nStart % 8);
        nValue |= ((pBuffer[nStart / 8] >> (nStart % 8)) & ((1 << nBits) - 1)) << i;
        i += nBits;
        nStart += nBits;
    }
    return nValue;
}

static inline int64_t _uint2int(uint64_t val, uint8_t len)
{
    // Check for the most significant bit, it shows the sign
    if(val & (1 << (len - 1)))
        return -((1 << len) - val); // Negative value
    return val; // Positive value
}

UsbHumanInterfaceDevice::UsbHumanInterfaceDevice(UsbDevice *pDev) : Device(pDev), UsbDevice(pDev)
{
    HidDescriptor *pHidDescriptor = 0;
    for(size_t i = 0;i < m_pInterface->pOtherDescriptors.count();i++)
    {
        UnknownDescriptor *pDescriptor = m_pInterface->pOtherDescriptors[i];
        if(pDescriptor->nType == 0x21)
        {
            pHidDescriptor = new HidDescriptor(pDescriptor);
            break;
        }
    }
    if(!pHidDescriptor)
    {
        ERROR("USB: HID: No HID descriptor");
        return;
    }

    PointerGuard<HidDescriptor> guard(pHidDescriptor);

    /// \bug WMware's mouse's second interface is known to cause problems
    if(m_pDescriptor->pDescriptor->nVendorId == 0x0e0f && m_pInterface->pDescriptor->nInterface)
        return;

    // Disable BIOS stuff
    //controlRequest(RequestType::Class | RequestRecipient::Interface, Request::SetInterface, 0, m_pInterface->pDescriptor->nInterface);
    // Set Idle Rate to 0
    controlRequest(RequestType::Class | RequestRecipient::Interface, Request::GetInterface, 0, 0);

    uint16_t nHidSize = pHidDescriptor->pDescriptor->nDescriptorLength;
    uint8_t *pHidReportDescriptor = static_cast<uint8_t*>(getDescriptor(0x22, 0, nHidSize, RequestRecipient::Interface));
    int64_t nLogMin = undefined, nLogMax = undefined, nPhysMin = undefined, nPhysMax = undefined, nUsagePage = undefined,
            nUsageMin = undefined, nUsageMax = undefined, nReportSize = undefined, nReportCount = undefined;
    uint8_t nLogSize = 0;
    uint32_t nBits = 0;
    m_pReport = new HidReport();
    Vector<size_t> *pUsages = new Vector<size_t>();
    for(size_t i = 0; i < nHidSize; i++)
    {
        union
        {
            struct
            {
                uint8_t size : 2;
                uint8_t type : 2;
                uint8_t tag : 4;
            } PACKED;
            uint8_t raw;
        } item;
        item.raw = pHidReportDescriptor[i];
        uint8_t size = item.size == 3 ? 4 : item.size;
        uint32_t value = 0;
        if(size == 1)
            value = pHidReportDescriptor[i + 1];
        else if(size == 2)
            value = pHidReportDescriptor[i + 1] | (pHidReportDescriptor[i + 2] << 8);
        else if(size == 4)
            value = pHidReportDescriptor[i + 1] | (pHidReportDescriptor[i + 2] << 8) | (pHidReportDescriptor[i + 3] << 16) | (pHidReportDescriptor[i + 4] << 24);
#ifdef USB_VERBOSE_DEBUG
        DEBUG_LOG("USB: HID: Item tag=" << item.tag << " type=" << Dec << item.type << " size=" << size << Hex);
#endif
        switch(item.type)
        {
            case 0:
                switch(item.tag)
                {
                    case 0x8:
                        HidReportBlock *pBlock = new HidReportBlock();
                        pBlock->nCount = nReportCount;
                        pBlock->nSize = nReportSize;
                        if(value & 1)
                        {
                            pBlock->type = HidReportBlock::Ignore;
                        }
                        else
                        {
                            pBlock->nUsagePage = nUsagePage;
                            pBlock->nLogSize = nLogSize;
                            if(value & 2)
                            {
                                for(size_t j = 0; pUsages->count() < nReportCount; j++)
                                    pUsages->pushBack(nUsageMin + j);
                                pBlock->pUsages = pUsages;
                                if(value & 4)
                                    pBlock->type = HidReportBlock::Relative;
                                else
                                    pBlock->type = HidReportBlock::Absolute;
                            }
                            else
                            {
                                pBlock->type = HidReportBlock::Array;
                                pBlock->nUsageBase = nUsageMin;
                            }
                        }
                        m_pReport->pBlockList.pushBack(pBlock);
                        nBits += nReportSize * nReportCount;
                        nUsageMin = undefined;
                        nUsageMax = undefined;
                        pUsages = new Vector<size_t>();
                        break;
                }
                break;
            case 1:
                switch(item.tag)
                {
                    case 0x0:
                        nUsagePage = value;
                        pUsages->clear();
                        break;
                    case 0x1:
                        nLogMin = value;
                        break;
                    case 0x2:
                        nLogMax = value;
                        nLogSize = size;
                        break;
                    case 0x3:
                        nPhysMin = value;
                        break;
                    case 0x4:
                        nPhysMax = value;
                        break;
                    case 0x7:
                        nReportSize = value;
                        break;
                    case 0x9:
                        nReportCount = value;
                        break;
                }
                break;
            case 2:
                switch(item.tag)
                {
                    case 0x0:
                        pUsages->pushBack(value);
                        break;
                    case 0x1:
                        nUsageMin = value;
                        break;
                    case 0x2:
                        nUsageMax = value;
                        break;
                }
                break;
        }
        i += size;
    }
    delete pUsages;
    m_pReport->nBytes = nBits / 8;

    // Allocate the report buffers
    m_pReportBuffer = new uint8_t[m_pReport->nBytes];
    m_pOldReportBuffer = new uint8_t[m_pReport->nBytes];
    memset(m_pOldReportBuffer, 0, m_pReport->nBytes);

    Endpoint *pInEndpoint = 0;

    for(size_t i = 0; i < m_pInterface->pEndpoints.count(); i++)
    {
        Endpoint *pEndpoint = m_pInterface->pEndpoints[i];
        if(pEndpoint->nTransferType == Endpoint::Interrupt && pEndpoint->bIn)
        {
            pInEndpoint = pEndpoint;
            break;
        }
    }

    if(!pInEndpoint)
    {
        ERROR("USB: HID: No Interrupt IN endpoint");
        return;
    }

    // Add the input handler
    addInterruptInHandler(pInEndpoint, reinterpret_cast<uintptr_t>(m_pReportBuffer), m_pReport->nBytes, callback, reinterpret_cast<uintptr_t>(this));

    m_bHasDriver = true;
}

UsbHumanInterfaceDevice::~UsbHumanInterfaceDevice()
{
}

void UsbHumanInterfaceDevice::callback(uintptr_t pParam, ssize_t ret)
{
    UsbHumanInterfaceDevice *pHid = reinterpret_cast<UsbHumanInterfaceDevice*>(pParam);
    pHid->inputHandler();
}

void UsbHumanInterfaceDevice::inputHandler()
{
    //NOTICE("USB: HID: Handling input on interface " << Dec << m_pInterface->pDescriptor->nInterface << Hex);

    size_t nCurrentBit = 0;
    for(List<HidReportBlock*>::Iterator it = m_pReport->pBlockList.begin(); it != m_pReport->pBlockList.end(); it++)
    {
        HidReportBlock *pBlock = *it;
        for(size_t i = 0; pBlock->type != HidReportBlock::Ignore && i < pBlock->nCount; i++)
        {
            uint64_t nValue = _getField(m_pReportBuffer, nCurrentBit + i * pBlock->nSize, pBlock->nSize);
            int64_t nSignedValue;
            switch(pBlock->type)
            {
                case HidReportBlock::Absolute:
                    nSignedValue = nValue - _getField(m_pOldReportBuffer, nCurrentBit + i * pBlock->nSize, pBlock->nSize);

                    if(nSignedValue)
                    {
                        if(pBlock->nUsagePage == 7)
                        {
                            if(nSignedValue > 0)
                                HidInputManager::instance().keyDown((*pBlock->pUsages)[i]);
                            else
                                HidInputManager::instance().keyUp((*pBlock->pUsages)[i]);
                        }
                        else if(pBlock->nUsagePage == 9)
                        {
                            if(nSignedValue > 0)
                                NOTICE("    Button " << Dec << ((*pBlock->pUsages)[i]) << Hex << " down");
                            else
                                NOTICE("    Button " << Dec << ((*pBlock->pUsages)[i]) << Hex << " up");
                        }
                        else
                            NOTICE("    Absolute input, usage " << Dec << pBlock->nUsagePage << ":" << ((*pBlock->pUsages)[i]) << ", value " << _sign(nSignedValue) << " " << pBlock->nSize << Hex);
                    }
                    break;
                case HidReportBlock::Relative:
                    nSignedValue = _uint2int(nValue, pBlock->nLogSize * 8);

                    if(nSignedValue)
                        NOTICE("    Relative input, usage " << Dec << pBlock->nUsagePage << ":" << ((*pBlock->pUsages)[i]) << ", value " << _sign(nSignedValue) << Hex);
                    break;
                case HidReportBlock::Array:

                    if(nValue)
                    {
                        NOTICE("    Array input, usage entry " << Dec << pBlock->nUsagePage << ":" << (pBlock->nUsageBase + nValue) << Hex);

                        // Check if this array entry is new
                        bool bNew = true;
                        for(size_t j = 0; j < pBlock->nCount; j++)
                        {
                            if(_getField(m_pOldReportBuffer, nCurrentBit + j * pBlock->nSize, pBlock->nSize) == nValue)
                            {
                                bNew = false;
                                break;
                            }
                        }
                        if(bNew)
                            if(pBlock->nUsagePage == 7)
                                HidInputManager::instance().keyDown(pBlock->nUsageBase + nValue);
                    }
                case HidReportBlock::Ignore:
                default:
                    break;
            }
        }

        // Special case here: check for array entries that disapeared
        if(pBlock->type == HidReportBlock::Array)
        {
            for(size_t i = 0; i < pBlock->nCount; i++)
            {
                uint64_t nOldValue = _getField(m_pOldReportBuffer, nCurrentBit + i * pBlock->nSize, pBlock->nSize);
                if(nOldValue)
                {
                    // Check if this array entry disapeared
                    bool bDisapeared = true;
                    for(size_t j = 0; j < pBlock->nCount; j++)
                    {
                        if(_getField(m_pReportBuffer, nCurrentBit + j * pBlock->nSize, pBlock->nSize) == nOldValue)
                        {
                            bDisapeared = false;
                            break;
                        }
                    }
                    if(bDisapeared)
                        if(pBlock->nUsagePage == 7)
                            HidInputManager::instance().keyUp(pBlock->nUsageBase + nOldValue);
                }
            }
        }

        nCurrentBit += pBlock->nCount * pBlock->nSize;
    }
    memcpy(m_pOldReportBuffer, m_pReportBuffer, m_pReport->nBytes);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_DATETIME_HPP
#define REALM_COLUMN_DATETIME_HPP

#include <realm/column.hpp>

namespace realm {

struct NewDate {
    NewDate(int64_t seconds, int32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false) { }
    NewDate(const null&) : m_is_null(true) { }
    NewDate() : NewDate(null()) { }

    bool is_null() const { return m_is_null; }
    bool operator == (const NewDate& rhs) const { return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator != (const NewDate& rhs) const { return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator > (const NewDate& rhs) const { return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator < (const NewDate& rhs) const { return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    NewDate& operator = (const NewDate& rhs) = default;

    int64_t m_seconds;
    int32_t m_nanoseconds;
    bool m_is_null;
};

class DateTimeColumn : public ColumnBase, public ColumnTemplate<NewDate> {
public:
    DateTimeColumn();
    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                            bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;
    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    Allocator& get_alloc() const noexcept override;
    /// Returns the 'ref' of the root array.
    ref_type get_ref() const noexcept override;
    MemRef get_mem() const noexcept override;
    void replace_root_array(std::unique_ptr<Array> leaf) override;
    MemRef clone_deep(Allocator& alloc) const override;
    void detach() override;
    bool is_attached() const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void set_parent(ArrayParent*, size_t ndx_in_parent) noexcept override;
    size_t get_ndx_in_parent() const noexcept override;
    void set_ndx_in_parent(size_t ndx_in_parent) noexcept override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
    void add(const NewDate& ndt = NewDate{});
    NewDate get(size_t row_ndx) const noexcept;
    NewDate get_val(size_t row_ndx) const override;
    void set(size_t row_ndx, const NewDate& ndt);
private:
    IntNullColumn m_seconds;
    IntegerColumn m_nanoseconds;
};

// Implementation

inline DateTimeColumn::DateTimeColumn() :
    m_seconds(Allocator::get_default(), IntNullColumn::create(Allocator::get_default())),
    m_nanoseconds(Allocator::get_default(), IntegerColumn::create(Allocator::get_default()))
{
}

/// Get the number of entries in this column. This operation is relatively
/// slow.
inline size_t DateTimeColumn::size() const noexcept
{
    // FIXME: Consider debug asserts on the columns having the same size
    return m_seconds.size();
}

/// Whether or not this column is nullable.
inline bool DateTimeColumn::is_nullable() const noexcept
{
    return m_seconds.is_nullable();
}

/// Whether or not the value at \a row_ndx is NULL. If the column is not
/// nullable, always returns false.
inline bool DateTimeColumn::is_null(size_t row_ndx) const noexcept
{
    return m_seconds.is_null(row_ndx);
}

/// Sets the value at \a row_ndx to be NULL.
/// \throw LogicError Thrown if this column is not nullable.
inline void DateTimeColumn::set_null(size_t row_ndx)
{
    m_seconds.set_null(row_ndx);
}

inline void DateTimeColumn::insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows,
                                        bool nullable)
{
    m_seconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, nullable);
    m_nanoseconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, nullable);
}

inline void DateTimeColumn::erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                                       bool broken_reciprocal_backlinks)
{
    m_seconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                                               bool broken_reciprocal_backlinks)
{
    m_seconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::clear(size_t num_rows, bool broken_reciprocal_backlinks)
{
    m_seconds.clear(num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.clear(num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::swap_rows(size_t row_ndx_1, size_t row_ndx_2)
{
    m_seconds.swap_rows(row_ndx_1, row_ndx_2);
    m_nanoseconds.swap_rows(row_ndx_1, row_ndx_2);
}

inline void DateTimeColumn::destroy() noexcept
{
    m_seconds.destroy();
    m_nanoseconds.destroy();
}

inline StringData DateTimeColumn::get_index_data(size_t, StringIndex::StringConversionBuffer& /*buffer*/) const noexcept
{
    // FIXME: Dummy implementation
    return null();
}

inline Allocator& DateTimeColumn::get_alloc() const noexcept
{
    // FIXME: Dummy implementation
    return Allocator::get_default();
}

inline ref_type DateTimeColumn::get_ref() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline MemRef DateTimeColumn::get_mem() const noexcept
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::replace_root_array(std::unique_ptr<Array> /*leaf*/)
{
    // FIXME: Dummy implementation
}

inline MemRef DateTimeColumn::clone_deep(Allocator& /*alloc*/) const
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::detach()
{
    m_seconds.detach();
    m_nanoseconds.detach();
}

inline bool DateTimeColumn::is_attached() const noexcept
{
    // FIXME: Assert on both columns having same attached state?
    return m_seconds.is_attached();
}

inline ref_type DateTimeColumn::write(size_t /*slice_offset*/, size_t /*slice_size*/, size_t /*table_size*/,
                                      _impl::OutputStream&) const
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_parent(ArrayParent*, size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline size_t DateTimeColumn::get_ndx_in_parent() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_ndx_in_parent(size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::update_from_parent(size_t /*old_baseline*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::refresh_accessor_tree(size_t /*new_col_ndx*/, const Spec&)
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::verify() const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::to_dot(std::ostream&, StringData /*title*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::do_dump_node_structure(std::ostream&, int /*level*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::leaf_to_dot(MemRef, ArrayParent*, size_t /*ndx_in_parent*/, std::ostream&) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::add(const NewDate& ndt)
{
    util::Optional<int64_t> seconds = ndt.is_null() ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = ndt.is_null() ? 0 : ndt.m_nanoseconds;
    m_seconds.add(seconds);
    m_nanoseconds.add(nanoseconds);
}

inline NewDate DateTimeColumn::get(size_t row_ndx) const noexcept
{
    util::Optional<int64_t> seconds = m_seconds.get(row_ndx);
    return seconds ? NewDate(*seconds, int32_t(m_nanoseconds.get(row_ndx))) : NewDate(null());
}

inline NewDate DateTimeColumn::get_val(size_t row_ndx) const
{
    return get(row_ndx);
}

inline void DateTimeColumn::set(size_t row_ndx, const NewDate& ndt)
{
    util::Optional<int64_t> seconds = ndt.is_null() ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = ndt.is_null() ? 0 : ndt.m_nanoseconds;
    m_seconds.set(row_ndx, seconds);
    m_nanoseconds.set(row_ndx, nanoseconds);
}

} // namespace realm

#endif // REALM_COLUMN_DATETIME_HPP
<commit_msg>Fixed non-debug compile issues.<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_DATETIME_HPP
#define REALM_COLUMN_DATETIME_HPP

#include <realm/column.hpp>

namespace realm {

struct NewDate {
    NewDate(int64_t seconds, int32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false) { }
    NewDate(const null&) : m_is_null(true) { }
    NewDate() : NewDate(null()) { }

    bool is_null() const { return m_is_null; }
    bool operator == (const NewDate& rhs) const { return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator != (const NewDate& rhs) const { return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator > (const NewDate& rhs) const { return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator < (const NewDate& rhs) const { return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    NewDate& operator = (const NewDate& rhs) = default;

    int64_t m_seconds;
    int32_t m_nanoseconds;
    bool m_is_null;
};

class DateTimeColumn : public ColumnBase, public ColumnTemplate<NewDate> {
public:
    DateTimeColumn();
    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                            bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;
    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    Allocator& get_alloc() const noexcept override;
    /// Returns the 'ref' of the root array.
    ref_type get_ref() const noexcept override;
    MemRef get_mem() const noexcept override;
    void replace_root_array(std::unique_ptr<Array> leaf) override;
    MemRef clone_deep(Allocator& alloc) const override;
    void detach() override;
    bool is_attached() const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void set_parent(ArrayParent*, size_t ndx_in_parent) noexcept override;
    size_t get_ndx_in_parent() const noexcept override;
    void set_ndx_in_parent(size_t ndx_in_parent) noexcept override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
#ifdef REALM_DEBUG
    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
#endif
    void add(const NewDate& ndt = NewDate{});
    NewDate get(size_t row_ndx) const noexcept;
    NewDate get_val(size_t row_ndx) const override;
    void set(size_t row_ndx, const NewDate& ndt);
private:
    IntNullColumn m_seconds;
    IntegerColumn m_nanoseconds;
};

// Implementation

inline DateTimeColumn::DateTimeColumn() :
    m_seconds(Allocator::get_default(), IntNullColumn::create(Allocator::get_default())),
    m_nanoseconds(Allocator::get_default(), IntegerColumn::create(Allocator::get_default()))
{
}

/// Get the number of entries in this column. This operation is relatively
/// slow.
inline size_t DateTimeColumn::size() const noexcept
{
    // FIXME: Consider debug asserts on the columns having the same size
    return m_seconds.size();
}

/// Whether or not this column is nullable.
inline bool DateTimeColumn::is_nullable() const noexcept
{
    return m_seconds.is_nullable();
}

/// Whether or not the value at \a row_ndx is NULL. If the column is not
/// nullable, always returns false.
inline bool DateTimeColumn::is_null(size_t row_ndx) const noexcept
{
    return m_seconds.is_null(row_ndx);
}

/// Sets the value at \a row_ndx to be NULL.
/// \throw LogicError Thrown if this column is not nullable.
inline void DateTimeColumn::set_null(size_t row_ndx)
{
    m_seconds.set_null(row_ndx);
}

inline void DateTimeColumn::insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows,
                                        bool nullable)
{
    m_seconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, nullable);
    m_nanoseconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, nullable);
}

inline void DateTimeColumn::erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                                       bool broken_reciprocal_backlinks)
{
    m_seconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                                               bool broken_reciprocal_backlinks)
{
    m_seconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::clear(size_t num_rows, bool broken_reciprocal_backlinks)
{
    m_seconds.clear(num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.clear(num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::swap_rows(size_t row_ndx_1, size_t row_ndx_2)
{
    m_seconds.swap_rows(row_ndx_1, row_ndx_2);
    m_nanoseconds.swap_rows(row_ndx_1, row_ndx_2);
}

inline void DateTimeColumn::destroy() noexcept
{
    m_seconds.destroy();
    m_nanoseconds.destroy();
}

inline StringData DateTimeColumn::get_index_data(size_t, StringIndex::StringConversionBuffer& /*buffer*/) const noexcept
{
    // FIXME: Dummy implementation
    return null();
}

inline Allocator& DateTimeColumn::get_alloc() const noexcept
{
    // FIXME: Dummy implementation
    return Allocator::get_default();
}

inline ref_type DateTimeColumn::get_ref() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline MemRef DateTimeColumn::get_mem() const noexcept
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::replace_root_array(std::unique_ptr<Array> /*leaf*/)
{
    // FIXME: Dummy implementation
}

inline MemRef DateTimeColumn::clone_deep(Allocator& /*alloc*/) const
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::detach()
{
    m_seconds.detach();
    m_nanoseconds.detach();
}

inline bool DateTimeColumn::is_attached() const noexcept
{
    // FIXME: Assert on both columns having same attached state?
    return m_seconds.is_attached();
}

inline ref_type DateTimeColumn::write(size_t /*slice_offset*/, size_t /*slice_size*/, size_t /*table_size*/,
                                      _impl::OutputStream&) const
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_parent(ArrayParent*, size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline size_t DateTimeColumn::get_ndx_in_parent() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_ndx_in_parent(size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::update_from_parent(size_t /*old_baseline*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::refresh_accessor_tree(size_t /*new_col_ndx*/, const Spec&)
{
    // FIXME: Dummy implementation
}

#ifdef REALM_DEBUG

inline void DateTimeColumn::verify() const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::to_dot(std::ostream&, StringData /*title*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::do_dump_node_structure(std::ostream&, int /*level*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::leaf_to_dot(MemRef, ArrayParent*, size_t /*ndx_in_parent*/, std::ostream&) const
{
    // FIXME: Dummy implementation
}

#endif

inline void DateTimeColumn::add(const NewDate& ndt)
{
    util::Optional<int64_t> seconds = ndt.is_null() ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = ndt.is_null() ? 0 : ndt.m_nanoseconds;
    m_seconds.add(seconds);
    m_nanoseconds.add(nanoseconds);
}

inline NewDate DateTimeColumn::get(size_t row_ndx) const noexcept
{
    util::Optional<int64_t> seconds = m_seconds.get(row_ndx);
    return seconds ? NewDate(*seconds, int32_t(m_nanoseconds.get(row_ndx))) : NewDate(null());
}

inline NewDate DateTimeColumn::get_val(size_t row_ndx) const
{
    return get(row_ndx);
}

inline void DateTimeColumn::set(size_t row_ndx, const NewDate& ndt)
{
    util::Optional<int64_t> seconds = ndt.is_null() ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = ndt.is_null() ? 0 : ndt.m_nanoseconds;
    m_seconds.set(row_ndx, seconds);
    m_nanoseconds.set(row_ndx, nanoseconds);
}

} // namespace realm

#endif // REALM_COLUMN_DATETIME_HPP
<|endoftext|>


<commit_before>#include <die-tk.h>
#include <iostream>
using namespace std;
using namespace tk;

WDims getDims(bool big) { return big ? WDims(200,100) : WDims(100,200); }

int main()
{
	Application app;

    bool firstWindowWide = true;
    auto swapWindowSizes = [&firstWindowWide](Window & w1, Window & w2) {
		w2.setDims(getDims(firstWindowWide));
		firstWindowWide = ! firstWindowWide;
    	w1.setDims(getDims(firstWindowWide));
    };

	Window window(WindowParams("first").start(10,10).dims(200,100));
	Window window2(WindowParams("second").start(250,10).dims(100,200));
	window.onMouseDown([&](MouseEvent e, Point pt) {
		switch(e.button) {
			case MouseButton::left: {
				swapWindowSizes(window,window2);
				app.processMessages(); // makes setDims to execute now, before drawing the poly
				Points points = { {40,10}, {80,40}, {40,80}, {10,40}, };
				window.canvas().drawPoly(points,RGBColor(0,180,0));
			} break;
			case MouseButton::right:
				swapWindowSizes(window,window2);
				break;
		}
	});
	window2.onMouseDown([&](MouseEvent e, Point pt) {
		switch(e.button) {
			case MouseButton::left:
				swapWindowSizes(window,window2);
				app.processMessages(); // makes setDims to execute now, before drawing the poly
				window2.canvas().fillRect(Rect::closed(Point(10,10),WDims(80,80)),RGBColor(180,180,0));
				break;
			case MouseButton::right:
				swapWindowSizes(window,window2);
				break;
		}
	});

	bool open = true;
	auto closeFn = [&open]() -> bool { open = false; return true; };
	window.onClose(closeFn);
	window2.onClose(closeFn);

	window.onResize([](WDims d) -> WDims {
		if( d.width > 200 ) d.width = 200;
		if( d.height > 400 ) d.height = 400;
		return d;
	});
	window2.onResize([](WDims d) -> WDims {
		if( d.width < 100 ) d.width = 100;
		if( d.height < 100 ) d.height = 100;
		return d;
	});

	do {
		app.waitForMessages();
		app.processMessages();
	} while( open );
}
<commit_msg>fixing tabs<commit_after>#include <die-tk.h>
#include <iostream>
using namespace std;
using namespace tk;

WDims getDims(bool big) { return big ? WDims(200,100) : WDims(100,200); }

int main()
{
	Application app;

	bool firstWindowWide = true;
	auto swapWindowSizes = [&firstWindowWide](Window & w1, Window & w2) {
		w2.setDims(getDims(firstWindowWide));
		firstWindowWide = ! firstWindowWide;
		w1.setDims(getDims(firstWindowWide));
	};

	Window window(WindowParams("first").start(10,10).dims(200,100));
	Window window2(WindowParams("second").start(250,10).dims(100,200));
	window.onMouseDown([&](MouseEvent e, Point pt) {
		switch(e.button) {
			case MouseButton::left: {
				swapWindowSizes(window,window2);
				app.processMessages(); // makes setDims to execute now, before drawing the poly
				Points points = { {40,10}, {80,40}, {40,80}, {10,40}, };
				window.canvas().drawPoly(points,RGBColor(0,180,0));
			} break;
			case MouseButton::right:
				swapWindowSizes(window,window2);
				break;
		}
	});
	window2.onMouseDown([&](MouseEvent e, Point pt) {
		switch(e.button) {
			case MouseButton::left:
				swapWindowSizes(window,window2);
				app.processMessages(); // makes setDims to execute now, before drawing the poly
				window2.canvas().fillRect(Rect::closed(Point(10,10),WDims(80,80)),RGBColor(180,180,0));
				break;
			case MouseButton::right:
				swapWindowSizes(window,window2);
				break;
		}
	});

	bool open = true;
	auto closeFn = [&open]() -> bool { open = false; return true; };
	window.onClose(closeFn);
	window2.onClose(closeFn);

	window.onResize([](WDims d) -> WDims {
		if( d.width > 200 ) d.width = 200;
		if( d.height > 400 ) d.height = 400;
		return d;
	});
	window2.onResize([](WDims d) -> WDims {
		if( d.width < 100 ) d.width = 100;
		if( d.height < 100 ) d.height = 100;
		return d;
	});

	do {
		app.waitForMessages();
		app.processMessages();
	} while( open );
}
<|endoftext|>


<commit_before>//*****************************************************************************
// Copyright 2017-2018 Intel Corporation
//
// 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 <algorithm>
#include <typeindex>
#include <unordered_set>

#include "ngraph/graph_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/op/constant.hpp"
#include "ngraph/op/convolution.hpp"
#include "ngraph/op/parameter.hpp"
#include "ngraph/op/reshape.hpp"
#include "ngraph/op/slice.hpp"
#include "ngraph/pass/graph_rewrite.hpp"
#include "ngraph/pass/manager.hpp"
#include "ngraph/pattern/matcher.hpp"
#include "ngraph/pattern/op/label.hpp"
#include "ngraph/pattern/op/skip.hpp"
#include "ngraph/runtime/cpu/cpu_layout_descriptor.hpp"
#include "ngraph/runtime/cpu/cpu_op_annotations.hpp"
#include "ngraph/runtime/cpu/mkldnn_utils.hpp"
#include "ngraph/runtime/cpu/op/convert_layout.hpp"
#include "ngraph/runtime/cpu/pass/cpu_post_layout_optimizations.hpp"

using namespace ngraph;
using namespace std;

#define TI(x) std::type_index(typeid(x))

void ngraph::runtime::cpu::pass::CPUPostLayoutOptimizations::construct_weight_fusion()
{
    auto param = std::make_shared<pattern::op::Label>(element::f32, Shape{64});
    auto reshape_conv =
        std::make_shared<ngraph::op::Reshape>(param, AxisVector{0}, Shape{16, 4, 1, 1});
    auto data_conv = std::make_shared<pattern::op::Label>(element::f32, Shape{16, 4, 7, 7});
    auto tvt = reshape_conv->get_outputs().at(0).get_tensor_ptr().get();
    auto lt_desc = std::make_shared<runtime::cpu::LayoutDescriptor>(*tvt);
    auto cvt_lt_conv = std::make_shared<runtime::cpu::op::ConvertLayout>(reshape_conv, lt_desc);
    auto conv = std::make_shared<ngraph::op::Convolution>(
        data_conv, cvt_lt_conv, Strides{1, 1}, Strides{1, 1});

    pattern::graph_rewrite_callback callback = [param](pattern::Matcher& m) {
        NGRAPH_DEBUG << "In a callback for construct_weight against "
                     << m.get_match_root()->get_name();

        auto m_cvt_lt = m.get_match_root()->get_argument(1);
        auto m_reshape_conv = m_cvt_lt->get_argument(0);

        std::shared_ptr<Node> m_conv_bprop;

        std::vector<std::type_index> user_pattern = {TI(ngraph::op::Reshape),
                                                     TI(runtime::cpu::op::ConvertLayout),
                                                     TI(ngraph::op::ConvolutionBackpropData)};

        for (auto u : m.get_pattern_map()[param]->get_users())
        {
            if (u != m_reshape_conv)
            {
                size_t num_matches = 0;
                auto ui = u;
                for (; num_matches < user_pattern.size(); num_matches++)
                {
                    const Node& user_ref = *ui;
                    if (TI(user_ref) != user_pattern.at(num_matches))
                    {
                        NGRAPH_DEBUG << "the type for user " << ui->get_name()
                                     << " doesn't match the type at " << num_matches;
                        break;
                    }

                    if (ui->get_users().size() != 1)
                    {
                        NGRAPH_DEBUG << u->get_name() << " has more than one user";
                        break;
                    }
                    ui = ui->get_users().at(0);
                }

                if (num_matches == user_pattern.size())
                {
                    m_conv_bprop = u->get_users().at(0)->get_users().at(0);
                    NGRAPH_DEBUG << " m_conv_bprop is set to " << m_conv_bprop->get_name();
                    break;
                }
            }
        }

        if (!m_conv_bprop)
        {
            return false;
        }

        auto m_cvt_lt_bprop = m_conv_bprop->get_argument(0);
        auto m_reshape_bprop = m_cvt_lt_bprop->get_argument(0);

        NGRAPH_DEBUG << "Replacing input "
                     << m_cvt_lt_bprop->get_inputs().at(0).get_output().get_node()->get_name()
                     << " to " << m_cvt_lt_bprop->get_name() << " with "
                     << m_cvt_lt->get_outputs().at(0).get_node()->get_name();
        m_cvt_lt_bprop->get_inputs().at(0).replace_output(m_cvt_lt->get_outputs().at(0));

        return true;
    };

    auto m = make_shared<pattern::Matcher>(
        conv, callback, "CPUPostLayoutOptimizations.ConstructWeight_fusion");
    this->add_matcher(m);
}

void ngraph::runtime::cpu::pass::CPUPostLayoutOptimizations::construct_slice_convertLayout_fusion()
{
    auto param = std::make_shared<pattern::op::Label>(element::f32, Shape{1, 576, 17, 17});
    auto slice = std::make_shared<ngraph::op::Slice>(
        param, Coordinate{0, 0, 0, 0}, Coordinate{1, 192, 17, 17});
    auto tvt = slice->get_outputs().at(0).get_tensor_ptr().get();
    auto lt_desc = std::make_shared<runtime::cpu::LayoutDescriptor>(*tvt);
    auto cvt_lt = std::make_shared<runtime::cpu::op::ConvertLayout>(slice, lt_desc);

    pattern::graph_rewrite_callback callback = [param](pattern::Matcher& m) {
        NGRAPH_DEBUG << "In a callback for construct_slice_converLayout against "
                     << m.get_match_root()->get_name();

        auto m_cvt_lt = m.get_match_root();
        auto m_slice = m_cvt_lt->get_argument(0);
        auto slice_ptr = static_cast<const ngraph::op::Slice*>(m_slice.get());
        // do the fusion if slice has 1 user and uses mkldnn kernel.
        if (!runtime::cpu::mkldnn_utils::use_mkldnn_kernel(slice_ptr) ||
            m_slice->get_users().size() != 1)
        {
            return false;
        }

        for (auto u : m.get_pattern_map()[param]->get_users())
        {
            if (u != m_slice)
            {
                continue;
            }

            auto new_slice = std::make_shared<ngraph::op::Slice>(m_slice->get_argument(0),
                                                                 slice_ptr->get_lower_bounds(),
                                                                 slice_ptr->get_upper_bounds(),
                                                                 slice_ptr->get_strides());
            auto op_annotations = std::make_shared<ngraph::runtime::cpu::CPUOpAnnotations>();
            op_annotations->set_mkldnn_op(true);
            new_slice->set_op_annotations(op_annotations);
            auto tv = new_slice->get_output_tensor_ptr(0);
            auto layout = std::make_shared<ngraph::runtime::cpu::LayoutDescriptor>(*tv);
            layout->set_mkldnn_md(mkldnn_utils::get_output_mkldnn_md(m_cvt_lt.get(), 0));
            tv->set_tensor_layout(layout);
            ngraph::replace_node(m_cvt_lt, new_slice);
        }

        return true;
    };

    auto m = make_shared<pattern::Matcher>(
        cvt_lt, callback, "CPUPostLayoutOptimizations.ConstructSliceConvertLayoutFusion");
    this->add_matcher(m);
}

// Reshape(transpose) + ConvertLayout
// MKLDNN has more efficient ConvertLayout kernels for named/non-padded formats
// If a transpose is converting a padded format into a generic padded/blocked format, it is better
// to ConvertLayout first and then do the transpose
// E.g.,
// Shape{10, 20, 30, 40} --(Reshape)--> Shape{10, 40, 20, 30} --(ConvertLayout)--> Shape{10, 40, 20, 30}
// is changed to
// Shape{10, 20, 30, 40} --(ConvertLayout)--> Shape{10, 20, 30, 40} --(Reshape)--> Shape{10, 40, 20, 30}
// The new ConvertLayout op computes the desired output layout (out_md) directly from
// input layout using a rotated out_md
void ngraph::runtime::cpu::pass::CPUPostLayoutOptimizations::
    construct_reshape_convertLayout_fusion()
{
    auto input = std::make_shared<pattern::op::Label>(element::f32, Shape{1, 1, 1, 1});
    auto reshape =
        std::make_shared<ngraph::op::Reshape>(input, AxisVector{0, 1, 2, 3}, Shape{1, 1, 1, 1});
    auto lt_desc =
        std::make_shared<runtime::cpu::LayoutDescriptor>(*reshape->get_output_tensor_ptr());
    auto cvt_lt = std::make_shared<runtime::cpu::op::ConvertLayout>(reshape, lt_desc);

    pattern::graph_rewrite_callback callback = [](pattern::Matcher& m) {
        NGRAPH_DEBUG << "In a callback for construct_reshape_converLayout against "
                     << m.get_match_root()->get_name();

        auto cvt_lt_m = static_pointer_cast<runtime::cpu::op::ConvertLayout>(m.get_match_root());
        auto reshape_m = static_pointer_cast<ngraph::op::Reshape>(cvt_lt_m->get_argument(0));

        if (reshape_m->get_users().size() > 1)
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape has multiple users";
            return false;
        }

        if (!reshape_m->get_is_transpose())
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape is not a transpose";
            return false;
        }

        if (reshape_m->get_op_annotations()->get_in_place_oi_pairs().size() == 0)
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape is not pass-through";
            return false;
        }

        auto reshape_m_md = runtime::cpu::mkldnn_utils::get_output_mkldnn_md(reshape_m.get(), 0);
        if (reshape_m_md.data.format != mkldnn_blocked ||
            !runtime::cpu::mkldnn_utils::is_mkldnn_padded_layout(
                reshape_m_md, ngraph::get_default_order(reshape_m->get_shape())))
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape is not creating a blocked/padded layout";
            return false;
        }

        // Rotate output layout to the pre-transposed order
        auto out_md = runtime::cpu::mkldnn_utils::get_output_mkldnn_md(cvt_lt_m.get(), 0);
        auto reshape_order = reshape_m->get_input_order();
        // Get the inverse of the original transpose order
        // E.g., [0, 3, 1, 2] -> [0, 2, 3, 1]
        AxisVector inverse_order;
        for (int i = 0; i < reshape_order.size(); i++)
        {
            inverse_order.push_back(std::find(reshape_order.begin(), reshape_order.end(), i) -
                                    reshape_order.begin());
        }
        auto rotated_md = runtime::cpu::mkldnn_utils::rotate_blocked_md(out_md, inverse_order);
        auto rotated_lt_desc = std::make_shared<runtime::cpu::LayoutDescriptor>(
            *reshape_m->get_argument(0)->get_output_tensor_ptr());
        rotated_lt_desc->set_mkldnn_md(rotated_md);

        auto cvt_lt_n = std::make_shared<runtime::cpu::op::ConvertLayout>(
            reshape_m->get_argument(0), 0, rotated_lt_desc);
        cvt_lt_n->set_op_annotations(cvt_lt_m->get_op_annotations());

        auto reshape_n =
            std::make_shared<ngraph::op::Reshape>(cvt_lt_n, reshape_order, cvt_lt_m->get_shape());
        auto reshape_n_layout = std::make_shared<ngraph::runtime::cpu::LayoutDescriptor>(
            *reshape_n->get_output_tensor_ptr());
        reshape_n_layout->set_mkldnn_md(out_md);
        reshape_n->get_output_tensor_ptr()->set_tensor_layout(reshape_n_layout);
        reshape_n->set_op_annotations(reshape_m->get_op_annotations());

        ngraph::replace_node(cvt_lt_m, reshape_n);
        NGRAPH_DEBUG << "ReshapeConvertLayout: Reordering reshape and convertlayout for faster "
                        "MKLDNN kernels";

        return true;
    };

    auto m = make_shared<pattern::Matcher>(
        cvt_lt, callback, "CPUPostLayoutOptimizations.ConstructReshapeConvertLayoutFusion");
    this->add_matcher(m);
}
<commit_msg>fix crash in ReshapeConvertLayout  (#2205)<commit_after>//*****************************************************************************
// Copyright 2017-2018 Intel Corporation
//
// 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 <algorithm>
#include <typeindex>
#include <unordered_set>

#include "ngraph/graph_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/op/constant.hpp"
#include "ngraph/op/convolution.hpp"
#include "ngraph/op/parameter.hpp"
#include "ngraph/op/reshape.hpp"
#include "ngraph/op/slice.hpp"
#include "ngraph/pass/graph_rewrite.hpp"
#include "ngraph/pass/manager.hpp"
#include "ngraph/pattern/matcher.hpp"
#include "ngraph/pattern/op/label.hpp"
#include "ngraph/pattern/op/skip.hpp"
#include "ngraph/runtime/cpu/cpu_layout_descriptor.hpp"
#include "ngraph/runtime/cpu/cpu_op_annotations.hpp"
#include "ngraph/runtime/cpu/mkldnn_utils.hpp"
#include "ngraph/runtime/cpu/op/convert_layout.hpp"
#include "ngraph/runtime/cpu/pass/cpu_post_layout_optimizations.hpp"

using namespace ngraph;
using namespace std;

#define TI(x) std::type_index(typeid(x))

void ngraph::runtime::cpu::pass::CPUPostLayoutOptimizations::construct_weight_fusion()
{
    auto param = std::make_shared<pattern::op::Label>(element::f32, Shape{64});
    auto reshape_conv =
        std::make_shared<ngraph::op::Reshape>(param, AxisVector{0}, Shape{16, 4, 1, 1});
    auto data_conv = std::make_shared<pattern::op::Label>(element::f32, Shape{16, 4, 7, 7});
    auto tvt = reshape_conv->get_outputs().at(0).get_tensor_ptr().get();
    auto lt_desc = std::make_shared<runtime::cpu::LayoutDescriptor>(*tvt);
    auto cvt_lt_conv = std::make_shared<runtime::cpu::op::ConvertLayout>(reshape_conv, lt_desc);
    auto conv = std::make_shared<ngraph::op::Convolution>(
        data_conv, cvt_lt_conv, Strides{1, 1}, Strides{1, 1});

    pattern::graph_rewrite_callback callback = [param](pattern::Matcher& m) {
        NGRAPH_DEBUG << "In a callback for construct_weight against "
                     << m.get_match_root()->get_name();

        auto m_cvt_lt = m.get_match_root()->get_argument(1);
        auto m_reshape_conv = m_cvt_lt->get_argument(0);

        std::shared_ptr<Node> m_conv_bprop;

        std::vector<std::type_index> user_pattern = {TI(ngraph::op::Reshape),
                                                     TI(runtime::cpu::op::ConvertLayout),
                                                     TI(ngraph::op::ConvolutionBackpropData)};

        for (auto u : m.get_pattern_map()[param]->get_users())
        {
            if (u != m_reshape_conv)
            {
                size_t num_matches = 0;
                auto ui = u;
                for (; num_matches < user_pattern.size(); num_matches++)
                {
                    const Node& user_ref = *ui;
                    if (TI(user_ref) != user_pattern.at(num_matches))
                    {
                        NGRAPH_DEBUG << "the type for user " << ui->get_name()
                                     << " doesn't match the type at " << num_matches;
                        break;
                    }

                    if (ui->get_users().size() != 1)
                    {
                        NGRAPH_DEBUG << u->get_name() << " has more than one user";
                        break;
                    }
                    ui = ui->get_users().at(0);
                }

                if (num_matches == user_pattern.size())
                {
                    m_conv_bprop = u->get_users().at(0)->get_users().at(0);
                    NGRAPH_DEBUG << " m_conv_bprop is set to " << m_conv_bprop->get_name();
                    break;
                }
            }
        }

        if (!m_conv_bprop)
        {
            return false;
        }

        auto m_cvt_lt_bprop = m_conv_bprop->get_argument(0);
        auto m_reshape_bprop = m_cvt_lt_bprop->get_argument(0);

        NGRAPH_DEBUG << "Replacing input "
                     << m_cvt_lt_bprop->get_inputs().at(0).get_output().get_node()->get_name()
                     << " to " << m_cvt_lt_bprop->get_name() << " with "
                     << m_cvt_lt->get_outputs().at(0).get_node()->get_name();
        m_cvt_lt_bprop->get_inputs().at(0).replace_output(m_cvt_lt->get_outputs().at(0));

        return true;
    };

    auto m = make_shared<pattern::Matcher>(
        conv, callback, "CPUPostLayoutOptimizations.ConstructWeight_fusion");
    this->add_matcher(m);
}

void ngraph::runtime::cpu::pass::CPUPostLayoutOptimizations::construct_slice_convertLayout_fusion()
{
    auto param = std::make_shared<pattern::op::Label>(element::f32, Shape{1, 576, 17, 17});
    auto slice = std::make_shared<ngraph::op::Slice>(
        param, Coordinate{0, 0, 0, 0}, Coordinate{1, 192, 17, 17});
    auto tvt = slice->get_outputs().at(0).get_tensor_ptr().get();
    auto lt_desc = std::make_shared<runtime::cpu::LayoutDescriptor>(*tvt);
    auto cvt_lt = std::make_shared<runtime::cpu::op::ConvertLayout>(slice, lt_desc);

    pattern::graph_rewrite_callback callback = [param](pattern::Matcher& m) {
        NGRAPH_DEBUG << "In a callback for construct_slice_converLayout against "
                     << m.get_match_root()->get_name();

        auto m_cvt_lt = m.get_match_root();
        auto m_slice = m_cvt_lt->get_argument(0);
        auto slice_ptr = static_cast<const ngraph::op::Slice*>(m_slice.get());
        // do the fusion if slice has 1 user and uses mkldnn kernel.
        if (!runtime::cpu::mkldnn_utils::use_mkldnn_kernel(slice_ptr) ||
            m_slice->get_users().size() != 1)
        {
            return false;
        }

        for (auto u : m.get_pattern_map()[param]->get_users())
        {
            if (u != m_slice)
            {
                continue;
            }

            auto new_slice = std::make_shared<ngraph::op::Slice>(m_slice->get_argument(0),
                                                                 slice_ptr->get_lower_bounds(),
                                                                 slice_ptr->get_upper_bounds(),
                                                                 slice_ptr->get_strides());
            auto op_annotations = std::make_shared<ngraph::runtime::cpu::CPUOpAnnotations>();
            op_annotations->set_mkldnn_op(true);
            new_slice->set_op_annotations(op_annotations);
            auto tv = new_slice->get_output_tensor_ptr(0);
            auto layout = std::make_shared<ngraph::runtime::cpu::LayoutDescriptor>(*tv);
            layout->set_mkldnn_md(mkldnn_utils::get_output_mkldnn_md(m_cvt_lt.get(), 0));
            tv->set_tensor_layout(layout);
            ngraph::replace_node(m_cvt_lt, new_slice);
        }

        return true;
    };

    auto m = make_shared<pattern::Matcher>(
        cvt_lt, callback, "CPUPostLayoutOptimizations.ConstructSliceConvertLayoutFusion");
    this->add_matcher(m);
}

// Reshape(transpose) + ConvertLayout
// MKLDNN has more efficient ConvertLayout kernels for named/non-padded formats
// If a transpose is converting a padded format into a generic padded/blocked format, it is better
// to ConvertLayout first and then do the transpose
// E.g.,
// Shape{10, 20, 30, 40} --(Reshape)--> Shape{10, 40, 20, 30} --(ConvertLayout)--> Shape{10, 40, 20, 30}
// is changed to
// Shape{10, 20, 30, 40} --(ConvertLayout)--> Shape{10, 20, 30, 40} --(Reshape)--> Shape{10, 40, 20, 30}
// The new ConvertLayout op computes the desired output layout (out_md) directly from
// input layout using a rotated out_md
void ngraph::runtime::cpu::pass::CPUPostLayoutOptimizations::
    construct_reshape_convertLayout_fusion()
{
    auto input = std::make_shared<pattern::op::Label>(element::f32, Shape{1, 1, 1, 1});
    auto reshape =
        std::make_shared<ngraph::op::Reshape>(input, AxisVector{0, 1, 2, 3}, Shape{1, 1, 1, 1});
    auto lt_desc =
        std::make_shared<runtime::cpu::LayoutDescriptor>(*reshape->get_output_tensor_ptr());
    auto cvt_lt = std::make_shared<runtime::cpu::op::ConvertLayout>(reshape, lt_desc);

    pattern::graph_rewrite_callback callback = [](pattern::Matcher& m) {
        NGRAPH_DEBUG << "In a callback for construct_reshape_converLayout against "
                     << m.get_match_root()->get_name();

        auto cvt_lt_m = static_pointer_cast<runtime::cpu::op::ConvertLayout>(m.get_match_root());
        auto reshape_m = static_pointer_cast<ngraph::op::Reshape>(cvt_lt_m->get_argument(0));

        if (reshape_m->get_users().size() > 1)
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape has multiple users";
            return false;
        }

        if (!reshape_m->get_is_transpose())
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape is not a transpose";
            return false;
        }

        auto annotation = reshape_m->get_op_annotations();
        if (!annotation || annotation->get_in_place_oi_pairs().size() == 0)
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape is not pass-through";
            return false;
        }

        auto reshape_m_md = runtime::cpu::mkldnn_utils::get_output_mkldnn_md(reshape_m.get(), 0);
        if (reshape_m_md.data.format != mkldnn_blocked ||
            !runtime::cpu::mkldnn_utils::is_mkldnn_padded_layout(
                reshape_m_md, ngraph::get_default_order(reshape_m->get_shape())))
        {
            NGRAPH_DEBUG << "ReshapeConvertLayout: Reshape is not creating a blocked/padded layout";
            return false;
        }

        // Rotate output layout to the pre-transposed order
        auto out_md = runtime::cpu::mkldnn_utils::get_output_mkldnn_md(cvt_lt_m.get(), 0);
        auto reshape_order = reshape_m->get_input_order();
        // Get the inverse of the original transpose order
        // E.g., [0, 3, 1, 2] -> [0, 2, 3, 1]
        AxisVector inverse_order;
        for (int i = 0; i < reshape_order.size(); i++)
        {
            inverse_order.push_back(std::find(reshape_order.begin(), reshape_order.end(), i) -
                                    reshape_order.begin());
        }
        auto rotated_md = runtime::cpu::mkldnn_utils::rotate_blocked_md(out_md, inverse_order);
        auto rotated_lt_desc = std::make_shared<runtime::cpu::LayoutDescriptor>(
            *reshape_m->get_argument(0)->get_output_tensor_ptr());
        rotated_lt_desc->set_mkldnn_md(rotated_md);

        auto cvt_lt_n = std::make_shared<runtime::cpu::op::ConvertLayout>(
            reshape_m->get_argument(0), 0, rotated_lt_desc);
        cvt_lt_n->set_op_annotations(cvt_lt_m->get_op_annotations());

        auto reshape_n =
            std::make_shared<ngraph::op::Reshape>(cvt_lt_n, reshape_order, cvt_lt_m->get_shape());
        auto reshape_n_layout = std::make_shared<ngraph::runtime::cpu::LayoutDescriptor>(
            *reshape_n->get_output_tensor_ptr());
        reshape_n_layout->set_mkldnn_md(out_md);
        reshape_n->get_output_tensor_ptr()->set_tensor_layout(reshape_n_layout);
        reshape_n->set_op_annotations(reshape_m->get_op_annotations());

        ngraph::replace_node(cvt_lt_m, reshape_n);
        NGRAPH_DEBUG << "ReshapeConvertLayout: Reordering reshape and convertlayout for faster "
                        "MKLDNN kernels";

        return true;
    };

    auto m = make_shared<pattern::Matcher>(
        cvt_lt, callback, "CPUPostLayoutOptimizations.ConstructReshapeConvertLayoutFusion");
    this->add_matcher(m);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: NeonUri.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: kso $ $Date: 2002-08-21 07:34:53 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _RTL_URI_HXX_
#include <rtl/uri.hxx>
#endif
#ifndef _RTL_OUSTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _NEONURI_HXX_
#include "NeonUri.hxx"
#endif
#ifndef _DAVEXCEPTION_HXX_
#include "DAVException.hxx"
#endif

using namespace webdav_ucp;

ne_uri NeonUri::sUriDefaultsHTTP  = { "http",  NULL, DEFAULT_HTTP_PORT,  NULL };
ne_uri NeonUri::sUriDefaultsHTTPS = { "https", NULL, DEFAULT_HTTPS_PORT, NULL };
ne_uri NeonUri::sUriDefaultsFTP   = { "ftp",   NULL, DEFAULT_FTP_PORT,   NULL };

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------

namespace {

//TODO! rtl::OString::matchIgnoreAsciiCaseAsciiL() missing
inline bool matchIgnoreAsciiCase(rtl::OString const & rStr1,
                                 sal_Char const * pStr2,
                                 sal_Int32 nStr2Len) SAL_THROW(())
{
    return
        rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
                rStr1.getStr(), rStr1.getLength(), pStr2, nStr2Len, nStr2Len)
            == 0;
}

}

NeonUri::NeonUri( const ne_uri * inUri )
    throw ( DAVException )
{
    if ( inUri == 0 )
        throw DAVException( DAVException::DAV_INVALID_ARG );

    char * uri = ne_uri_unparse( inUri );
    if ( uri == 0 )
        throw DAVException( DAVException::DAV_INVALID_ARG );

    init( rtl::OString( uri ), inUri );
    calculateURI();

    free( uri );
}

NeonUri::NeonUri( const rtl::OUString & inUri )
    throw ( DAVException )
{
    if ( inUri.getLength() <= 0 )
        throw DAVException( DAVException::DAV_INVALID_ARG );

    rtl::OString theInputUri(
        inUri.getStr(), inUri.getLength(), RTL_TEXTENCODING_UTF8 );

    ne_uri theUri;
    if ( ne_uri_parse( theInputUri.getStr(), &theUri ) != 0 )
    {
        ne_uri_free( &theUri );
        throw DAVException( DAVException::DAV_INVALID_ARG );
    }

    init( theInputUri, &theUri );
    calculateURI();

    ne_uri_free( &theUri );
}

void NeonUri::init( const rtl::OString & rUri, const ne_uri * pUri )
{
    // Complete URI.
    ne_uri * pUriDefs
        = matchIgnoreAsciiCase( rUri,
                                RTL_CONSTASCII_STRINGPARAM( "ftp:" ) ) ?
              &sUriDefaultsFTP :
          matchIgnoreAsciiCase( rUri,
                                RTL_CONSTASCII_STRINGPARAM( "https:" ) ) ?
              &sUriDefaultsHTTPS :
              &sUriDefaultsHTTP;

    mScheme   = rtl::OStringToOUString(
                    pUri->scheme ? pUri->scheme : pUriDefs->scheme,
                    RTL_TEXTENCODING_UTF8 );
    mUserInfo = rtl::OStringToOUString(
                    pUri->authinfo ? pUri->authinfo : pUriDefs->authinfo,
                    RTL_TEXTENCODING_UTF8 );
    mHostName = rtl::OStringToOUString(
                    pUri->host ? pUri->host : pUriDefs->host,
                    RTL_TEXTENCODING_UTF8 );
    mPort     = pUri->port > 0 ? pUri->port : pUriDefs->port;
    mPath     = rtl::OStringToOUString(
                    pUri->path ? pUri->path : pUriDefs->path,
                    RTL_TEXTENCODING_UTF8 );
}

// -------------------------------------------------------------------
// Destructor
// -------------------------------------------------------------------
NeonUri::~NeonUri( )
{
}

void NeonUri::calculateURI ()
{
    mURI = mScheme;
    mURI += rtl::OUString::createFromAscii ("://");
    if (mUserInfo.getLength() > 0)
    {
        //TODO! differentiate between empty and missing userinfo
        mURI += mUserInfo;
        mURI += rtl::OUString::createFromAscii ("@");
    }
    mURI += mHostName;
    mURI += rtl::OUString::createFromAscii (":");
    mURI += rtl::OUString::valueOf (mPort);
    mURI += mPath;
}

::rtl::OUString NeonUri::GetPathBaseName () const
{
    sal_Int32 nPos = mPath.lastIndexOf ('/');
    sal_Int32 nTrail = 0;
    if (nPos == mPath.getLength () - 1)
    {
        // Trailing slash found. Skip.
        nTrail = 1;
        nPos = mPath.lastIndexOf ('/', nPos);
    }
    if (nPos != -1)
        return mPath.copy (nPos + 1, mPath.getLength () - nPos - 1 - nTrail);
    else
        return rtl::OUString::createFromAscii ("/");
}

bool NeonUri::operator== ( const NeonUri & rOther ) const
{
    return ( mURI == rOther.mURI );
}

::rtl::OUString NeonUri::GetPathBaseNameUnescaped () const
{
    return unescape( GetPathBaseName() );
}

::rtl::OUString NeonUri::GetPathDirName () const
{
    sal_Int32 nPos = mPath.lastIndexOf ('/');
    if (nPos == mPath.getLength () - 1)
    {
        // Trailing slash found. Skip.
        nPos = mPath.lastIndexOf ('/', nPos);
    }
    if (nPos != -1)
        return mPath.copy (0, nPos + 1);
    else
        return rtl::OUString::createFromAscii ("/");
}

void NeonUri::AppendPath (const rtl::OUString& path)
{
    if (mPath.lastIndexOf ('/') != mPath.getLength () - 1)
        mPath += rtl::OUString::createFromAscii ("/");

    mPath += path;
    calculateURI ();
};

// static
rtl::OUString NeonUri::escapeSegment( const rtl::OUString& segment )
{
    return rtl::Uri::encode( segment,
                             rtl_UriCharClassPchar,
                             rtl_UriEncodeIgnoreEscapes,
                             RTL_TEXTENCODING_UTF8 );
}

// static
rtl::OUString NeonUri::unescape( const rtl::OUString& segment )
{
    return rtl::Uri::decode( segment,
                             rtl_UriDecodeWithCharset,
                             RTL_TEXTENCODING_UTF8 );
}

// static
rtl::OUString NeonUri::makeConnectionEndPointString(
                                const rtl::OUString & rHostName, int nPort )
{
    rtl::OUString aServer( rHostName );
    if ( ( nPort != DEFAULT_HTTP_PORT ) && ( nPort != DEFAULT_HTTPS_PORT ) )
    {
        aServer += rtl::OUString::createFromAscii( ":" );
        aServer += rtl::OUString::valueOf( sal_Int32( nPort ) );
    }
    return aServer;
}

<commit_msg>INTEGRATION: CWS ipv6ooo2 (1.12.192); FILE MERGED 2004/10/11 15:43:13 kso 1.12.192.1: #i33615# - IPv6 support.<commit_after>/*************************************************************************
 *
 *  $RCSfile: NeonUri.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: pjunck $ $Date: 2004-11-03 07:59:39 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <string.h>

#ifndef _RTL_URI_HXX_
#include <rtl/uri.hxx>
#endif
#ifndef _RTL_OUSTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

#ifndef _NEONURI_HXX_
#include "NeonUri.hxx"
#endif
#ifndef _DAVEXCEPTION_HXX_
#include "DAVException.hxx"
#endif

using namespace webdav_ucp;

ne_uri NeonUri::sUriDefaultsHTTP  = { "http",  NULL, DEFAULT_HTTP_PORT,  NULL };
ne_uri NeonUri::sUriDefaultsHTTPS = { "https", NULL, DEFAULT_HTTPS_PORT, NULL };
ne_uri NeonUri::sUriDefaultsFTP   = { "ftp",   NULL, DEFAULT_FTP_PORT,   NULL };

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------

namespace {

//TODO! rtl::OString::matchIgnoreAsciiCaseAsciiL() missing
inline bool matchIgnoreAsciiCase(rtl::OString const & rStr1,
                                 sal_Char const * pStr2,
                                 sal_Int32 nStr2Len) SAL_THROW(())
{
    return
        rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
                rStr1.getStr(), rStr1.getLength(), pStr2, nStr2Len, nStr2Len)
            == 0;
}

}

NeonUri::NeonUri( const ne_uri * inUri )
    throw ( DAVException )
{
    if ( inUri == 0 )
        throw DAVException( DAVException::DAV_INVALID_ARG );

    char * uri = ne_uri_unparse( inUri );

    if ( uri == 0 )
        throw DAVException( DAVException::DAV_INVALID_ARG );

    init( rtl::OString( uri ), inUri );
    free( uri );

    calculateURI();
}

NeonUri::NeonUri( const rtl::OUString & inUri )
    throw ( DAVException )
{
    if ( inUri.getLength() <= 0 )
        throw DAVException( DAVException::DAV_INVALID_ARG );

    rtl::OString theInputUri(
        inUri.getStr(), inUri.getLength(), RTL_TEXTENCODING_UTF8 );

    ne_uri theUri;
    if ( ne_uri_parse( theInputUri.getStr(), &theUri ) != 0 )
    {
        ne_uri_free( &theUri );
        throw DAVException( DAVException::DAV_INVALID_ARG );
    }

    init( theInputUri, &theUri );
    ne_uri_free( &theUri );

    calculateURI();
}

void NeonUri::init( const rtl::OString & rUri, const ne_uri * pUri )
{
    // Complete URI.
    ne_uri * pUriDefs
        = matchIgnoreAsciiCase( rUri,
                                RTL_CONSTASCII_STRINGPARAM( "ftp:" ) ) ?
              &sUriDefaultsFTP :
          matchIgnoreAsciiCase( rUri,
                                RTL_CONSTASCII_STRINGPARAM( "https:" ) ) ?
              &sUriDefaultsHTTPS :
              &sUriDefaultsHTTP;

    mScheme   = rtl::OStringToOUString(
                    pUri->scheme ? pUri->scheme : pUriDefs->scheme,
                    RTL_TEXTENCODING_UTF8 );
    mUserInfo = rtl::OStringToOUString(
                    pUri->authinfo ? pUri->authinfo : pUriDefs->authinfo,
                    RTL_TEXTENCODING_UTF8 );
    mHostName = rtl::OStringToOUString(
                    pUri->host ? pUri->host : pUriDefs->host,
                    RTL_TEXTENCODING_UTF8 );
    mPort     = pUri->port > 0 ? pUri->port : pUriDefs->port;
    mPath     = rtl::OStringToOUString(
                    pUri->path ? pUri->path : pUriDefs->path,
                    RTL_TEXTENCODING_UTF8 );
}

// -------------------------------------------------------------------
// Destructor
// -------------------------------------------------------------------
NeonUri::~NeonUri( )
{
}

void NeonUri::calculateURI ()
{
    rtl::OUStringBuffer aBuf( mScheme );
    aBuf.appendAscii( "://" );
    if ( mUserInfo.getLength() > 0 )
    {
        //TODO! differentiate between empty and missing userinfo
        aBuf.append( mUserInfo );
        aBuf.appendAscii( "@" );
    }
    // Is host a numeric IPv6 address?
    if ( ( mHostName.indexOf( ':' ) != -1 ) &&
         ( mHostName[ 0 ] != sal_Unicode( '[' ) ) )
    {
        aBuf.appendAscii( "[" );
        aBuf.append( mHostName );
        aBuf.appendAscii( "]" );
    }
    else
    {
        aBuf.append( mHostName );
    }
    aBuf.appendAscii( ":" );
    aBuf.append( rtl::OUString::valueOf( mPort ) );
    aBuf.append( mPath );

    mURI = aBuf.makeStringAndClear();
}

::rtl::OUString NeonUri::GetPathBaseName () const
{
    sal_Int32 nPos = mPath.lastIndexOf ('/');
    sal_Int32 nTrail = 0;
    if (nPos == mPath.getLength () - 1)
    {
        // Trailing slash found. Skip.
        nTrail = 1;
        nPos = mPath.lastIndexOf ('/', nPos);
    }
    if (nPos != -1)
        return mPath.copy (nPos + 1, mPath.getLength () - nPos - 1 - nTrail);
    else
        return rtl::OUString::createFromAscii ("/");
}

bool NeonUri::operator== ( const NeonUri & rOther ) const
{
    return ( mURI == rOther.mURI );
}

::rtl::OUString NeonUri::GetPathBaseNameUnescaped () const
{
    return unescape( GetPathBaseName() );
}

::rtl::OUString NeonUri::GetPathDirName () const
{
    sal_Int32 nPos = mPath.lastIndexOf ('/');
    if (nPos == mPath.getLength () - 1)
    {
        // Trailing slash found. Skip.
        nPos = mPath.lastIndexOf ('/', nPos);
    }
    if (nPos != -1)
        return mPath.copy (0, nPos + 1);
    else
        return rtl::OUString::createFromAscii ("/");
}

void NeonUri::AppendPath (const rtl::OUString& path)
{
    if (mPath.lastIndexOf ('/') != mPath.getLength () - 1)
        mPath += rtl::OUString::createFromAscii ("/");

    mPath += path;
    calculateURI ();
};

// static
rtl::OUString NeonUri::escapeSegment( const rtl::OUString& segment )
{
    return rtl::Uri::encode( segment,
                             rtl_UriCharClassPchar,
                             rtl_UriEncodeIgnoreEscapes,
                             RTL_TEXTENCODING_UTF8 );
}

// static
rtl::OUString NeonUri::unescape( const rtl::OUString& segment )
{
    return rtl::Uri::decode( segment,
                             rtl_UriDecodeWithCharset,
                             RTL_TEXTENCODING_UTF8 );
}

// static
rtl::OUString NeonUri::makeConnectionEndPointString(
                                const rtl::OUString & rHostName, int nPort )
{
    rtl::OUStringBuffer aBuf;

    // Is host a numeric IPv6 address?
    if ( ( rHostName.indexOf( ':' ) != -1 ) &&
         ( rHostName[ 0 ] != sal_Unicode( '[' ) ) )
    {
        aBuf.appendAscii( "[" );
        aBuf.append( rHostName );
        aBuf.appendAscii( "]" );
    }
    else
    {
        aBuf.append( rHostName );
    }

    if ( ( nPort != DEFAULT_HTTP_PORT ) && ( nPort != DEFAULT_HTTPS_PORT ) )
    {
        aBuf.appendAscii( ":" );
        aBuf.append( rtl::OUString::valueOf( sal_Int32( nPort ) ) );
    }
    return aBuf.makeStringAndClear();
}

<|endoftext|>