<commit_before>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file Fileio.cxx
 * This file implements the generic fileio.
 *
 * @author Stuart W. Baker
 * @date 27 December 2012
 */

#include <sys/stat.h>
#include <cstring>
#include <cerrno>
#include <cstdarg>
#include <algorithm>
#include <fcntl.h>
#include "reent.h"
#include "Devtab.hxx"
#include "os/OS.hxx"
#include "can_ioctl.h"
#include "executor/Notifiable.hxx"

Device *Device::first = NULL;
OSMutex Device::mutex;

#ifdef TARGET_LPC11Cxx
#define NUM_OPEN_FILES     4
#else
#define NUM_OPEN_FILES     8
#endif

/** Null device instance */
class Null : public Device
{
public:
    /** Constructor */
    Null(const char* path) : Device(path)
    {
    }

    /** Open method */
    int open(File *, const char *, int, int) OVERRIDE;
    /** Close method */
    int close(File *) OVERRIDE;
    /** Read method */
    ssize_t read(File *, void *, size_t) OVERRIDE;
    /** Write method */
    ssize_t write(File *, const void *, size_t) OVERRIDE;
};

Null null("/dev/null");

/** default stdin */
const char *STDIN_DEVICE __attribute__ ((weak)) = "/dev/null";

/** default stdout */
const char *STDOUT_DEVICE __attribute__ ((weak)) = "/dev/null";

/** default stderr */
const char *STDERR_DEVICE __attribute__ ((weak)) = "/dev/null";

/** File descriptor array. */
static File files[NUM_OPEN_FILES];

/** Allocate a free file descriptor.
 * @return file number on success, else -1 on failure
 */
int fd_alloc(void)
{
    for (unsigned int i = 0; i < NUM_OPEN_FILES; i++)
    {
        if (files[i].inuse == 0)
        {
            files[i].inuse = 1;
            files[i].priv = nullptr;
            files[i].dev = nullptr;
            files[i].offset = 0;
            files[i].flags = 0;
            return i;
        }
    }
    return -1;
}

/** Free up a file descriptor.
 * @param fd number to free up
 */
void fd_free(int fd)
{
    files[fd].inuse = 0;
}

/** Looks up an fd.
 *
 * @param fd is a file descriptor as supplied to the read-write-close-ioctl
 * commands.
 * @returns NULL and sets errno if fd is invalid, otherwise the file structure
 * pointer. */
File* fd_find(int fd) {
    if (fd < 0 || fd >= NUM_OPEN_FILES)
    {
        errno = EBADF;
        return nullptr;
    }
    if (files[fd].inuse == 0)
    {
        errno = EBADF;
        return nullptr;
    }
    return &files[fd];
}

/** Open a file or device.
 * @param reent thread save reentrant structure
 * @param path file or device name
 * @param flags open flags
 * @param mode open mode, ignored in this implementation
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int _open_r(struct _reent *reent, const char *path, int flags, int mode)
{
    return Device::open(reent, path, flags, mode);
}

/** Close a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to close
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int _close_r(struct _reent *reent, int fd)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }
    if (fd >=0 && fd <= 2)
    {
        // stdin, stdout, and stderr never get closed
        return 0;
    }
    int result = f->dev->close(f);
    if (result < 0)
    {
        errno = -result;
        return -1;
    }
    fd_free(fd);
    return 0;
}

/** Read from a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to read
 * @param buf location to place read data
 * @param count number of bytes to read
 * @return number of bytes read upon success, -1 upon failure with errno containing the cause
 */
ssize_t _read_r(struct _reent *reent, int fd, void *buf, size_t count)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }
    ssize_t result = f->dev->read(f, buf, count);
    if (result < 0)
    {
        errno = -result;
        return -1;
    }
    return result;
}

/** Write to a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to write
 * @param buf location to find write data
 * @param count number of bytes to write
 * @return number of bytes written upon success, -1 upon failure with errno containing the cause
 */
ssize_t _write_r(struct _reent *reent, int fd, const void *buf, size_t count)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }
    ssize_t result = f->dev->write(f, buf, count);
    if (result < 0)
    {
        errno = -result;
        return -1;
    }
    return result;
}

/** Get the status information of a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to get status of
 * @param stat structure to fill status info into
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int _fstat_r(struct _reent *reent, int fd, struct stat *stat)
{
    return 0;
}

/** Get the tty information of a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor determine if it is a tty
 * @return 1 if a tty, else 0
 */
int _isatty_r(struct _reent *reent, int fd)
{
    return 1;
}

/** Change the offset index of a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to seek
 * @param offset offset within file
 * @param whence type of seek to complete
 * @return resulting offset from beginning of file, -1 upon failure with errno containing the cause
 */
_off_t _lseek_r(struct _reent *reent, int fd, _off_t offset, int whence)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return (_off_t) -1;
    }
    return f->dev->lseek(f, offset, whence);
}

/** Request and ioctl transaction.
 * @param fd file descriptor
 * @param key ioctl key
 * @param ... key data
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int ioctl(int fd, unsigned long int key, ...)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }

    va_list ap;
    va_start(ap, key);

    int result = f->dev->ioctl(f, key, va_arg(ap, unsigned long));

    va_end(ap);
    return result;
}

Device::Device(const char *name)
    : name(name)
{
    mutex.lock();
    next = first;
    first = this;
    mutex.unlock();
}

/** Open a file or device.
 * @param reent thread save reentrant structure
 * @param path file or device name
 * @param flags open flags
 * @param mode open mode, ignored in this implementation
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int Device::open(struct _reent *reent, const char *path, int flags, int mode)
{
    mutex.lock();
    int fd = fd_alloc();
    mutex.unlock();
    if (fd < 0)
    {
        errno = EMFILE;
        return -1;
    }
    // Sets the dev to a safe default in case we don't find the file later.
    files[fd].dev = &null;
    files[fd].flags = flags;
    for (Device *dev = first; dev != NULL; dev = dev->next)
    {
        if (!strcmp(dev->name, path))
        {
            files[fd].dev = dev;
            int result = dev->open(&files[fd], path, flags, mode);
            if (result < 0)
            {
                fd_free(fd);
                errno = -result;
                return -1;
            }
            return fd;
        }
    }
    // No device found.
    fd_free(fd);
    errno = ENODEV;
    return -1;
}

off_t Device::lseek(File* f, off_t offset, int whence)
{
    switch (whence) {
    case SEEK_SET:
        f->offset = offset;
        return offset;
    case SEEK_CUR:
        f->offset += offset;
        return f->offset;
    }
    errno = EINVAL;
    return (off_t)-1;
}

/** Open a device.
 * @param file new file reference to this device
 * @param path file or device name
 * @param flags open flags
 * @param mode open mode
 * @return 0 upon success, negative errno upon failure
 */
int Null::open(File* file, const char *path, int flags, int mode)
{
    return 0;
}

/** Close a device.
 * @param file file reference for this device
 * @param node node reference for this device
 * @return 0 upon success, negative errno upon failure
 */
int Null::close(File *file)
{
    return 0;
}

/** Read from a file or device.
 * @param file file reference for this device
 * @param buf location to place read data
 * @param count number of bytes to read
 * @return number of bytes read upon success, -1 upon failure with errno containing the cause
 */
ssize_t Null::read(File *file, void *buf, size_t count)
{
    // /dev/null returns EOF when trying to read from it.
    return 0;
}

/** Write to a file or device.
 * @param file file reference for this device
 * @param buf location to find write data
 * @param count number of bytes to write
 * @return number of bytes written upon success, -1 upon failure with errno containing the cause
 */
ssize_t Null::write(File *file, const void *buf, size_t count)
{
    return count;
}

int Device::ioctl(File *, unsigned long int, unsigned long) {
    return -EINVAL;
}

/** Open method */
int Node::open(File *, const char *, int, int) OVERRIDE {
    OSMutexLock l(&lock_);
    if (references_++ == 0) {
        enable();
    }
    return 0;
}

/** Close method */
int Node::close(File *) OVERRIDE {
    OSMutexLock l(&lock_);
    if (--references_ <= 0) {
        disable();
        references_ = 0;
    }
    return 0;
}

/** Request an ioctl transaction
 * @param file file reference for this device
 * @param node node reference for this device
 * @param key ioctl key
 * @param data key data
 */
int NonBlockNode::ioctl(File *file, unsigned long int key, unsigned long data)
{
    /* sanity check to be sure we have a valid key for this device */
    HASSERT(IOC_TYPE(key) == CAN_IOC_MAGIC);

    // Will be called at the end if non-null.
    Notifiable* n = nullptr;

    if (IOC_SIZE(key) == NOTIFIABLE_TYPE) {
        n = reinterpret_cast<Notifiable*>(data);
    }

    switch (key)
    {
        default:
            return -EINVAL;
        case CAN_IOC_READ_ACTIVE:
            portENTER_CRITICAL();
            if (!has_rx_buffer_data())
            {
                swap(n, readableNotify_);
            }
            portEXIT_CRITICAL();
            break;
        case CAN_IOC_WRITE_ACTIVE:
            portENTER_CRITICAL();
            if (!has_tx_buffer_space())
            {
                swap(n, writableNotify_);
            }
            portEXIT_CRITICAL();
            break;
    }
    if (n)
    {
        n->notify();
    }
    return 0;
}
<commit_msg>trivial coding style change<commit_after>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file Fileio.cxx
 * This file implements the generic fileio.
 *
 * @author Stuart W. Baker
 * @date 27 December 2012
 */

#include <sys/stat.h>
#include <cstring>
#include <cerrno>
#include <cstdarg>
#include <algorithm>
#include <fcntl.h>
#include "reent.h"
#include "Devtab.hxx"
#include "os/OS.hxx"
#include "can_ioctl.h"
#include "executor/Notifiable.hxx"

Device *Device::first = NULL;
OSMutex Device::mutex;

#ifdef TARGET_LPC11Cxx
#define NUM_OPEN_FILES     4
#else
#define NUM_OPEN_FILES     8
#endif

/** Null device instance */
class Null : public Device
{
public:
    /** Constructor */
    Null(const char* path) : Device(path)
    {
    }

    /** Open method */
    int open(File *, const char *, int, int) OVERRIDE;
    /** Close method */
    int close(File *) OVERRIDE;
    /** Read method */
    ssize_t read(File *, void *, size_t) OVERRIDE;
    /** Write method */
    ssize_t write(File *, const void *, size_t) OVERRIDE;
};

Null null("/dev/null");

/** default stdin */
const char *STDIN_DEVICE __attribute__ ((weak)) = "/dev/null";

/** default stdout */
const char *STDOUT_DEVICE __attribute__ ((weak)) = "/dev/null";

/** default stderr */
const char *STDERR_DEVICE __attribute__ ((weak)) = "/dev/null";

/** File descriptor array. */
static File files[NUM_OPEN_FILES];

/** Allocate a free file descriptor.
 * @return file number on success, else -1 on failure
 */
int fd_alloc(void)
{
    for (unsigned int i = 0; i < NUM_OPEN_FILES; i++)
    {
        if (files[i].inuse == 0)
        {
            files[i].inuse = 1;
            files[i].priv = nullptr;
            files[i].dev = nullptr;
            files[i].offset = 0;
            files[i].flags = 0;
            return i;
        }
    }
    return -1;
}

/** Free up a file descriptor.
 * @param fd number to free up
 */
void fd_free(int fd)
{
    files[fd].inuse = 0;
}

/** Looks up an fd.
 *
 * @param fd is a file descriptor as supplied to the read-write-close-ioctl
 * commands.
 * @returns NULL and sets errno if fd is invalid, otherwise the file structure
 * pointer. */
File* fd_find(int fd) {
    if (fd < 0 || fd >= NUM_OPEN_FILES)
    {
        errno = EBADF;
        return nullptr;
    }
    if (files[fd].inuse == 0)
    {
        errno = EBADF;
        return nullptr;
    }
    return &files[fd];
}

/** Open a file or device.
 * @param reent thread save reentrant structure
 * @param path file or device name
 * @param flags open flags
 * @param mode open mode, ignored in this implementation
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int _open_r(struct _reent *reent, const char *path, int flags, int mode)
{
    return Device::open(reent, path, flags, mode);
}

/** Close a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to close
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int _close_r(struct _reent *reent, int fd)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }
    if (fd >=0 && fd <= 2)
    {
        // stdin, stdout, and stderr never get closed
        return 0;
    }
    int result = f->dev->close(f);
    if (result < 0)
    {
        errno = -result;
        return -1;
    }
    fd_free(fd);
    return 0;
}

/** Read from a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to read
 * @param buf location to place read data
 * @param count number of bytes to read
 * @return number of bytes read upon success, -1 upon failure with errno containing the cause
 */
ssize_t _read_r(struct _reent *reent, int fd, void *buf, size_t count)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }
    ssize_t result = f->dev->read(f, buf, count);
    if (result < 0)
    {
        errno = -result;
        return -1;
    }
    return result;
}

/** Write to a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to write
 * @param buf location to find write data
 * @param count number of bytes to write
 * @return number of bytes written upon success, -1 upon failure with errno containing the cause
 */
ssize_t _write_r(struct _reent *reent, int fd, const void *buf, size_t count)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }
    ssize_t result = f->dev->write(f, buf, count);
    if (result < 0)
    {
        errno = -result;
        return -1;
    }
    return result;
}

/** Get the status information of a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to get status of
 * @param stat structure to fill status info into
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int _fstat_r(struct _reent *reent, int fd, struct stat *stat)
{
    return 0;
}

/** Get the tty information of a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor determine if it is a tty
 * @return 1 if a tty, else 0
 */
int _isatty_r(struct _reent *reent, int fd)
{
    return 1;
}

/** Change the offset index of a file or device.
 * @param reent thread save reentrant structure
 * @param fd file descriptor to seek
 * @param offset offset within file
 * @param whence type of seek to complete
 * @return resulting offset from beginning of file, -1 upon failure with errno containing the cause
 */
_off_t _lseek_r(struct _reent *reent, int fd, _off_t offset, int whence)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return (_off_t) -1;
    }
    return f->dev->lseek(f, offset, whence);
}

/** Request and ioctl transaction.
 * @param fd file descriptor
 * @param key ioctl key
 * @param ... key data
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int ioctl(int fd, unsigned long int key, ...)
{
    File* f = fd_find(fd);
    if (!f)
    {
        return -1;
    }

    va_list ap;
    va_start(ap, key);

    int result = f->dev->ioctl(f, key, va_arg(ap, unsigned long));

    va_end(ap);
    return result;
}

Device::Device(const char *name)
    : name(name)
{
    mutex.lock();
    next = first;
    first = this;
    mutex.unlock();
}

/** Open a file or device.
 * @param reent thread save reentrant structure
 * @param path file or device name
 * @param flags open flags
 * @param mode open mode, ignored in this implementation
 * @return 0 upon success, -1 upon failure with errno containing the cause
 */
int Device::open(struct _reent *reent, const char *path, int flags, int mode)
{
    mutex.lock();
    int fd = fd_alloc();
    mutex.unlock();
    if (fd < 0)
    {
        errno = EMFILE;
        return -1;
    }
    // Sets the dev to a safe default in case we don't find the file later.
    files[fd].dev = &null;
    files[fd].flags = flags;
    for (Device *dev = first; dev != NULL; dev = dev->next)
    {
        if (!strcmp(dev->name, path))
        {
            files[fd].dev = dev;
            int result = dev->open(&files[fd], path, flags, mode);
            if (result < 0)
            {
                fd_free(fd);
                errno = -result;
                return -1;
            }
            return fd;
        }
    }
    // No device found.
    fd_free(fd);
    errno = ENODEV;
    return -1;
}

off_t Device::lseek(File* f, off_t offset, int whence)
{
    switch (whence)
    {
        case SEEK_SET:
            f->offset = offset;
            return offset;
        case SEEK_CUR:
            f->offset += offset;
            return f->offset;
    }
    errno = EINVAL;
    return (off_t)-1;
}

/** Open a device.
 * @param file new file reference to this device
 * @param path file or device name
 * @param flags open flags
 * @param mode open mode
 * @return 0 upon success, negative errno upon failure
 */
int Null::open(File* file, const char *path, int flags, int mode)
{
    return 0;
}

/** Close a device.
 * @param file file reference for this device
 * @param node node reference for this device
 * @return 0 upon success, negative errno upon failure
 */
int Null::close(File *file)
{
    return 0;
}

/** Read from a file or device.
 * @param file file reference for this device
 * @param buf location to place read data
 * @param count number of bytes to read
 * @return number of bytes read upon success, -1 upon failure with errno containing the cause
 */
ssize_t Null::read(File *file, void *buf, size_t count)
{
    // /dev/null returns EOF when trying to read from it.
    return 0;
}

/** Write to a file or device.
 * @param file file reference for this device
 * @param buf location to find write data
 * @param count number of bytes to write
 * @return number of bytes written upon success, -1 upon failure with errno containing the cause
 */
ssize_t Null::write(File *file, const void *buf, size_t count)
{
    return count;
}

int Device::ioctl(File *, unsigned long int, unsigned long) {
    return -EINVAL;
}

/** Open method */
int Node::open(File *, const char *, int, int) OVERRIDE {
    OSMutexLock l(&lock_);
    if (references_++ == 0) {
        enable();
    }
    return 0;
}

/** Close method */
int Node::close(File *) OVERRIDE {
    OSMutexLock l(&lock_);
    if (--references_ <= 0) {
        disable();
        references_ = 0;
    }
    return 0;
}

/** Request an ioctl transaction
 * @param file file reference for this device
 * @param node node reference for this device
 * @param key ioctl key
 * @param data key data
 */
int NonBlockNode::ioctl(File *file, unsigned long int key, unsigned long data)
{
    /* sanity check to be sure we have a valid key for this device */
    HASSERT(IOC_TYPE(key) == CAN_IOC_MAGIC);

    // Will be called at the end if non-null.
    Notifiable* n = nullptr;

    if (IOC_SIZE(key) == NOTIFIABLE_TYPE) {
        n = reinterpret_cast<Notifiable*>(data);
    }

    switch (key)
    {
        default:
            return -EINVAL;
        case CAN_IOC_READ_ACTIVE:
            portENTER_CRITICAL();
            if (!has_rx_buffer_data())
            {
                swap(n, readableNotify_);
            }
            portEXIT_CRITICAL();
            break;
        case CAN_IOC_WRITE_ACTIVE:
            portENTER_CRITICAL();
            if (!has_tx_buffer_space())
            {
                swap(n, writableNotify_);
            }
            portEXIT_CRITICAL();
            break;
    }
    if (n)
    {
        n->notify();
    }
    return 0;
}
<|endoftext|>


<commit_before>/* Copyright 2014 - 2015 CyberTech Labs Ltd.
 *
 * 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 "trikScriptRunnerTest.h"

#include <QtCore/QEventLoop>

#include <trikControl/brickFactory.h>
#include <trikKernel/fileUtils.h>
#include <testUtils/wait.h>

using namespace tests;

QScriptValue scriptAssert(QScriptContext *context, QScriptEngine *engine)
{
	Q_UNUSED(engine);

	if (context->argumentCount() != 1) {
		ADD_FAILURE() << "'assert' shall have exactly one argument";
		return {};
	}

	if (!context->argument(0).toBool()) {
		ADD_FAILURE() << "Assertion failure at\n"
				<< QStringList(context->backtrace().mid(1)).join("\n").toStdString();
	}

	return {};
}

void TrikScriptRunnerTest::SetUp()
{
	mBrick.reset(trikControl::BrickFactory::create("./", "./"));
	mScriptRunner.reset(new trikScriptRunner::TrikScriptRunner(*mBrick, nullptr, nullptr));
	mScriptRunner->registerUserFunction("assert", scriptAssert);
}

void TrikScriptRunnerTest::TearDown()
{
}

void TrikScriptRunnerTest::run(const QString &script)
{
	QEventLoop waitingLoop;
	QObject::connect(mScriptRunner.data(), SIGNAL(completed(QString, int)), &waitingLoop, SLOT(quit()));
	mScriptRunner->run(script);

	waitingLoop.exec();
}

void TrikScriptRunnerTest::runDirectCommandAndWaitForQuit(const QString &script)
{
	QEventLoop waitingLoop;
	QObject::connect(mScriptRunner.data(), SIGNAL(completed(QString, int)), &waitingLoop, SLOT(quit()));
	mScriptRunner->runDirectCommand(script);

	waitingLoop.exec();
}

void TrikScriptRunnerTest::runFromFile(const QString &fileName)
{
	const auto fileContents = trikKernel::FileUtils::readFromFile("data/" + fileName);
	run(fileContents);
}

trikScriptRunner::TrikScriptRunner &TrikScriptRunnerTest::scriptRunner()
{
	return *mScriptRunner;
}

TEST_F(TrikScriptRunnerTest, sanityCheck)
{
	run("1 + 1");
}

TEST_F(TrikScriptRunnerTest, fileTest)
{
	runFromFile("file-test.js");
}

TEST_F(TrikScriptRunnerTest, asyncSystemTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	runFromFile("async-system-test.js");
	ASSERT_FALSE(testFile.exists());
	tests::utils::Wait::wait(2500);
	ASSERT_TRUE(testFile.exists());
}

TEST_F(TrikScriptRunnerTest, syncSystemTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	runFromFile("sync-system-test.js");
	ASSERT_TRUE(testFile.exists());
}

TEST_F(TrikScriptRunnerTest, directCommandTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	scriptRunner().runDirectCommand("script.system('echo 123 > test', true);");
	tests::utils::Wait::wait(100);
	ASSERT_TRUE(testFile.exists());
	scriptRunner().runDirectCommand("script.system('rm test', true);");
	tests::utils::Wait::wait(100);
	ASSERT_FALSE(testFile.exists());
	scriptRunner().runDirectCommand("script.quit();");
}

TEST_F(TrikScriptRunnerTest, directCommandThatQuitsImmediatelyTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	runDirectCommandAndWaitForQuit("script.system('echo 123 > test', true); script.quit();");
	ASSERT_TRUE(testFile.exists());
	runDirectCommandAndWaitForQuit("script.system('rm test', true); script.quit();");
	ASSERT_FALSE(testFile.exists());
}
<commit_msg>Added test that sumultaneously launches two scripts<commit_after>/* Copyright 2014 - 2015 CyberTech Labs Ltd.
 *
 * 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 "trikScriptRunnerTest.h"

#include <QtCore/QEventLoop>

#include <trikControl/brickFactory.h>
#include <trikKernel/fileUtils.h>
#include <testUtils/wait.h>

using namespace tests;

QScriptValue scriptAssert(QScriptContext *context, QScriptEngine *engine)
{
	Q_UNUSED(engine);

	if (context->argumentCount() != 1) {
		ADD_FAILURE() << "'assert' shall have exactly one argument";
		return {};
	}

	if (!context->argument(0).toBool()) {
		ADD_FAILURE() << "Assertion failure at\n"
				<< QStringList(context->backtrace().mid(1)).join("\n").toStdString();
	}

	return {};
}

void TrikScriptRunnerTest::SetUp()
{
	mBrick.reset(trikControl::BrickFactory::create("./", "./"));
	mScriptRunner.reset(new trikScriptRunner::TrikScriptRunner(*mBrick, nullptr, nullptr));
	mScriptRunner->registerUserFunction("assert", scriptAssert);
}

void TrikScriptRunnerTest::TearDown()
{
}

void TrikScriptRunnerTest::run(const QString &script)
{
	QEventLoop waitingLoop;
	QObject::connect(mScriptRunner.data(), SIGNAL(completed(QString, int)), &waitingLoop, SLOT(quit()));
	mScriptRunner->run(script);

	waitingLoop.exec();
}

void TrikScriptRunnerTest::runDirectCommandAndWaitForQuit(const QString &script)
{
	QEventLoop waitingLoop;
	QObject::connect(mScriptRunner.data(), SIGNAL(completed(QString, int)), &waitingLoop, SLOT(quit()));
	mScriptRunner->runDirectCommand(script);

	waitingLoop.exec();
}

void TrikScriptRunnerTest::runFromFile(const QString &fileName)
{
	const auto fileContents = trikKernel::FileUtils::readFromFile("data/" + fileName);
	run(fileContents);
}

trikScriptRunner::TrikScriptRunner &TrikScriptRunnerTest::scriptRunner()
{
	return *mScriptRunner;
}

TEST_F(TrikScriptRunnerTest, sanityCheck)
{
	run("1 + 1");
}

TEST_F(TrikScriptRunnerTest, fileTest)
{
	runFromFile("file-test.js");
}

TEST_F(TrikScriptRunnerTest, asyncSystemTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	runFromFile("async-system-test.js");
	ASSERT_FALSE(testFile.exists());
	tests::utils::Wait::wait(2500);
	ASSERT_TRUE(testFile.exists());
}

TEST_F(TrikScriptRunnerTest, syncSystemTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	runFromFile("sync-system-test.js");
	ASSERT_TRUE(testFile.exists());
}

TEST_F(TrikScriptRunnerTest, directCommandTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	scriptRunner().runDirectCommand("script.system('echo 123 > test', true);");
	tests::utils::Wait::wait(100);
	ASSERT_TRUE(testFile.exists());
	scriptRunner().runDirectCommand("script.system('rm test', true);");
	tests::utils::Wait::wait(100);
	ASSERT_FALSE(testFile.exists());
	scriptRunner().runDirectCommand("script.quit();");
}

TEST_F(TrikScriptRunnerTest, directCommandThatQuitsImmediatelyTest)
{
	QFile testFile("test");
	testFile.remove();
	ASSERT_FALSE(testFile.exists());
	runDirectCommandAndWaitForQuit("script.system('echo 123 > test', true); script.quit();");
	ASSERT_TRUE(testFile.exists());
	runDirectCommandAndWaitForQuit("script.system('rm test', true); script.quit();");
	ASSERT_FALSE(testFile.exists());
}

TEST_F(TrikScriptRunnerTest, twoProgramsTest)
{
	scriptRunner().run("script.wait(500);");
	tests::utils::Wait::wait(100);
	scriptRunner().run("script.wait(500);");
	tests::utils::Wait::wait(600);
}
<|endoftext|>


<commit_before>/**
 * @file compile_filter_main.cc
 *
 * @section LICENSE
 *
 * The MIT License
 *
 * @copyright Copyright (c) 2022 TileDB, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "../bzip_compressor.h"
#include "../dd_compressor.h"
#include "../dict_compressor.h"
#include "../gzip_compressor.h"
#include "../lz4_compressor.h"
#include "../rle_compressor.h"
#include "../zstd_compressor.h"

#include "tiledb/common/common.h"
#include "tiledb/common/scoped_executor.h"
#include "tiledb/sm/buffer/buffer.h"
#include "tiledb/sm/filter/filter_buffer.h"
#include "tiledb/sm/filter/filter_storage.h"
#include "tiledb/sm/misc/types.h"

#include "gzip_wrappers.h"

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>

#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif

int main(int argc, char* argv[]) {
  (void)sizeof(tiledb::sm::GZip);

  const int seg_sz = 4096;
  char fbuf[seg_sz];
  auto filter_stg = make_shared<tiledb::sm::FilterStorage>(HERE());
  auto inbuf = make_shared<tiledb::sm::Buffer>(HERE());
  auto zipped_buf = make_shared<tiledb::sm::FilterBuffer>(HERE(), &*filter_stg);
  uint64_t nread;
  uint64_t cntread = 0;

  auto infile = stdin;
  auto outfile = stdout;

  // note: If stdout used ( '>' ), compressed data subject to being
  // intermixed with any application output, corrupting the compressed
  // output stream.

  if (argc > 1) {
    outfile = fopen(argv[1], "w+b");
    if (!outfile) {
      fprintf(stderr, "Unable to create file %s\n", argv[1]);
      exit(-2);
    }
  }
  auto closefile = [&]() { fclose(outfile); };
  tiledb::common::ScopedExecutor onexit1(closefile);

#ifdef _WIN32
  // need to be sure in/out are in binay mode, windows default won't be!!!
  if ((-1 == _setmode(fileno(stdin), _O_BINARY)) ||
      (-1 == _setmode(fileno(stdout), _O_BINARY))) {
    fprintf(stderr, "failure setting stdin/stdout to binary mode!");
    exit(-1);
  }
#endif

  do {
    nread = fread(fbuf, 1, sizeof(fbuf), infile);
    if (nread) {
      inbuf->write(fbuf, nread);
      cntread += nread;
    }
  } while (nread == sizeof(fbuf));

  tiledb::sm::ConstBuffer const_inbuf(&*inbuf);
  // Ensure space in output buffer for worst case.
  if (!zipped_buf->prepend_buffer(inbuf->size()).ok()) {
    printf("output buffer allocation error!\n");
    exit(-3);
  }
  tiledb::sm::Buffer* out_buffer_ptr = zipped_buf->buffer_ptr(0);
  assert(out_buffer_ptr != nullptr);
  out_buffer_ptr->reset_offset();
  if (!tiledb::sm::GZip::compress(9, &const_inbuf, out_buffer_ptr).ok()) {
    printf("Error compressing data!\n");
    exit(-4);
  }
  std::cerr << "sizes input " << inbuf->size() << ", compressed "
            << out_buffer_ptr->size() << std::endl;
  if(0) // leave available for future possible diagnostic need
  {
    // save compressed data to allow examination from filesystem
    auto outgzip = fopen("magic-mgc.tdbgzip", "wb");
    if (!outgzip) {
      fprintf(stderr, "Unable to create magic-mgc.tdbgzip!\n");
      exit(-21);
    }
    if (fwrite(out_buffer_ptr->data(0), 1, out_buffer_ptr->size(), outgzip) !=
        out_buffer_ptr->size()) {
      fprintf(stderr, "write failure magic-mgc.tdbgzip!\n");
      exit(-22);
    }
    fclose(outgzip);
  }
  auto tdb_gzip_buf = make_shared<tiledb::sm::Buffer>(HERE());

  unsigned maxnperline = 128;
  auto addbytevals = [&](void* _pbytes, uint64_t nbytes) {
    uint8_t* pbytes = reinterpret_cast<uint8_t*>(_pbytes);
    static unsigned cntout = 0;
    for (auto i = 0u; i < nbytes; ++i) {
      fprintf(outfile, "'\\x%02x',", pbytes[i]);
      if (++cntout > maxnperline) {
        cntout = 0;
        fprintf(outfile, "\n");
      }
    }
  };
  addbytevals(&cntread, sizeof(cntread));
  tdb_gzip_buf->write(&cntread, sizeof(cntread));
  uint64_t compressed_size = zipped_buf->size();
  addbytevals(&compressed_size, sizeof(compressed_size));
  tdb_gzip_buf->write(&compressed_size, sizeof(compressed_size));
  auto nremaining = zipped_buf->size();
  // vs19 complained...
  // A) could not find raw string literal terminator
  //    for almost identical error, though not quite same cause, can see
  // https://developercommunity.visualstudio.com/t/bug-in-raw-string-implementation-converning-eof-02/254730)
  // vs19 16.11.3 was in use with tiledb failed #include of raw literal file
  // B) that (all data as) one string was to large a string
  // C) many shorter strings expecting concatention were causing
  //    compiler heap memory errors (100+GB)
  // D) caused warnings trying to do direct 0xXX numeric values
  // end result format is comma delimited '\xXX' characters with periodic line
  // splits
  while (nremaining) {
    auto ntowrite = nremaining > seg_sz ? seg_sz : nremaining;
    // TBD: error from ->read()?
    if (!zipped_buf->read(fbuf, ntowrite).ok()) {
      printf("ERROR reading from compressed data.\n");
      exit(-7);
    }
    if (!tdb_gzip_buf->write(fbuf, ntowrite).ok()) {
      printf("ERROR writing compressed format buffer.");
      exit(-11);
    }
    addbytevals(fbuf, ntowrite);
    nremaining -= ntowrite;
  }

  // brief sanity check that wrapper compression matches unwrapped compression
  shared_ptr<tiledb::sm::Buffer> out_gzipped_buf =
      make_shared<tiledb::sm::Buffer>(HERE());
  gzip_compress(out_gzipped_buf, inbuf->data(0), inbuf->size());
  if (out_gzipped_buf->size() != tdb_gzip_buf->size()) {
    printf(
        "Error, compressed data sizes mismatch! %" PRIu64 ", %" PRIu64 "u\n",
        out_gzipped_buf->size(),
        tdb_gzip_buf->size());
    exit(-13);
  }
  if (memcmp(
          out_gzipped_buf->data(0),
          tdb_gzip_buf->data(0),
          out_gzipped_buf->size())  // tdb_gzip_buf->size())
  ) {
    printf("Error, compressed data mismatch!\n");
    exit(-17);
  }

  shared_ptr<tiledb::sm::ByteVecValue> expanded_buffer =
      make_shared<tiledb::sm::ByteVecValue>(HERE());

  // brief sanity check the decompressed()d data matches original
  tdb_gzip_buf->set_offset(0);
  gzip_decompress(expanded_buffer, static_cast<uint8_t*>(tdb_gzip_buf->data()));
  if (expanded_buffer->size() != inbuf->size()) {
    fprintf(stderr, "re-expanded size different from original size!\n");
    exit(-29);
  }
  if (memcmp(expanded_buffer->data(), inbuf->data(), inbuf->size())) {
    printf("Error uncompress data != original data!\n");
    exit(-21);
  }

  return 0;
}
<commit_msg>clang format<commit_after>/**
 * @file compile_filter_main.cc
 *
 * @section LICENSE
 *
 * The MIT License
 *
 * @copyright Copyright (c) 2022 TileDB, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "../bzip_compressor.h"
#include "../dd_compressor.h"
#include "../dict_compressor.h"
#include "../gzip_compressor.h"
#include "../lz4_compressor.h"
#include "../rle_compressor.h"
#include "../zstd_compressor.h"

#include "tiledb/common/common.h"
#include "tiledb/common/scoped_executor.h"
#include "tiledb/sm/buffer/buffer.h"
#include "tiledb/sm/filter/filter_buffer.h"
#include "tiledb/sm/filter/filter_storage.h"
#include "tiledb/sm/misc/types.h"

#include "gzip_wrappers.h"

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>

#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif

int main(int argc, char* argv[]) {
  (void)sizeof(tiledb::sm::GZip);

  const int seg_sz = 4096;
  char fbuf[seg_sz];
  auto filter_stg = make_shared<tiledb::sm::FilterStorage>(HERE());
  auto inbuf = make_shared<tiledb::sm::Buffer>(HERE());
  auto zipped_buf = make_shared<tiledb::sm::FilterBuffer>(HERE(), &*filter_stg);
  uint64_t nread;
  uint64_t cntread = 0;

  auto infile = stdin;
  auto outfile = stdout;

  // note: If stdout used ( '>' ), compressed data subject to being
  // intermixed with any application output, corrupting the compressed
  // output stream.

  if (argc > 1) {
    outfile = fopen(argv[1], "w+b");
    if (!outfile) {
      fprintf(stderr, "Unable to create file %s\n", argv[1]);
      exit(-2);
    }
  }
  auto closefile = [&]() { fclose(outfile); };
  tiledb::common::ScopedExecutor onexit1(closefile);

#ifdef _WIN32
  // need to be sure in/out are in binay mode, windows default won't be!!!
  if ((-1 == _setmode(fileno(stdin), _O_BINARY)) ||
      (-1 == _setmode(fileno(stdout), _O_BINARY))) {
    fprintf(stderr, "failure setting stdin/stdout to binary mode!");
    exit(-1);
  }
#endif

  do {
    nread = fread(fbuf, 1, sizeof(fbuf), infile);
    if (nread) {
      inbuf->write(fbuf, nread);
      cntread += nread;
    }
  } while (nread == sizeof(fbuf));

  tiledb::sm::ConstBuffer const_inbuf(&*inbuf);
  // Ensure space in output buffer for worst case.
  if (!zipped_buf->prepend_buffer(inbuf->size()).ok()) {
    printf("output buffer allocation error!\n");
    exit(-3);
  }
  tiledb::sm::Buffer* out_buffer_ptr = zipped_buf->buffer_ptr(0);
  assert(out_buffer_ptr != nullptr);
  out_buffer_ptr->reset_offset();
  if (!tiledb::sm::GZip::compress(9, &const_inbuf, out_buffer_ptr).ok()) {
    printf("Error compressing data!\n");
    exit(-4);
  }
  std::cerr << "sizes input " << inbuf->size() << ", compressed "
            << out_buffer_ptr->size() << std::endl;
  if (0)  // leave available for future possible diagnostic need
  {
    // save compressed data to allow examination from filesystem
    auto outgzip = fopen("magic-mgc.tdbgzip", "wb");
    if (!outgzip) {
      fprintf(stderr, "Unable to create magic-mgc.tdbgzip!\n");
      exit(-21);
    }
    if (fwrite(out_buffer_ptr->data(0), 1, out_buffer_ptr->size(), outgzip) !=
        out_buffer_ptr->size()) {
      fprintf(stderr, "write failure magic-mgc.tdbgzip!\n");
      exit(-22);
    }
    fclose(outgzip);
  }
  auto tdb_gzip_buf = make_shared<tiledb::sm::Buffer>(HERE());

  unsigned maxnperline = 128;
  auto addbytevals = [&](void* _pbytes, uint64_t nbytes) {
    uint8_t* pbytes = reinterpret_cast<uint8_t*>(_pbytes);
    static unsigned cntout = 0;
    for (auto i = 0u; i < nbytes; ++i) {
      fprintf(outfile, "'\\x%02x',", pbytes[i]);
      if (++cntout > maxnperline) {
        cntout = 0;
        fprintf(outfile, "\n");
      }
    }
  };
  addbytevals(&cntread, sizeof(cntread));
  tdb_gzip_buf->write(&cntread, sizeof(cntread));
  uint64_t compressed_size = zipped_buf->size();
  addbytevals(&compressed_size, sizeof(compressed_size));
  tdb_gzip_buf->write(&compressed_size, sizeof(compressed_size));
  auto nremaining = zipped_buf->size();
  // vs19 complained...
  // A) could not find raw string literal terminator
  //    for almost identical error, though not quite same cause, can see
  // https://developercommunity.visualstudio.com/t/bug-in-raw-string-implementation-converning-eof-02/254730)
  // vs19 16.11.3 was in use with tiledb failed #include of raw literal file
  // B) that (all data as) one string was to large a string
  // C) many shorter strings expecting concatention were causing
  //    compiler heap memory errors (100+GB)
  // D) caused warnings trying to do direct 0xXX numeric values
  // end result format is comma delimited '\xXX' characters with periodic line
  // splits
  while (nremaining) {
    auto ntowrite = nremaining > seg_sz ? seg_sz : nremaining;
    // TBD: error from ->read()?
    if (!zipped_buf->read(fbuf, ntowrite).ok()) {
      printf("ERROR reading from compressed data.\n");
      exit(-7);
    }
    if (!tdb_gzip_buf->write(fbuf, ntowrite).ok()) {
      printf("ERROR writing compressed format buffer.");
      exit(-11);
    }
    addbytevals(fbuf, ntowrite);
    nremaining -= ntowrite;
  }

  // brief sanity check that wrapper compression matches unwrapped compression
  shared_ptr<tiledb::sm::Buffer> out_gzipped_buf =
      make_shared<tiledb::sm::Buffer>(HERE());
  gzip_compress(out_gzipped_buf, inbuf->data(0), inbuf->size());
  if (out_gzipped_buf->size() != tdb_gzip_buf->size()) {
    printf(
        "Error, compressed data sizes mismatch! %" PRIu64 ", %" PRIu64 "u\n",
        out_gzipped_buf->size(),
        tdb_gzip_buf->size());
    exit(-13);
  }
  if (memcmp(
          out_gzipped_buf->data(0),
          tdb_gzip_buf->data(0),
          out_gzipped_buf->size())  // tdb_gzip_buf->size())
  ) {
    printf("Error, compressed data mismatch!\n");
    exit(-17);
  }

  shared_ptr<tiledb::sm::ByteVecValue> expanded_buffer =
      make_shared<tiledb::sm::ByteVecValue>(HERE());

  // brief sanity check the decompressed()d data matches original
  tdb_gzip_buf->set_offset(0);
  gzip_decompress(expanded_buffer, static_cast<uint8_t*>(tdb_gzip_buf->data()));
  if (expanded_buffer->size() != inbuf->size()) {
    fprintf(stderr, "re-expanded size different from original size!\n");
    exit(-29);
  }
  if (memcmp(expanded_buffer->data(), inbuf->data(), inbuf->size())) {
    printf("Error uncompress data != original data!\n");
    exit(-21);
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "run_submission.h"
#include <stdio.h>
#include <string.h>

const char * safe_get(Table& t, const char* key, const char* defaultValue)
{
  Table::const_iterator got = t.find(key);
  if (got == t.end())
    return defaultValue;
  return got->second.c_str();
}

void translate(Table& envT, Table& userT, DTable& userDT)
{
  enum QueueType { UNKNOWN = -1, SLURM = 1, SGE, SLURM_TACC, PBS, LSF };
  QueueType queueType = UNKNOWN;

  // Pick type of queuing system.

  if (envT.count("SGE_ACCOUNT"))
    queueType = SGE;
  else if (envT.count("SLURM_TACC_ACCOUNT") || envT.count("SLURM_TACC_JOBNAME"))
    queueType = SLURM_TACC;
  else if (envT.count("SBATCH_ACCOUNT"))
    queueType = SLURM;
  else if (envT.count("PBS_JOBID"))
    queueType = PBS;
  else if (envT.count("LSF_VERSION"))
    queueType = LSF;

  // userDT["num_tasks"] has a safe default value of 1 if not overridden by the run.
  userDT["num_cores"]  = userDT["num_tasks"];

  // Now fill in num_cores, num_nodes, account, job_id, queue, submit_host in userT from the environment
  if (queueType == SGE)
    {
      userT["account"]     = safe_get(envT,        "SGE_ACCOUNT", "unknown");
      userT["job_id"]      = safe_get(envT,        "JOB_ID",      "unknown");
      userT["queue"]       = safe_get(envT,        "QUEUE",       "unknown");
      userT["submit_host"] = "unknown";
      userDT["num_nodes"]  = strtod(safe_get(envT, "NHOSTS",      "1"),        (char **) NULL);
    }
  else if (queueType == SLURM_TACC || queueType == SLURM )
    {
      userT["job_id"]      = safe_get(envT,        "SLURM_JOB_ID",        "unknown");
      userT["queue"]       = safe_get(envT,        "SLURM_QUEUE",         "unknown");
      userT["submit_host"] = safe_get(envT,        "SLURM_SUBMIT_HOST",   "unknown");
      userT["account"]     = safe_get(envT,        "SLURM_TACC_ACCOUNT",  "unknown");
      userDT["num_nodes"]  = strtod(safe_get(envT, "SLURM_NNODES",        "1"),       (char **) NULL);
    }
  else if (queueType == PBS)
    {
      std::string job_id   = safe_get(envT,        "PBS_JOBID",     "unknown");
      std::size_t idx      = job_id.find_first_not_of("0123456789");
      userT["job_id"]      = job_id.substr(0,idx);
      userT["queue"]       = safe_get(envT,        "PBS_QUEUE",     "unknown");
      userT["submit_host"] = safe_get(envT,        "PBS_O_HOST",    "unknown");
      userT["account"]     = safe_get(envT,        "PBS_ACCOUNT",   "unknown");
      userDT["num_nodes"]  = strtod(safe_get(envT, "PBS_NUM_NODES", "1"),       (char **) NULL);;
    }
  else if (queueType == LSF)
    {
      // We must count the number of "words" in mcpuA.
      // We find the number of words by counting space blocks and add 1;
      // then divide by 2. then convert to a string.
      std::string mcpuA    = safe_get(envT,  "LSB_MCPU_HOSTS",  "a 1");
      std::string::size_type idx;
      int count = 1;
      idx = 0;
      while (1)
        {
          idx = mcpuA.find(" ",idx);
          if (idx == std::string::npos)
            break;
          count++;
          idx = mcpuA.find_first_not_of(" ",idx+1);
        }
      count /= 2;

      userT["job_id"]      = safe_get(envT,  "LSB_JOBID",        "unknown");
      userT["queue"]       = safe_get(envT,  "LSB_QUEUE",        "unknown");
      userT["submit_host"] = safe_get(envT,  "LSB_EXEC_CLUSTER", "unknown");
      userT["account"]     = "unknown";
      userDT["num_nodes"]  = (double) count;
    }
  else
    {
      userT["job_id"]      = "unknown";
      userT["queue"]       = "unknown";
      userT["submit_host"] = "unknown";
      userT["account"]     = "unknown";
      userDT["num_nodes"]  = 1.0;
    }
}
<commit_msg>Support Torque job arrays where ID would be form of 123[1]<commit_after>#include "run_submission.h"
#include <stdio.h>
#include <string.h>

const char * safe_get(Table& t, const char* key, const char* defaultValue)
{
  Table::const_iterator got = t.find(key);
  if (got == t.end())
    return defaultValue;
  return got->second.c_str();
}

void translate(Table& envT, Table& userT, DTable& userDT)
{
  enum QueueType { UNKNOWN = -1, SLURM = 1, SGE, SLURM_TACC, PBS, LSF };
  QueueType queueType = UNKNOWN;

  // Pick type of queuing system.

  if (envT.count("SGE_ACCOUNT"))
    queueType = SGE;
  else if (envT.count("SLURM_TACC_ACCOUNT") || envT.count("SLURM_TACC_JOBNAME"))
    queueType = SLURM_TACC;
  else if (envT.count("SBATCH_ACCOUNT"))
    queueType = SLURM;
  else if (envT.count("PBS_JOBID"))
    queueType = PBS;
  else if (envT.count("LSF_VERSION"))
    queueType = LSF;

  // userDT["num_tasks"] has a safe default value of 1 if not overridden by the run.
  userDT["num_cores"]  = userDT["num_tasks"];

  // Now fill in num_cores, num_nodes, account, job_id, queue, submit_host in userT from the environment
  if (queueType == SGE)
    {
      userT["account"]     = safe_get(envT,        "SGE_ACCOUNT", "unknown");
      userT["job_id"]      = safe_get(envT,        "JOB_ID",      "unknown");
      userT["queue"]       = safe_get(envT,        "QUEUE",       "unknown");
      userT["submit_host"] = "unknown";
      userDT["num_nodes"]  = strtod(safe_get(envT, "NHOSTS",      "1"),        (char **) NULL);
    }
  else if (queueType == SLURM_TACC || queueType == SLURM )
    {
      userT["job_id"]      = safe_get(envT,        "SLURM_JOB_ID",        "unknown");
      userT["queue"]       = safe_get(envT,        "SLURM_QUEUE",         "unknown");
      userT["submit_host"] = safe_get(envT,        "SLURM_SUBMIT_HOST",   "unknown");
      userT["account"]     = safe_get(envT,        "SLURM_TACC_ACCOUNT",  "unknown");
      userDT["num_nodes"]  = strtod(safe_get(envT, "SLURM_NNODES",        "1"),       (char **) NULL);
    }
  else if (queueType == PBS)
    {
      std::string job_id   = safe_get(envT,        "PBS_JOBID",     "unknown");
      std::size_t idx      = job_id.find_first_not_of("0123456789[]");
      userT["job_id"]      = job_id.substr(0,idx);
      userT["queue"]       = safe_get(envT,        "PBS_QUEUE",     "unknown");
      userT["submit_host"] = safe_get(envT,        "PBS_O_HOST",    "unknown");
      userT["account"]     = safe_get(envT,        "PBS_ACCOUNT",   "unknown");
      userDT["num_nodes"]  = strtod(safe_get(envT, "PBS_NUM_NODES", "1"),       (char **) NULL);;
    }
  else if (queueType == LSF)
    {
      // We must count the number of "words" in mcpuA.
      // We find the number of words by counting space blocks and add 1;
      // then divide by 2. then convert to a string.
      std::string mcpuA    = safe_get(envT,  "LSB_MCPU_HOSTS",  "a 1");
      std::string::size_type idx;
      int count = 1;
      idx = 0;
      while (1)
        {
          idx = mcpuA.find(" ",idx);
          if (idx == std::string::npos)
            break;
          count++;
          idx = mcpuA.find_first_not_of(" ",idx+1);
        }
      count /= 2;

      userT["job_id"]      = safe_get(envT,  "LSB_JOBID",        "unknown");
      userT["queue"]       = safe_get(envT,  "LSB_QUEUE",        "unknown");
      userT["submit_host"] = safe_get(envT,  "LSB_EXEC_CLUSTER", "unknown");
      userT["account"]     = "unknown";
      userDT["num_nodes"]  = (double) count;
    }
  else
    {
      userT["job_id"]      = "unknown";
      userT["queue"]       = "unknown";
      userT["submit_host"] = "unknown";
      userT["account"]     = "unknown";
      userDT["num_nodes"]  = 1.0;
    }
}
<|endoftext|>


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

#include <gtest/gtest.h>

#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/integral_image_normal.h>

#include <iostream>

using namespace pcl;
using namespace std;

typedef search::KdTree<PointXYZ>::Ptr KdTreePtr;
PointCloud<PointXYZ> cloud;
KdTreePtr tree;

NormalEstimation<PointXYZ, Normal> n;
IntegralImageNormalEstimation<PointXYZ, Normal> ne;

TEST(PCL, IntegralImage)
{
  const unsigned width = 640;
  const unsigned height = 480;
  const unsigned max_window_size = 11;
  IntegralImage2Dim<float,1> integral_image(true);

  // test for dense data with elementstride = 1
  float* data = new float[width * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[width * yIdx + xIdx] = 1;
    }
  }
  integral_image.setInput (data, width, height, 1, width);

  for (unsigned window_width = 2; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 2; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  //now test with element-stride 2
  unsigned element_stride = 2;
  unsigned row_stride = width * element_stride;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < row_stride; xIdx += element_stride)
    {
      data[row_stride * yIdx + xIdx] = 1;
      data[row_stride * yIdx + xIdx + 1] = -1;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  //now test with odd element-stride 3 and modulo-uneven row_stride
  element_stride = 3;
  row_stride = width * element_stride + 1; // +1 to enforce a non-zero modulo
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[row_stride * yIdx + element_stride * xIdx] = 1;
      data[row_stride * yIdx + element_stride * xIdx + 1] = 2;
      data[row_stride * yIdx + element_stride * xIdx + 2] = xIdx;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
          EXPECT_EQ (window_width * window_height, integral_image.getSecondOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  // now test multidimensional case with 3D but element_stride = 4 and row_stride non-dividable by element_stride
  IntegralImage2Dim<float, 3> integral_image3(true);
  element_stride = 4;
  row_stride = width * element_stride + 1;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[row_stride * yIdx + xIdx * element_stride] = xIdx;
      data[row_stride * yIdx + xIdx * element_stride + 1] = yIdx;
      data[row_stride * yIdx + xIdx * element_stride + 2] = xIdx + yIdx;
      data[row_stride * yIdx + xIdx * element_stride + 3] = -1000;
    }
  }
  integral_image3.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          IntegralImage2Dim<float, 3>::ElementType sum = integral_image3.getFirstOrderSum (xIdx, yIdx, window_width, window_height);

          EXPECT_EQ (window_height * window_width * (window_width + 2 * xIdx - 1), sum[0] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1), sum[1] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1) + window_height * window_width * (window_width + 2 * xIdx - 1), sum[2] * 2);

          IntegralImage2Dim<float, 3>::SecondOrderType sumSqr = integral_image3.getSecondOrderSum (xIdx, yIdx, window_width, window_height);

          IntegralImage2Dim<float, 3>::SecondOrderType ground_truth;
          ground_truth.setZero ();
          for (unsigned wy = yIdx; wy < yIdx + window_height; ++wy)
          {
            for (unsigned wx = xIdx; wx < xIdx + window_width; ++wx)
            {
              float* val = data + (wy * row_stride + wx * element_stride);
              //ground_truth[0] += val[0] * val[0];
              ground_truth[1] += val[0] * val[1];
              ground_truth[2] += val[0] * val[2];
              //ground_truth[3] += val[1] * val[1];
              ground_truth[4] += val[1] * val[2];
              ground_truth[5] += val[2] * val[2];
            }
          }

          //EXPECT_EQ (ground_truth [0], sumSqr[0]);
          EXPECT_EQ (ground_truth [1], sumSqr[1]);
          EXPECT_EQ (ground_truth [2], sumSqr[2]);
          //EXPECT_EQ (ground_truth [3], sumSqr[3]);
          EXPECT_EQ (ground_truth [4], sumSqr[4]);
          EXPECT_EQ (ground_truth [5], sumSqr[5]);

          int w = window_width + xIdx - 1;
          long result = w * (w + 1) * (2*w + 1) - xIdx * (xIdx - 1) * (2*xIdx - 1);

          EXPECT_EQ (window_height * result, sumSqr[0] * 6);

          int h = window_height + yIdx - 1;
          result = h * (h + 1) * (2*h + 1) - yIdx * (yIdx - 1) * (2*yIdx - 1);
          EXPECT_EQ (window_width * result, sumSqr[3] * 6);
        }
      }
    }
  }
  delete[] data;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, NormalEstimation)
{
  tree.reset (new search::KdTree<PointXYZ> (false));
  n.setSearchMethod (tree);
  n.setKSearch (10);

  n.setInputCloud (cloud.makeShared ());

  PointCloud<Normal> output;
  n.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t i = 0; i < cloud.points.size (); ++i)
  {
    EXPECT_NEAR (fabs (output.points[i].normal_x),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_y),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_z), 1.0, 1e-2);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, IINormalEstimation)
{
  Normal normal;
  ne.setInputCloud (cloud.makeShared ());
  ne.setRectSize (2, 2);
  ne.computePointNormal (160, 120, normal);
  ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);

  EXPECT_NEAR (fabs (normal.normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_z), 1.0, 1e-2);

  PointCloud<Normal> output;
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
  EXPECT_NEAR (fabs (output (160, 120).normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_z), 1.0, 1e-2);

  ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
}

/* ---[ */
int
main (int argc, char** argv)
{
  cloud.points.resize (320 * 240);
  cloud.width = 320;
  cloud.height = 240;
  cloud.is_dense = true;
  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      cloud (u, v).x = u;
      cloud (u, v).y = v;
      cloud (u, v).z = 10;
    }
  }

  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());

  return 1;
}
/* ]--- */

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

#include <gtest/gtest.h>

#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/integral_image_normal.h>

#include <iostream>

using namespace pcl;
using namespace std;

typedef search::KdTree<PointXYZ>::Ptr KdTreePtr;
PointCloud<PointXYZ> cloud;
KdTreePtr tree;

NormalEstimation<PointXYZ, Normal> n;
IntegralImageNormalEstimation<PointXYZ, Normal> ne;

TEST(PCL, IntegralImage)
{
  const unsigned width = 640;
  const unsigned height = 480;
  const unsigned max_window_size = 11;
  IntegralImage2D<float,1> integral_image(true);

  // test for dense data with elementstride = 1
  float* data = new float[width * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[width * yIdx + xIdx] = 1;
    }
  }
  integral_image.setInput (data, width, height, 1, width);

  for (unsigned window_width = 2; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 2; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height));
        }
      }
    }
  }
  delete[] data;

  //now test with element-stride 2
  unsigned element_stride = 2;
  unsigned row_stride = width * element_stride;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < row_stride; xIdx += element_stride)
    {
      data[row_stride * yIdx + xIdx] = 1;
      data[row_stride * yIdx + xIdx + 1] = -1;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height));
        }
      }
    }
  }
  delete[] data;

  //now test with odd element-stride 3 and modulo-uneven row_stride
  element_stride = 3;
  row_stride = width * element_stride + 1; // +1 to enforce a non-zero modulo
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[row_stride * yIdx + element_stride * xIdx] = 1;
      data[row_stride * yIdx + element_stride * xIdx + 1] = 2;
      data[row_stride * yIdx + element_stride * xIdx + 2] = xIdx;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height));
          EXPECT_EQ (window_width * window_height, integral_image.getSecondOrderSum (xIdx, yIdx, window_width, window_height));
        }
      }
    }
  }
  delete[] data;

  // now test multidimensional case with 3D but element_stride = 4 and row_stride non-dividable by element_stride
  IntegralImage2D<float, 3> integral_image3(true);
  element_stride = 4;
  row_stride = width * element_stride + 1;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[row_stride * yIdx + xIdx * element_stride] = xIdx;
      data[row_stride * yIdx + xIdx * element_stride + 1] = yIdx;
      data[row_stride * yIdx + xIdx * element_stride + 2] = xIdx + yIdx;
      data[row_stride * yIdx + xIdx * element_stride + 3] = -1000;
    }
  }
  integral_image3.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          IntegralImage2D<float, 3>::ElementType sum = integral_image3.getFirstOrderSum (xIdx, yIdx, window_width, window_height);

          EXPECT_EQ (window_height * window_width * (window_width + 2 * xIdx - 1), sum[0] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1), sum[1] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1) + window_height * window_width * (window_width + 2 * xIdx - 1), sum[2] * 2);

          IntegralImage2D<float, 3>::SecondOrderType sumSqr = integral_image3.getSecondOrderSum (xIdx, yIdx, window_width, window_height);

          IntegralImage2D<float, 3>::SecondOrderType ground_truth;
          ground_truth.setZero ();
          for (unsigned wy = yIdx; wy < yIdx + window_height; ++wy)
          {
            for (unsigned wx = xIdx; wx < xIdx + window_width; ++wx)
            {
              float* val = data + (wy * row_stride + wx * element_stride);
              //ground_truth[0] += val[0] * val[0];
              ground_truth[1] += val[0] * val[1];
              ground_truth[2] += val[0] * val[2];
              //ground_truth[3] += val[1] * val[1];
              ground_truth[4] += val[1] * val[2];
              ground_truth[5] += val[2] * val[2];
            }
          }

          //EXPECT_EQ (ground_truth [0], sumSqr[0]);
          EXPECT_EQ (ground_truth [1], sumSqr[1]);
          EXPECT_EQ (ground_truth [2], sumSqr[2]);
          //EXPECT_EQ (ground_truth [3], sumSqr[3]);
          EXPECT_EQ (ground_truth [4], sumSqr[4]);
          EXPECT_EQ (ground_truth [5], sumSqr[5]);

          int w = window_width + xIdx - 1;
          long result = w * (w + 1) * (2*w + 1) - xIdx * (xIdx - 1) * (2*xIdx - 1);

          EXPECT_EQ (window_height * result, sumSqr[0] * 6);

          int h = window_height + yIdx - 1;
          result = h * (h + 1) * (2*h + 1) - yIdx * (yIdx - 1) * (2*yIdx - 1);
          EXPECT_EQ (window_width * result, sumSqr[3] * 6);
        }
      }
    }
  }
  delete[] data;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, NormalEstimation)
{
  tree.reset (new search::KdTree<PointXYZ> (false));
  n.setSearchMethod (tree);
  n.setKSearch (10);

  n.setInputCloud (cloud.makeShared ());

  PointCloud<Normal> output;
  n.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t i = 0; i < cloud.points.size (); ++i)
  {
    EXPECT_NEAR (fabs (output.points[i].normal_x),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_y),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_z), 1.0, 1e-2);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, IINormalEstimation)
{
  Normal normal;
  ne.setInputCloud (cloud.makeShared ());
  ne.setRectSize (2, 2);
  ne.computePointNormal (160, 120, normal);
  ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);

  EXPECT_NEAR (fabs (normal.normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_z), 1.0, 1e-2);

  PointCloud<Normal> output;
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
  EXPECT_NEAR (fabs (output (160, 120).normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_z), 1.0, 1e-2);

  ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
}

/* ---[ */
int
main (int argc, char** argv)
{
  cloud.points.resize (320 * 240);
  cloud.width = 320;
  cloud.height = 240;
  cloud.is_dense = true;
  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      cloud (u, v).x = u;
      cloud (u, v).y = v;
      cloud (u, v).z = 10;
    }
  }

  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());

  return 1;
}
/* ]--- */

<|endoftext|>


<commit_before>/*
 * Copyright 2016 Gigatribe
 *
 * 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 "CurlProgress.h"
#include "../../rest/HttpErrors.h"

#include <curl_easy.h>
#include <mutex>
#include <curl_exception.h>
#include <chrono>
#include <thread>

using namespace std::chrono;

namespace giga
{
namespace details
{

CurlProgress::CurlProgress (pplx::cancellation_token token) :
        _mut{}, _item{0ul, 0ul, 0ul, 0ul}, _cancelToken{token}, _pause{false}, _isPaused{false}, _curl{nullptr},
        _limitRate{0ul}, _currentLimitRate{0ul}, _rateTime{}, _rateBytes{0ul}, _bucket{0ul}, _upPostion{0ul}
{
}

CurlProgress::CurlProgress (const CurlProgress& other) :
        _mut{},
        _item{other._item.dltotal, other._item.dlnow, other._item.ultotal, other._item.ulnow},
        _cancelToken{other._cancelToken},
        _pause{other._pause},
        _isPaused{other._isPaused},
        _curl{other._curl},
        _limitRate{other._limitRate},
        _currentLimitRate{other._currentLimitRate},
        _rateTime{other._rateTime},
        _rateBytes{other._rateBytes},
        _bucket{other._bucket},
        _upPostion{other._upPostion}
{
}

CurlProgress::Item
CurlProgress::data () const
{
    std::lock_guard<std::mutex> l(_mut);
    return _item;
}

void
CurlProgress::setPause (bool pause)
{
    std::lock_guard<std::mutex> l(_mut);
    _pause = pause;
}

void
CurlProgress::setUploadPosition (uint64_t pos)
{
    std::lock_guard<std::mutex> l(_mut);
    _upPostion = pos;
}

void
CurlProgress::setLimitRate (uint64_t rate)
{
    std::lock_guard<std::mutex> l(_mut);
    _limitRate = rate;
}

void
CurlProgress::setCurl (curl::curl_easy& curl)
{
    std::lock_guard<std::mutex> l(_mut);
    _curl = &curl;
}

bool
CurlProgress::isPaused () const
{
    std::lock_guard<std::mutex> l(_mut);
    return _pause;
}

int
CurlProgress::onCallback (curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) noexcept
{
    try {
        uint64_t limitRate = 0;
        {
            std::lock_guard<std::mutex> l(_mut);
            limitRate = _limitRate;

            _item.dltotal = static_cast<uint64_t>(dltotal);
            _item.dlnow   = static_cast<uint64_t>(dlnow);
            _item.ultotal = static_cast<uint64_t>(ultotal + _upPostion);
            _item.ulnow   = static_cast<uint64_t>(ulnow + _upPostion);

            if (_pause != _isPaused && _curl != nullptr)
            {
                _curl->pause(_pause ? CURLPAUSE_ALL : CURLPAUSE_CONT);
                _isPaused = _pause;
            }
            if (_cancelToken.is_canceled())
            {
                return CURLE_ABORTED_BY_CALLBACK;
            }
        }

        // Do the limit rate outside of the mutex locked zone
        // because there is waiting here.
        auto transfered = static_cast<uint64_t>(dlnow + ulnow);
        if (limitRate != _currentLimitRate || transfered == 0ul)
        {
            _rateBytes = transfered;
            _currentLimitRate = limitRate;
            _rateTime = high_resolution_clock::now();
            _bucket = _limitRate; // give it 1 sec
        }
        if (limitRate > 0 && transfered > 0)
        {
            auto now = high_resolution_clock::now();
            do
            {
                // calculate duration
                duration<float> duration = now - _rateTime;
                auto elapsedMs = duration_cast<milliseconds>(duration).count();
                _rateTime = now;

                // add bytes in the bucket
                _bucket += std::max(static_cast<uint64_t>((elapsedMs * _limitRate) / 1000), static_cast<uint64_t>(1ul));

                // take bytes in the bucket
                auto take = std::min(_bucket, transfered - _rateBytes);
                _bucket    -= take;
                _rateBytes += take;

                // wait for new bytes.
                if (_bucket == 0)
                {
                    std::this_thread::sleep_for(milliseconds(500));
                    now = high_resolution_clock::now();
                }
            } while (_bucket == 0 && (dlnow - _rateBytes) > 0);
        }
    } catch (...) {
        return CURLE_OBSOLETE40;
    }
    return CURLE_OK;
}

} /* namespace details */
} /* namespace giga */
<commit_msg>fix the limitRate feature<commit_after>/*
 * Copyright 2016 Gigatribe
 *
 * 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 "CurlProgress.h"
#include "../../rest/HttpErrors.h"

#include <curl_easy.h>
#include <mutex>
#include <curl_exception.h>
#include <chrono>
#include <thread>

using namespace std::chrono;

namespace giga
{
namespace details
{

CurlProgress::CurlProgress (pplx::cancellation_token token) :
        _mut{}, _item{0ul, 0ul, 0ul, 0ul}, _cancelToken{token}, _pause{false}, _isPaused{false}, _curl{nullptr},
        _limitRate{0ul}, _currentLimitRate{0ul}, _rateTime{}, _rateBytes{0ul}, _bucket{0ul}, _upPostion{0ul}
{
}

CurlProgress::CurlProgress (const CurlProgress& other) :
        _mut{},
        _item{other._item.dltotal, other._item.dlnow, other._item.ultotal, other._item.ulnow},
        _cancelToken{other._cancelToken},
        _pause{other._pause},
        _isPaused{other._isPaused},
        _curl{other._curl},
        _limitRate{other._limitRate},
        _currentLimitRate{other._currentLimitRate},
        _rateTime{other._rateTime},
        _rateBytes{other._rateBytes},
        _bucket{other._bucket},
        _upPostion{other._upPostion}
{
}

CurlProgress::Item
CurlProgress::data () const
{
    std::lock_guard<std::mutex> l(_mut);
    return _item;
}

void
CurlProgress::setPause (bool pause)
{
    std::lock_guard<std::mutex> l(_mut);
    _pause = pause;
}

void
CurlProgress::setUploadPosition (uint64_t pos)
{
    std::lock_guard<std::mutex> l(_mut);
    _upPostion = pos;
}

void
CurlProgress::setLimitRate (uint64_t rate)
{
    std::lock_guard<std::mutex> l(_mut);
    _limitRate = rate;
}

void
CurlProgress::setCurl (curl::curl_easy& curl)
{
    std::lock_guard<std::mutex> l(_mut);
    _curl = &curl;
}

bool
CurlProgress::isPaused () const
{
    std::lock_guard<std::mutex> l(_mut);
    return _pause;
}

int
CurlProgress::onCallback (curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) noexcept
{
    try {
        uint64_t limitRate = 0;
        {
            std::lock_guard<std::mutex> l(_mut);
            limitRate = _limitRate;

            _item.dltotal = static_cast<uint64_t>(dltotal);
            _item.dlnow   = static_cast<uint64_t>(dlnow);
            _item.ultotal = static_cast<uint64_t>(ultotal + _upPostion);
            _item.ulnow   = static_cast<uint64_t>(ulnow + _upPostion);

            if (_pause != _isPaused && _curl != nullptr)
            {
                _curl->pause(_pause ? CURLPAUSE_ALL : CURLPAUSE_CONT);
                _isPaused = _pause;
            }
            if (_cancelToken.is_canceled())
            {
                return CURLE_ABORTED_BY_CALLBACK;
            }
        }

        // Do the limit rate outside of the mutex locked zone
        // because there is waiting here.
        auto transfered = static_cast<uint64_t>(dlnow + ulnow);
        if (limitRate != _currentLimitRate || transfered == 0ul)
        {
            _rateBytes = transfered;
            _currentLimitRate = limitRate;
            _rateTime = high_resolution_clock::now();
            _bucket = _limitRate; // give it 1 sec
        }
        if (limitRate > 0 && transfered > 0)
        {
            auto now = high_resolution_clock::now();
            do
            {
                // calculate duration
                duration<float> duration = now - _rateTime;
                auto elapsedMs = duration_cast<milliseconds>(duration).count();
                _rateTime = now;

                // add bytes in the bucket
                _bucket += std::max(static_cast<uint64_t>((elapsedMs * limitRate) / 1000), static_cast<uint64_t>(1ul));

                // take bytes in the bucket
                auto take = std::min(_bucket, transfered - _rateBytes);
                _bucket    -= take;
                _rateBytes += take;

                // wait for new bytes.
                if (_bucket == 0)
                {
                    std::this_thread::sleep_for(milliseconds(500));
                    now = high_resolution_clock::now();
                }
            } while (_bucket == 0 && (dlnow - _rateBytes) > 0);
        }
    } catch (...) {
        return CURLE_OBSOLETE40;
    }
    return CURLE_OK;
}

} /* namespace details */
} /* namespace giga */
<|endoftext|>


<commit_before><commit_msg>Add a TODO comment to describe when we can remove the const_cast for the NSS function SGN_Update.<commit_after><|endoftext|>


<commit_before><commit_msg>WaE: type name first seen using 'class' now seen using 'struct'<commit_after><|endoftext|>


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

#include <GL/freeglut.h>

#include "WindowImp.h"
#include "Test.util.h"
#include "http/HTTPConnection.h"

using namespace org::w3c::dom::bootstrap;
using namespace org::w3c::dom;

extern html::Window window;

void reshape(int w, int h)
{
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, w, h, 0, -1000.0, 1.0);

    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->render();
    glutSwapBuffers();  // This would block until the sync happens
}

unsigned getCharKeyCode(int key)
{
    // US Qwerty
    static unsigned map[] = {
        0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 12, 13, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 27, 0, 0, 0, 0,
        32, 49 /* ! */, 222 /* " */, 51 /* # */, 52 /* $ */, 53 /* % */, 55 /* & */, 222 /* ' */,
        57 /* ( */, 48 /* ) */, 56 /* * */, 187 /* + */, 188 /* , */, 189 /* - */, 190 /* . */, 191 /* / */,
        48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */, 52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
        56 /* 8 */, 57 /* 9 */, 186 /* : */, 186 /* ; */, 188 /* < */, 187 /* = */, 190 /* > */, 191 /* ? */,
        50 /* @ */, 65 /* A */, 66 /* B */, 67 /* C */, 68 /* D */, 69 /* E */, 70 /* F */, 71 /* G */,
        72 /* H */, 73 /* I */, 74 /* J */, 75 /* K */, 76 /* L */, 77 /* M */, 78 /* N */, 79 /* O */,
        80 /* P */, 81 /* Q */, 82 /* R */, 83 /* S */, 84 /* T */, 85 /* U */, 86 /* V */, 87 /* W */,
        88 /* X */, 89 /* Y */, 90 /* Z */, 219 /* [ */, 220 /* \ */, 221 /* ] */, 54 /* ^ */, 189 /* _ */,
        192 /* ` */, 65 /* a */, 66 /* b */, 67 /* c */, 68 /* d */, 69 /* e */, 70 /* f */, 71 /* g */,
        72 /* h */, 73 /* i */, 74 /* j */, 75 /* k */, 76 /* l */, 77 /* m */, 78 /* n */, 79 /* o */,
        80 /* p */, 81 /* q */, 82 /* r */, 83 /* s */, 84 /* t */, 85 /* u */, 86 /* v */, 87 /* w */,
        88 /* x */, 89 /* y */, 90 /* z */, 219 /* { */, 220 /* | */, 221 /* } */, 192 /* ~ */, 46 /* DEL */
    };
    static_assert(sizeof map /sizeof map[0] == 128, "invalid map");
    return (0 <= key && key <= 127) ? map[key] : 0;
}

void keyboard(unsigned char key, int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->keydown(key, getCharKeyCode(key), glutGetModifiers());
}

void keyboardUp(unsigned char key, int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->keyup(key, getCharKeyCode(key), glutGetModifiers());
}

unsigned getSpecialKeyCode(int key)
{
    switch (key) {
    case GLUT_KEY_F1:
        return 112;
    case GLUT_KEY_F2:
        return 113;
    case GLUT_KEY_F3:
        return 114;
    case GLUT_KEY_F4:
        return 115;
    case GLUT_KEY_F5:
        return 116;
    case GLUT_KEY_F6:
        return 117;
    case GLUT_KEY_F7:
        return 118;
    case GLUT_KEY_F8:
        return 119;
    case GLUT_KEY_F9:
        return 120;
    case GLUT_KEY_F10:
        return 121;
    case GLUT_KEY_F11:
        return 122;
    case GLUT_KEY_F12:
        return 123;
    case GLUT_KEY_LEFT:
        return 37;
    case GLUT_KEY_UP:
        return 38;
    case GLUT_KEY_RIGHT:
        return 39;
    case GLUT_KEY_DOWN:
        return 40;
    case GLUT_KEY_PAGE_UP:
        return 33;
    case GLUT_KEY_PAGE_DOWN:
        return 34;
    case GLUT_KEY_HOME:
        return 36;
    case GLUT_KEY_END:
        return 35;
    case GLUT_KEY_INSERT:
        return 45;
    case 109:  // Num Lock
        return 144;
    default:
        return 0;
    }
}

void special(int key, int x, int y)
{
    unsigned keycode = getSpecialKeyCode(key);
    if (keycode) {
        if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
            imp->keydown(0, keycode, glutGetModifiers());
    }
}

void specialUp(int key, int x, int y)
{
    unsigned keycode = getSpecialKeyCode(key);
    if (keycode) {
        if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
            imp->keyup(0, keycode, glutGetModifiers());
    }
}

void mouse(int button, int state, int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->mouse(button, state, x, y, glutGetModifiers());
}

void mouseMove(int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->mouseMove(x, y, glutGetModifiers());
}

void timer(int value)
{
    HttpConnectionManager::getIOService().poll();
    if (WindowImp* imp = static_cast<WindowImp*>(window.self())) {
        if (imp->poll())
            glutPostRedisplay();
    }
    glutTimerFunc(50, timer, 0);
    // TODO: do GC here or maybe in the idle proc
}

void init(int* argc, char* argv[])
{
    glutInit(argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(816, 1056);
    glutCreateWindow(argv[0]);
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glEnable(GL_TEXTURE_2D);
    glDepthFunc(GL_LEQUAL);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_ALPHA_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glutKeyboardFunc(keyboard);
    glutKeyboardUpFunc(keyboardUp);
    glutSpecialFunc(special);
    glutSpecialUpFunc(specialUp);
    glutMouseFunc(mouse);
    glutMotionFunc(mouseMove);
    glutPassiveMotionFunc(mouseMove);
    glutTimerFunc(50, timer, 0);
    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
}
<commit_msg>(keyboard, keyboardUp) : Fix bugs.<commit_after>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <GL/freeglut.h>

#include "WindowImp.h"
#include "Test.util.h"
#include "http/HTTPConnection.h"

using namespace org::w3c::dom::bootstrap;
using namespace org::w3c::dom;

extern html::Window window;

void reshape(int w, int h)
{
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, w, h, 0, -1000.0, 1.0);

    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->render();
    glutSwapBuffers();  // This would block until the sync happens
}

unsigned getCharKeyCode(int key)
{
    // US Qwerty
    static unsigned map[] = {
        0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 12, 13, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 27, 0, 0, 0, 0,
        32, 49 /* ! */, 222 /* " */, 51 /* # */, 52 /* $ */, 53 /* % */, 55 /* & */, 222 /* ' */,
        57 /* ( */, 48 /* ) */, 56 /* * */, 187 /* + */, 188 /* , */, 189 /* - */, 190 /* . */, 191 /* / */,
        48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */, 52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
        56 /* 8 */, 57 /* 9 */, 186 /* : */, 186 /* ; */, 188 /* < */, 187 /* = */, 190 /* > */, 191 /* ? */,
        50 /* @ */, 65 /* A */, 66 /* B */, 67 /* C */, 68 /* D */, 69 /* E */, 70 /* F */, 71 /* G */,
        72 /* H */, 73 /* I */, 74 /* J */, 75 /* K */, 76 /* L */, 77 /* M */, 78 /* N */, 79 /* O */,
        80 /* P */, 81 /* Q */, 82 /* R */, 83 /* S */, 84 /* T */, 85 /* U */, 86 /* V */, 87 /* W */,
        88 /* X */, 89 /* Y */, 90 /* Z */, 219 /* [ */, 220 /* \ */, 221 /* ] */, 54 /* ^ */, 189 /* _ */,
        192 /* ` */, 65 /* a */, 66 /* b */, 67 /* c */, 68 /* d */, 69 /* e */, 70 /* f */, 71 /* g */,
        72 /* h */, 73 /* i */, 74 /* j */, 75 /* k */, 76 /* l */, 77 /* m */, 78 /* n */, 79 /* o */,
        80 /* p */, 81 /* q */, 82 /* r */, 83 /* s */, 84 /* t */, 85 /* u */, 86 /* v */, 87 /* w */,
        88 /* x */, 89 /* y */, 90 /* z */, 219 /* { */, 220 /* | */, 221 /* } */, 192 /* ~ */, 46 /* DEL */
    };
    static_assert(sizeof map /sizeof map[0] == 128, "invalid map");
    return (0 <= key && key <= 127) ? map[key] : 0;
}

void keyboard(unsigned char key, int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->keydown(isprint(key) ? key : 0, getCharKeyCode(key), glutGetModifiers());
}

void keyboardUp(unsigned char key, int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->keyup(isprint(key) ? key : 0, getCharKeyCode(key), glutGetModifiers());
}

unsigned getSpecialKeyCode(int key)
{
    switch (key) {
    case GLUT_KEY_F1:
        return 112;
    case GLUT_KEY_F2:
        return 113;
    case GLUT_KEY_F3:
        return 114;
    case GLUT_KEY_F4:
        return 115;
    case GLUT_KEY_F5:
        return 116;
    case GLUT_KEY_F6:
        return 117;
    case GLUT_KEY_F7:
        return 118;
    case GLUT_KEY_F8:
        return 119;
    case GLUT_KEY_F9:
        return 120;
    case GLUT_KEY_F10:
        return 121;
    case GLUT_KEY_F11:
        return 122;
    case GLUT_KEY_F12:
        return 123;
    case GLUT_KEY_LEFT:
        return 37;
    case GLUT_KEY_UP:
        return 38;
    case GLUT_KEY_RIGHT:
        return 39;
    case GLUT_KEY_DOWN:
        return 40;
    case GLUT_KEY_PAGE_UP:
        return 33;
    case GLUT_KEY_PAGE_DOWN:
        return 34;
    case GLUT_KEY_HOME:
        return 36;
    case GLUT_KEY_END:
        return 35;
    case GLUT_KEY_INSERT:
        return 45;
    case 109:  // Num Lock
        return 144;
    default:
        return 0;
    }
}

void special(int key, int x, int y)
{
    unsigned keycode = getSpecialKeyCode(key);
    if (keycode) {
        if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
            imp->keydown(0, keycode, glutGetModifiers());
    }
}

void specialUp(int key, int x, int y)
{
    unsigned keycode = getSpecialKeyCode(key);
    if (keycode) {
        if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
            imp->keyup(0, keycode, glutGetModifiers());
    }
}

void mouse(int button, int state, int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->mouse(button, state, x, y, glutGetModifiers());
}

void mouseMove(int x, int y)
{
    if (WindowImp* imp = static_cast<WindowImp*>(window.self()))
        imp->mouseMove(x, y, glutGetModifiers());
}

void timer(int value)
{
    HttpConnectionManager::getIOService().poll();
    if (WindowImp* imp = static_cast<WindowImp*>(window.self())) {
        if (imp->poll())
            glutPostRedisplay();
    }
    glutTimerFunc(50, timer, 0);
    // TODO: do GC here or maybe in the idle proc
}

void init(int* argc, char* argv[])
{
    glutInit(argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(816, 1056);
    glutCreateWindow(argv[0]);
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glEnable(GL_TEXTURE_2D);
    glDepthFunc(GL_LEQUAL);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_ALPHA_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glutKeyboardFunc(keyboard);
    glutKeyboardUpFunc(keyboardUp);
    glutSpecialFunc(special);
    glutSpecialUpFunc(specialUp);
    glutMouseFunc(mouse);
    glutMotionFunc(mouseMove);
    glutPassiveMotionFunc(mouseMove);
    glutTimerFunc(50, timer, 0);
    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
}
<|endoftext|>