<commit_before>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011, 2012                                                   *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation, either version 3 of the License                  *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa is distributed in the hope that it will be useful,                 *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       *
 * See the GNU Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_CONFIG_HPP
#define CPPA_CONFIG_HPP

// uncomment this line or use
// ./configure CXXFLAGS="-DCPPA_DISABLE_CONTEXT_SWITCHING"
// if ucontext_t is not available on your platform
//#define CPPA_DISABLE_CONTEXT_SWITCHING

#if defined(__GNUC__)
#  define CPPA_GCC
#endif

#if defined(__APPLE__)
#  define CPPA_MACOS
#  ifndef _GLIBCXX_HAS_GTHREADS
#    define _GLIBCXX_HAS_GTHREADS
#  endif
#elif defined(__GNUC__) && defined(__linux__)
#  define CPPA_LINUX
#elif defined(WIN32)
#  define CPPA_WINDOWS
#else
#  error Plattform and/or compiler not supportet
#endif

#if defined(__amd64__) || defined(__LP64__)
#  define CPPA_64BIT
#endif

#include <cstdio>
#include <cstdlib>

#ifdef CPPA_DEBUG
#include <execinfo.h>

#define CPPA_REQUIRE__(stmt, file, line)                                       \
    printf("%s:%u: requirement failed '%s'\n", file, line, stmt);              \
    {                                                                          \
        void *array[10];                                                       \
        size_t size = backtrace(array, 10);                                    \
        backtrace_symbols_fd(array, size, 2);                                  \
    }                                                                          \
    abort()
#define CPPA_REQUIRE(stmt)                                                     \
    if ((stmt) == false) {                                                     \
        CPPA_REQUIRE__(#stmt, __FILE__, __LINE__);                             \
    }((void) 0)
#else // CPPA_DEBUG
#define CPPA_REQUIRE(unused) ((void) 0)
#endif // CPPA_DEBUG

#define CPPA_CRITICAL__(error, file, line) {                                   \
        printf("%s:%u: critical error: '%s'\n", file, line, error);            \
        exit(7);                                                               \
    } ((void) 0)

#define CPPA_CRITICAL(error) CPPA_CRITICAL__(error, __FILE__, __LINE__)

#endif // CPPA_CONFIG_HPP
<commit_msg>removed obsolete macro<commit_after>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011, 2012                                                   *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation, either version 3 of the License                  *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa is distributed in the hope that it will be useful,                 *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       *
 * See the GNU Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_CONFIG_HPP
#define CPPA_CONFIG_HPP

// uncomment this line or use
// ./configure CXXFLAGS="-DCPPA_DISABLE_CONTEXT_SWITCHING"
// if ucontext_t is not available on your platform
//#define CPPA_DISABLE_CONTEXT_SWITCHING

#if defined(__GNUC__)
#  define CPPA_GCC
#endif

#if defined(__APPLE__)
#  define CPPA_MACOS
#  ifndef _GLIBCXX_HAS_GTHREADS
#    define _GLIBCXX_HAS_GTHREADS
#  endif
#elif defined(__GNUC__) && defined(__linux__)
#  define CPPA_LINUX
#elif defined(WIN32)
#  define CPPA_WINDOWS
#else
#  error Plattform and/or compiler not supportet
#endif

#include <cstdio>
#include <cstdlib>

#ifdef CPPA_DEBUG
#include <execinfo.h>

#define CPPA_REQUIRE__(stmt, file, line)                                       \
    printf("%s:%u: requirement failed '%s'\n", file, line, stmt);              \
    {                                                                          \
        void *array[10];                                                       \
        size_t size = backtrace(array, 10);                                    \
        backtrace_symbols_fd(array, size, 2);                                  \
    }                                                                          \
    abort()
#define CPPA_REQUIRE(stmt)                                                     \
    if ((stmt) == false) {                                                     \
        CPPA_REQUIRE__(#stmt, __FILE__, __LINE__);                             \
    }((void) 0)
#else // CPPA_DEBUG
#define CPPA_REQUIRE(unused) ((void) 0)
#endif // CPPA_DEBUG

#define CPPA_CRITICAL__(error, file, line) {                                   \
        printf("%s:%u: critical error: '%s'\n", file, line, error);            \
        exit(7);                                                               \
    } ((void) 0)

#define CPPA_CRITICAL(error) CPPA_CRITICAL__(error, __FILE__, __LINE__)

#endif // CPPA_CONFIG_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 */

#include <string>
#include <sstream>
#include <iostream>

#include "cpu/base_cpu.hh"
#include "base/cprintf.hh"
#include "cpu/exec_context.hh"
#include "base/misc.hh"
#include "sim/param.hh"
#include "sim/sim_events.hh"

using namespace std;

vector<BaseCPU *> BaseCPU::cpuList;

// This variable reflects the max number of threads in any CPU.  Be
// careful to only use it once all the CPUs that you care about have
// been initialized
int maxThreadsPerCPU = 1;

#ifdef FULL_SYSTEM
BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
                 Counter max_insts_any_thread,
                 Counter max_insts_all_threads,
                 Counter max_loads_any_thread,
                 Counter max_loads_all_threads,
                 System *_system, Tick freq)
    : SimObject(_name), frequency(freq),
      number_of_threads(_number_of_threads), system(_system)
#else
BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
                 Counter max_insts_any_thread,
                 Counter max_insts_all_threads,
                 Counter max_loads_any_thread,
                 Counter max_loads_all_threads)
    : SimObject(_name), number_of_threads(_number_of_threads)
#endif
{
    // add self to global list of CPUs
    cpuList.push_back(this);

    if (number_of_threads > maxThreadsPerCPU)
        maxThreadsPerCPU = number_of_threads;

    // allocate per-thread instruction-based event queues
    comInstEventQueue = new (EventQueue *)[number_of_threads];
    for (int i = 0; i < number_of_threads; ++i)
        comInstEventQueue[i] = new EventQueue("instruction-based event queue");

    //
    // set up instruction-count-based termination events, if any
    //
    if (max_insts_any_thread != 0)
        for (int i = 0; i < number_of_threads; ++i)
            new SimExitEvent(comInstEventQueue[i], max_insts_any_thread,
                "a thread reached the max instruction count");

    if (max_insts_all_threads != 0) {
        // allocate & initialize shared downcounter: each event will
        // decrement this when triggered; simulation will terminate
        // when counter reaches 0
        int *counter = new int;
        *counter = number_of_threads;
        for (int i = 0; i < number_of_threads; ++i)
            new CountedExitEvent(comInstEventQueue[i],
                "all threads reached the max instruction count",
                max_insts_all_threads, *counter);
    }

    // allocate per-thread load-based event queues
    comLoadEventQueue = new (EventQueue *)[number_of_threads];
    for (int i = 0; i < number_of_threads; ++i)
        comLoadEventQueue[i] = new EventQueue("load-based event queue");

    //
    // set up instruction-count-based termination events, if any
    //
    if (max_loads_any_thread != 0)
        for (int i = 0; i < number_of_threads; ++i)
            new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread,
                "a thread reached the max load count");

    if (max_loads_all_threads != 0) {
        // allocate & initialize shared downcounter: each event will
        // decrement this when triggered; simulation will terminate
        // when counter reaches 0
        int *counter = new int;
        *counter = number_of_threads;
        for (int i = 0; i < number_of_threads; ++i)
            new CountedExitEvent(comLoadEventQueue[i],
                "all threads reached the max load count",
                max_loads_all_threads, *counter);
    }

#ifdef FULL_SYSTEM
    memset(interrupts, 0, sizeof(interrupts));
    intstatus = 0;
#endif
}

void
BaseCPU::regStats()
{
    int size = execContexts.size();
    if (size > 1) {
        for (int i = 0; i < size; ++i) {
            stringstream namestr;
            ccprintf(namestr, "%s.ctx%d", name(), i);
            execContexts[i]->regStats(namestr.str());
        }
    } else if (size == 1)
        execContexts[0]->regStats(name());
}

void
BaseCPU::registerExecContexts()
{
    for (int i = 0; i < execContexts.size(); ++i) {
        ExecContext *xc = execContexts[i];
        int cpu_id;

#ifdef FULL_SYSTEM
        cpu_id = system->registerExecContext(xc);
#else
        cpu_id = xc->process->registerExecContext(xc);
#endif

        xc->cpu_id = cpu_id;
    }
}

void
BaseCPU::switchOut()
{
    // default: do nothing
}

void
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
{
    assert(execContexts.size() == oldCPU->execContexts.size());

    for (int i = 0; i < execContexts.size(); ++i) {
        ExecContext *newXC = execContexts[i];
        ExecContext *oldXC = oldCPU->execContexts[i];

        newXC->takeOverFrom(oldXC);
        assert(newXC->cpu_id == oldXC->cpu_id);
#ifdef FULL_SYSTEM
        system->replaceExecContext(newXC->cpu_id, newXC);
#else
        assert(newXC->process == oldXC->process);
        newXC->process->replaceExecContext(newXC->cpu_id, newXC);
#endif
    }

    for (int i = 0; i < NumInterruptLevels; ++i)
        interrupts[i] = oldCPU->interrupts[i];
    intstatus = oldCPU->intstatus;
}

#ifdef FULL_SYSTEM
void
BaseCPU::post_interrupt(int int_num, int index)
{
    DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);

    if (int_num < 0 || int_num >= NumInterruptLevels)
        panic("int_num out of bounds\n");

    if (index < 0 || index >= sizeof(uint8_t) * 8)
        panic("int_num out of bounds\n");

    AlphaISA::check_interrupts = 1;
    interrupts[int_num] |= 1 << index;
    intstatus |= (ULL(1) << int_num);
}

void
BaseCPU::clear_interrupt(int int_num, int index)
{
    DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);

    if (int_num < 0 || int_num >= NumInterruptLevels)
        panic("int_num out of bounds\n");

    if (index < 0 || index >= sizeof(uint8_t) * 8)
        panic("int_num out of bounds\n");

    interrupts[int_num] &= ~(1 << index);
    if (interrupts[int_num] == 0)
        intstatus &= ~(ULL(1) << int_num);
}

void
BaseCPU::clear_interrupts()
{
    DPRINTF(Interrupt, "Interrupts all cleared\n");

    memset(interrupts, 0, sizeof(interrupts));
    intstatus = 0;
}

#endif // FULL_SYSTEM

//
// This declaration is not needed now that SamplingCPU provides a
// BaseCPUBuilder object.
//
#if 0
DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
#endif
<commit_msg>Fix the swichover code.  It's only for FULL_SYSTEM<commit_after>/*
 * Copyright (c) 2003 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 */

#include <string>
#include <sstream>
#include <iostream>

#include "cpu/base_cpu.hh"
#include "base/cprintf.hh"
#include "cpu/exec_context.hh"
#include "base/misc.hh"
#include "sim/param.hh"
#include "sim/sim_events.hh"

using namespace std;

vector<BaseCPU *> BaseCPU::cpuList;

// This variable reflects the max number of threads in any CPU.  Be
// careful to only use it once all the CPUs that you care about have
// been initialized
int maxThreadsPerCPU = 1;

#ifdef FULL_SYSTEM
BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
                 Counter max_insts_any_thread,
                 Counter max_insts_all_threads,
                 Counter max_loads_any_thread,
                 Counter max_loads_all_threads,
                 System *_system, Tick freq)
    : SimObject(_name), frequency(freq),
      number_of_threads(_number_of_threads), system(_system)
#else
BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
                 Counter max_insts_any_thread,
                 Counter max_insts_all_threads,
                 Counter max_loads_any_thread,
                 Counter max_loads_all_threads)
    : SimObject(_name), number_of_threads(_number_of_threads)
#endif
{
    // add self to global list of CPUs
    cpuList.push_back(this);

    if (number_of_threads > maxThreadsPerCPU)
        maxThreadsPerCPU = number_of_threads;

    // allocate per-thread instruction-based event queues
    comInstEventQueue = new (EventQueue *)[number_of_threads];
    for (int i = 0; i < number_of_threads; ++i)
        comInstEventQueue[i] = new EventQueue("instruction-based event queue");

    //
    // set up instruction-count-based termination events, if any
    //
    if (max_insts_any_thread != 0)
        for (int i = 0; i < number_of_threads; ++i)
            new SimExitEvent(comInstEventQueue[i], max_insts_any_thread,
                "a thread reached the max instruction count");

    if (max_insts_all_threads != 0) {
        // allocate & initialize shared downcounter: each event will
        // decrement this when triggered; simulation will terminate
        // when counter reaches 0
        int *counter = new int;
        *counter = number_of_threads;
        for (int i = 0; i < number_of_threads; ++i)
            new CountedExitEvent(comInstEventQueue[i],
                "all threads reached the max instruction count",
                max_insts_all_threads, *counter);
    }

    // allocate per-thread load-based event queues
    comLoadEventQueue = new (EventQueue *)[number_of_threads];
    for (int i = 0; i < number_of_threads; ++i)
        comLoadEventQueue[i] = new EventQueue("load-based event queue");

    //
    // set up instruction-count-based termination events, if any
    //
    if (max_loads_any_thread != 0)
        for (int i = 0; i < number_of_threads; ++i)
            new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread,
                "a thread reached the max load count");

    if (max_loads_all_threads != 0) {
        // allocate & initialize shared downcounter: each event will
        // decrement this when triggered; simulation will terminate
        // when counter reaches 0
        int *counter = new int;
        *counter = number_of_threads;
        for (int i = 0; i < number_of_threads; ++i)
            new CountedExitEvent(comLoadEventQueue[i],
                "all threads reached the max load count",
                max_loads_all_threads, *counter);
    }

#ifdef FULL_SYSTEM
    memset(interrupts, 0, sizeof(interrupts));
    intstatus = 0;
#endif
}

void
BaseCPU::regStats()
{
    int size = execContexts.size();
    if (size > 1) {
        for (int i = 0; i < size; ++i) {
            stringstream namestr;
            ccprintf(namestr, "%s.ctx%d", name(), i);
            execContexts[i]->regStats(namestr.str());
        }
    } else if (size == 1)
        execContexts[0]->regStats(name());
}

void
BaseCPU::registerExecContexts()
{
    for (int i = 0; i < execContexts.size(); ++i) {
        ExecContext *xc = execContexts[i];
        int cpu_id;

#ifdef FULL_SYSTEM
        cpu_id = system->registerExecContext(xc);
#else
        cpu_id = xc->process->registerExecContext(xc);
#endif

        xc->cpu_id = cpu_id;
    }
}

void
BaseCPU::switchOut()
{
    // default: do nothing
}

void
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
{
    assert(execContexts.size() == oldCPU->execContexts.size());

    for (int i = 0; i < execContexts.size(); ++i) {
        ExecContext *newXC = execContexts[i];
        ExecContext *oldXC = oldCPU->execContexts[i];

        newXC->takeOverFrom(oldXC);
        assert(newXC->cpu_id == oldXC->cpu_id);
#ifdef FULL_SYSTEM
        system->replaceExecContext(newXC->cpu_id, newXC);
#else
        assert(newXC->process == oldXC->process);
        newXC->process->replaceExecContext(newXC->cpu_id, newXC);
#endif
    }

#ifdef FULL_SYSTEM
    for (int i = 0; i < NumInterruptLevels; ++i)
        interrupts[i] = oldCPU->interrupts[i];
    intstatus = oldCPU->intstatus;
#endif
}

#ifdef FULL_SYSTEM
void
BaseCPU::post_interrupt(int int_num, int index)
{
    DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);

    if (int_num < 0 || int_num >= NumInterruptLevels)
        panic("int_num out of bounds\n");

    if (index < 0 || index >= sizeof(uint8_t) * 8)
        panic("int_num out of bounds\n");

    AlphaISA::check_interrupts = 1;
    interrupts[int_num] |= 1 << index;
    intstatus |= (ULL(1) << int_num);
}

void
BaseCPU::clear_interrupt(int int_num, int index)
{
    DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);

    if (int_num < 0 || int_num >= NumInterruptLevels)
        panic("int_num out of bounds\n");

    if (index < 0 || index >= sizeof(uint8_t) * 8)
        panic("int_num out of bounds\n");

    interrupts[int_num] &= ~(1 << index);
    if (interrupts[int_num] == 0)
        intstatus &= ~(ULL(1) << int_num);
}

void
BaseCPU::clear_interrupts()
{
    DPRINTF(Interrupt, "Interrupts all cleared\n");

    memset(interrupts, 0, sizeof(interrupts));
    intstatus = 0;
}

#endif // FULL_SYSTEM

//
// This declaration is not needed now that SamplingCPU provides a
// BaseCPUBuilder object.
//
#if 0
DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <set>

#include <boost/test/unit_test.hpp>

#include <seastar/core/thread.hh>

#include "sstables/sstables.hh"
#include "compress.hh"
#include "schema_builder.hh"
#include "tests/test-utils.hh"

using namespace sstables;

class sstable_assertions final {
    shared_sstable _sst;
public:
    sstable_assertions(schema_ptr schema, const sstring& path, int generation = 1)
        : _sst(make_sstable(std::move(schema),
                            path,
                            generation,
                            sstable_version_types::mc,
                            sstable_format_types::big))
    { }
    void read_toc() {
        _sst->read_toc().get();
    }
    void read_summary() {
        _sst->read_summary(default_priority_class()).get();
    }
    void assert_toc(const std::set<component_type>& expected_components) {
        for (auto& expected : expected_components) {
            if(_sst->_recognized_components.count(expected) == 0) {
                BOOST_FAIL(sprint("Expected component of TOC missing: %s\n ... in: %s",
                                  expected,
                                  std::set<component_type>(
                                      cbegin(_sst->_recognized_components),
                                      cend(_sst->_recognized_components))));
            }
        }
        for (auto& present : _sst->_recognized_components) {
            if (expected_components.count(present) == 0) {
                BOOST_FAIL(sprint("Unexpected component of TOC: %s\n ... when expecting: %s",
                                  present,
                                  expected_components));
            }
        }
    }
};

// Following tests run on files in tests/sstables/3.x/uncompressed/simple
// They were created using following CQL statements:
//
// CREATE KEYSPACE test_ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
//
// CREATE TABLE test_ks.test_table ( pk INT, ck INT, val INT, PRIMARY KEY(pk, ck))
//      WITH compression = { 'enabled' : false };
//
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(1, 101, 1001);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(2, 102, 1002);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(3, 103, 1003);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(4, 104, 1004);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(5, 105, 1005);

static thread_local const sstring UNCOMPRESSED_SIMPLE_PATH = "tests/sstables/3.x/uncompressed/simple";
static thread_local const schema_ptr UNCOMPRESSED_SIMPLE_SCHEMA =
    schema_builder("test_ks", "test_table")
        .with_column("pk", int32_type, column_kind::partition_key)
        .with_column("ck", int32_type, column_kind::clustering_key)
        .with_column("val", int32_type)
        .build();

SEASTAR_TEST_CASE(test_uncompressed_simple_read_toc) {
    return seastar::async([] {
        sstable_assertions sst(UNCOMPRESSED_SIMPLE_SCHEMA, UNCOMPRESSED_SIMPLE_PATH);
        sst.read_toc();
        using ct = component_type;
        sst.assert_toc({ct::Index,
                        ct::Data,
                        ct::TOC,
                        ct::Summary,
                        ct::Digest,
                        ct::CRC,
                        ct::Filter,
                        ct::Statistics});
    });
}

SEASTAR_TEST_CASE(test_uncompressed_simple_read_summary) {
    return seastar::async([] {
        sstable_assertions sst(UNCOMPRESSED_SIMPLE_SCHEMA, UNCOMPRESSED_SIMPLE_PATH);
        sst.read_toc();
        sst.read_summary();
    });
}

<commit_msg>Add test for reading filter<commit_after>/*
 * Copyright (C) 2018 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <set>

#include <boost/test/unit_test.hpp>

#include <seastar/core/thread.hh>

#include "sstables/sstables.hh"
#include "compress.hh"
#include "schema_builder.hh"
#include "tests/test-utils.hh"

using namespace sstables;

class sstable_assertions final {
    shared_sstable _sst;
public:
    sstable_assertions(schema_ptr schema, const sstring& path, int generation = 1)
        : _sst(make_sstable(std::move(schema),
                            path,
                            generation,
                            sstable_version_types::mc,
                            sstable_format_types::big))
    { }
    void read_toc() {
        _sst->read_toc().get();
    }
    void read_summary() {
        _sst->read_summary(default_priority_class()).get();
    }
    void read_filter() {
        _sst->read_filter(default_priority_class()).get();
    }
    void assert_toc(const std::set<component_type>& expected_components) {
        for (auto& expected : expected_components) {
            if(_sst->_recognized_components.count(expected) == 0) {
                BOOST_FAIL(sprint("Expected component of TOC missing: %s\n ... in: %s",
                                  expected,
                                  std::set<component_type>(
                                      cbegin(_sst->_recognized_components),
                                      cend(_sst->_recognized_components))));
            }
        }
        for (auto& present : _sst->_recognized_components) {
            if (expected_components.count(present) == 0) {
                BOOST_FAIL(sprint("Unexpected component of TOC: %s\n ... when expecting: %s",
                                  present,
                                  expected_components));
            }
        }
    }
};

// Following tests run on files in tests/sstables/3.x/uncompressed/simple
// They were created using following CQL statements:
//
// CREATE KEYSPACE test_ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
//
// CREATE TABLE test_ks.test_table ( pk INT, ck INT, val INT, PRIMARY KEY(pk, ck))
//      WITH compression = { 'enabled' : false };
//
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(1, 101, 1001);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(2, 102, 1002);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(3, 103, 1003);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(4, 104, 1004);
// INSERT INTO test_ks.test_table(pk, ck, val) VALUES(5, 105, 1005);

static thread_local const sstring UNCOMPRESSED_SIMPLE_PATH = "tests/sstables/3.x/uncompressed/simple";
static thread_local const schema_ptr UNCOMPRESSED_SIMPLE_SCHEMA =
    schema_builder("test_ks", "test_table")
        .with_column("pk", int32_type, column_kind::partition_key)
        .with_column("ck", int32_type, column_kind::clustering_key)
        .with_column("val", int32_type)
        .build();

SEASTAR_TEST_CASE(test_uncompressed_simple_read_toc) {
    return seastar::async([] {
        sstable_assertions sst(UNCOMPRESSED_SIMPLE_SCHEMA, UNCOMPRESSED_SIMPLE_PATH);
        sst.read_toc();
        using ct = component_type;
        sst.assert_toc({ct::Index,
                        ct::Data,
                        ct::TOC,
                        ct::Summary,
                        ct::Digest,
                        ct::CRC,
                        ct::Filter,
                        ct::Statistics});
    });
}

SEASTAR_TEST_CASE(test_uncompressed_simple_read_summary) {
    return seastar::async([] {
        sstable_assertions sst(UNCOMPRESSED_SIMPLE_SCHEMA, UNCOMPRESSED_SIMPLE_PATH);
        sst.read_toc();
        sst.read_summary();
    });
}

SEASTAR_TEST_CASE(test_uncompressed_simple_read_filter) {
    return seastar::async([] {
        sstable_assertions sst(UNCOMPRESSED_SIMPLE_SCHEMA, UNCOMPRESSED_SIMPLE_PATH);
        sst.read_toc();
        sst.read_filter();
    });
}

<|endoftext|>


<commit_before>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>

#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <boost/random/normal_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/gamma_distribution.hpp>
#include <boost/random/variate_generator.hpp>

using namespace Eigen;
using namespace std;

typedef SparseMatrix<double> SparseMatrixD;

const int num_feat = 30;
unsigned num_p = 0;
unsigned num_m = 0;

const int alpha = 2;
const int nsims = 2;
const int burnin = 5;

double mean_rating;

SparseMatrixD M;

MatrixXd sample_u;
MatrixXd sample_m;

VectorXd mu_u(num_feat);
VectorXd mu_m(num_feat);
MatrixXd Lambda_u(num_feat, num_feat);
MatrixXd Lambda_m(num_feat, num_feat);

// parameters of Inv-Whishart distribution (see paper for details)
MatrixXd WI_u(num_feat, num_feat);
const int b0_u = 2;
const int df_u = num_feat;
VectorXd mu0_u(num_feat);

MatrixXd WI_m(num_feat, num_feat);
const int b0_m = 2;
const int df_m = num_feat;
VectorXd mu0_m(num_feat);

void loadChemo()
{
    typedef Eigen::Triplet<double> T;
    std::vector<T> lst;
    lst.reserve(100000);

    FILE *f = fopen("../data/chembl_19_mf1/chembl-IC50-360targets.csv", "r");
    assert(f);

    // skip header
    char buf[2048];
    fscanf(f, "%s\n", buf);

    // data
    unsigned i, j;
    double v_ij;
    while (!feof(f)) {
        if (!fscanf(f, "%d,%d,%lg\n", &i, &j, &v_ij)) continue;
        num_p = std::max(num_p, i);
        num_m = std::max(num_m, j);
        lst.push_back(T(i,j,v_ij));
    }
    num_p++;
    num_m++;

    fclose(f);

    M = SparseMatrix<double>(num_p, num_m);
    M.setFromTriplets(lst.begin(), lst.end());
}

void init() {
    mean_rating = M.sum() / M.nonZeros();
    Lambda_u.setIdentity();
    Lambda_m.setIdentity();

    // parameters of Inv-Whishart distribution (see paper for details)
    WI_u.setIdentity();
    mu0_u.setZero();

    WI_m.setIdentity();
    mu0_m.setZero();

    sample_u = MatrixXd(num_p, num_feat);
    sample_u.setZero();
    sample_m = MatrixXd(num_m, num_feat);
    sample_m.setZero();
}

/*
function pred(probe_vec, sample_m, sample_u, mean_rating)
  sum(sample_m[probe_vec[:,2],:].*sample_u[probe_vec[:,1],:],2) + mean_rating
end
*/

double rand(double mean = 0.5, double sigma = 1)
{
    boost::mt19937 gen;
    boost::random::normal_distribution<> dist(mean,sigma);
    return dist(gen);
}

VectorXd randn(int n, double mean = 0.5, double sigma = 1)
{
    VectorXd ret(n);
    boost::mt19937 gen;
    boost::random::normal_distribution<> dist(mean,sigma);

    for(int i=0; i<n; ++i) ret(i) = dist(gen);

    return ret;
}

MatrixXd sample_movie(int mm, SparseMatrixD &mat, double mean_rating,
    MatrixXd sample_u, int alpha, MatrixXd mu_u, MatrixXd Lambda_u)
{
    int i = 0;
    MatrixXd E(mat.col(mm).nonZeros(), num_feat);
    VectorXd rr(mat.col(mm).nonZeros());
    for (SparseMatrixD::InnerIterator it(mat,mm); it; ++it, ++i) {
        //cout << "M[" << it.row() << "," << it.col() << "] = " << it.value() << endl;
        E.row(i) = sample_u.row(it.row());
        rr(i) = it.value() - mean_rating;
    }

    auto MM = E.transpose() * E;
    MatrixXd MMs = alpha * MM.array();
    assert(MMs.cols() == num_feat && MMs.rows() == num_feat);
    auto covar = (Lambda_u + MMs).inverse();
    auto MMrr = E.transpose() * rr;
    MMrr.array() *= alpha;
    auto U = Lambda_u * mu_u;
    auto mu = covar * (MMrr + U);

    auto chol = covar.llt().matrixL().transpose();
    auto result = chol * randn(num_feat) + mu;
    return result.transpose();
}

MatrixXd WishartUnit(MatrixXd sigma, int df)
{
    auto m = sigma.cols();
    MatrixXd c(m,m);
    c.setZero();

    for ( int i = 0; i < m; i++ ) {
        boost::gamma_distribution<> chi(0.5*(df - i));
        boost::mt19937 rng;
        boost::variate_generator<boost::mt19937&, boost::gamma_distribution<> > gen(rng, chi);
        c(i,i) = sqrt(2.0 * chi(gen));
        c.block(i,i+1,1,m-i) = randn(m-i);
    }

    return c.transpose() * c;
}

MatrixXd Wishart(MatrixXd sigma, int df)
{
  MatrixXd r = sigma.llt().matrixU();
  auto u = WishartUnit(sigma, df);
  return r.transpose() * u;
}

void run() {
    double err_avg = 0.0;
    double err = 0.0;

    SparseMatrixD Mt = M.transpose();

    std::cout << "Sampling" << endl;
    for(int i=0; i<nsims; ++i) {

#if 0
      // Sample from movie hyperparams
      mu_m, Lambda_m = rand( ConditionalNormalWishart(sample_m, vec(mu0_m), b0_m, WI_m, df_m) )

      // Sample from user hyperparams
      mu_u, Lambda_u = rand( ConditionalNormalWishart(sample_u, vec(mu0_u), b0_u, WI_u, df_u) )
#endif

#pragma omp parallel for
      for(int mm = 1; mm < num_m; ++mm) {
        sample_m.row(mm) = sample_movie(mm, M, mean_rating, sample_u, alpha, mu_m, Lambda_m);
      }

      for(int uu = 1; uu < num_p; ++uu) {
        sample_u.row(uu) = sample_movie(uu, Mt, mean_rating, sample_m, alpha, mu_u, Lambda_u);
      }
#if 0

      probe_rat = pred(probe_vec, sample_m, sample_u, mean_rating)

      if i > burnin
        probe_rat_all = (counter_prob*probe_rat_all + probe_rat)/(counter_prob+1)
        counter_prob = counter_prob + 1
      else
        probe_rat_all = probe_rat
        counter_prob = 1
      end

      err_avg = mean(ratings_test .== (probe_rat_all .< log10(200)))
      err = mean(ratings_test .== (probe_rat .< log10(200)))

      printf("Iteration %d:\t avg RMSE %6.4f RMSE %6.4f FU(%6.4f) FM(%6.4f)\n", i, err_avg, err, vecnorm(sample_u), vecnorm(sample_m));
#endif
    }
}

int main()
{
    loadChemo();
    init();
    run();

    return 0;
}
<commit_msg>bpmf: c++ updates<commit_after>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>

#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <boost/random/normal_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/gamma_distribution.hpp>
#include <boost/random/variate_generator.hpp>

using namespace Eigen;
using namespace std;

typedef SparseMatrix<double> SparseMatrixD;

const int num_feat = 30;
unsigned num_p = 0;
unsigned num_m = 0;

const int alpha = 2;
const int nsims = 2;
const int burnin = 5;

double mean_rating;

SparseMatrixD M;

MatrixXd sample_u;
MatrixXd sample_m;

VectorXd mu_u(num_feat);
VectorXd mu_m(num_feat);
MatrixXd Lambda_u(num_feat, num_feat);
MatrixXd Lambda_m(num_feat, num_feat);

// parameters of Inv-Whishart distribution (see paper for details)
MatrixXd WI_u(num_feat, num_feat);
const int b0_u = 2;
const int df_u = num_feat;
VectorXd mu0_u(num_feat);

MatrixXd WI_m(num_feat, num_feat);
const int b0_m = 2;
const int df_m = num_feat;
VectorXd mu0_m(num_feat);

void loadChemo()
{
    typedef Eigen::Triplet<double> T;
    std::vector<T> lst;
    lst.reserve(100000);

    FILE *f = fopen("../data/chembl_19_mf1/chembl-IC50-360targets.csv", "r");
    assert(f);

    // skip header
    char buf[2048];
    fscanf(f, "%s\n", buf);

    // data
    unsigned i, j;
    double v_ij;
    while (!feof(f)) {
        if (!fscanf(f, "%d,%d,%lg\n", &i, &j, &v_ij)) continue;
        num_p = std::max(num_p, i);
        num_m = std::max(num_m, j);
        lst.push_back(T(i,j,v_ij));
    }
    num_p++;
    num_m++;

    fclose(f);

    M = SparseMatrix<double>(num_p, num_m);
    M.setFromTriplets(lst.begin(), lst.end());
}

void init() {
    mean_rating = M.sum() / M.nonZeros();
    Lambda_u.setIdentity();
    Lambda_m.setIdentity();

    // parameters of Inv-Whishart distribution (see paper for details)
    WI_u.setIdentity();
    mu0_u.setZero();

    WI_m.setIdentity();
    mu0_m.setZero();

    sample_u = MatrixXd(num_p, num_feat);
    sample_u.setZero();
    sample_m = MatrixXd(num_m, num_feat);
    sample_m.setZero();
}

/*
function pred(probe_vec, sample_m, sample_u, mean_rating)
  sum(sample_m[probe_vec[:,2],:].*sample_u[probe_vec[:,1],:],2) + mean_rating
end
*/

double rand(double mean = 0.5, double sigma = 1)
{
    boost::mt19937 gen;
    boost::random::normal_distribution<> dist(mean,sigma);
    return dist(gen);
}

VectorXd randn(int n, double mean = 0.5, double sigma = 1)
{
    VectorXd ret(n);
    boost::mt19937 gen;
    boost::random::normal_distribution<> dist(mean,sigma);

    for(int i=0; i<n; ++i) ret(i) = dist(gen);

    return ret;
}

MatrixXd sample_movie(int mm, SparseMatrixD &mat, double mean_rating,
    MatrixXd sample_u, int alpha, MatrixXd mu_u, MatrixXd Lambda_u)
{
    int i = 0;
    MatrixXd E(mat.col(mm).nonZeros(), num_feat);
    VectorXd rr(mat.col(mm).nonZeros());
    for (SparseMatrixD::InnerIterator it(mat,mm); it; ++it, ++i) {
        //cout << "M[" << it.row() << "," << it.col() << "] = " << it.value() << endl;
        E.row(i) = sample_u.row(it.row());
        rr(i) = it.value() - mean_rating;
    }

    auto MM = E.transpose() * E;
    MatrixXd MMs = alpha * MM.array();
    assert(MMs.cols() == num_feat && MMs.rows() == num_feat);
    auto covar = (Lambda_u + MMs).inverse();
    auto MMrr = E.transpose() * rr;
    MMrr.array() *= alpha;
    auto U = Lambda_u * mu_u;
    auto mu = covar * (MMrr + U);

    auto chol = covar.llt().matrixL().transpose();
    auto result = chol * randn(num_feat) + mu;
    return result.transpose();
}

MatrixXd WishartUnit(MatrixXd sigma, int df)
{
    auto m = sigma.cols();
    MatrixXd c(m,m);
    c.setZero();

    for ( int i = 0; i < m; i++ ) {
        boost::gamma_distribution<> chi(0.5*(df - i));
        boost::mt19937 rng;
        boost::variate_generator<boost::mt19937&, boost::gamma_distribution<> > gen(rng, chi);
        c(i,i) = sqrt(2.0 * chi(gen));
        c.block(i,i+1,1,m-i) = randn(m-i);
    }

    return c.transpose() * c;
}

MatrixXd Wishart(MatrixXd sigma, int df)
{
  MatrixXd r = sigma.llt().matrixU();
  auto u = WishartUnit(sigma, df);
  return r.transpose() * u;
}

MatrixXd NormalWishart(
  WI_u = eye(num_feat);
  b0_u = 2;
  df_u = num_feat;
  mu0_u = zeros(num_feat,1);
  WI_u = eye(num_feat);
  b0_u = 2;
  df_u = num_feat;
  mu0_u = zeros(num_feat,1);

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %%% Sample from user hyperparams
  N = size(w1_P1_sample,1);
  x_bar = mean(w1_P1_sample)';
  S_bar = cov(w1_P1_sample);

  WI_post = inv(inv(WI_u) + N/1*S_bar + ...
            N*b0_u*(mu0_u - x_bar)*(mu0_u - x_bar)'/(1*(b0_u+N)));
  WI_post = (WI_post + WI_post')/2;
  df_mpost = df_u+N;
  alpha_u = wishrnd(WI_post,df_mpost);
  mu_temp = (b0_u*mu0_u + N*x_bar)/(b0_u+N);
  lam = chol( inv((b0_u+N)*alpha_u) ); lam=lam';
  mu_u = lam*randn(num_feat,1)+mu_temp;

MatrixXd CondWishart(MatrixXd sigma, int df)
{
  MatrixXd r = sigma.llt().matrixU();
  auto u = WishartUnit(sigma, df);
  return r.transpose() * u;
}

void run() {
    double err_avg = 0.0;
    double err = 0.0;

    SparseMatrixD Mt = M.transpose();

    std::cout << "Sampling" << endl;
    for(int i=0; i<nsims; ++i) {

#if 0
      // Sample from movie hyperparams
      mu_m, Lambda_m = rand( ConditionalNormalWishart(sample_m, vec(mu0_m), b0_m, WI_m, df_m) )

      // Sample from user hyperparams
      mu_u, Lambda_u = rand( ConditionalNormalWishart(sample_u, vec(mu0_u), b0_u, WI_u, df_u) )
#endif

#pragma omp parallel for
      for(int mm = 1; mm < num_m; ++mm) {
        sample_m.row(mm) = sample_movie(mm, M, mean_rating, sample_u, alpha, mu_m, Lambda_m);
      }

      for(int uu = 1; uu < num_p; ++uu) {
        sample_u.row(uu) = sample_movie(uu, Mt, mean_rating, sample_m, alpha, mu_u, Lambda_u);
      }
#if 0

      probe_rat = pred(probe_vec, sample_m, sample_u, mean_rating)

      if i > burnin
        probe_rat_all = (counter_prob*probe_rat_all + probe_rat)/(counter_prob+1)
        counter_prob = counter_prob + 1
      else
        probe_rat_all = probe_rat
        counter_prob = 1
      end

      err_avg = mean(ratings_test .== (probe_rat_all .< log10(200)))
      err = mean(ratings_test .== (probe_rat .< log10(200)))

      printf("Iteration %d:\t avg RMSE %6.4f RMSE %6.4f FU(%6.4f) FM(%6.4f)\n", i, err_avg, err, vecnorm(sample_u), vecnorm(sample_m));
#endif
    }
}

int main()
{
    loadChemo();
    init();
    run();

    return 0;
}
<|endoftext|>


<commit_before>#include "IfNode.h"
#include "../Parser.h"

#include <assert.h>

namespace Language {
    IfNode* IfNode::parse(Parser& parser) {
        IfNode* node = new IfNode();

        node->setStatement(true);

        assert(parser.next().type() == Token::Type::KeywordIf);

        // parse the condition
        node->_conditionNode = parser.parseExpression();

        parser.parseNewline();

        // and now, parse the body
        while (true) {
            Token t = parser.peek();

            if (t.type() == Token::Type::KeywordEnd || t.type() == Token::Type::KeywordElse) {
                break;
            }

            node->addChild(parser.parseStatement());
        }

        if (parser.peek().type() == Token::Type::KeywordElse) {
            node->_elseNode = ElseNode::parse(parser);
        } else {
            assert(parser.next().type() == Token::Type::KeywordEnd);
        }

        return node;
    }

    ASTNode* IfNode::parseTailing(Parser& parser, ASTNode* node) {
        if (parser.peek().type() != Token::Type::KeywordIf) {
            return node;
        }

        assert(parser.next().type() == Token::Type::KeywordIf);

        IfNode* ifNode = new IfNode();

        ifNode->addChild(node);

        ifNode->_conditionNode = parser.parseExpression();

        return ifNode;
    }

    IfNode::IfNode() : _elseNode(NULL) {
    }

    std::string IfNode::name() const {
        return "If";
    }

    ASTNode* IfNode::condition() const {
        return _conditionNode;
    }

    ElseNode* IfNode::elseStatement() const {
        return _elseNode;
    }

    void IfNode::codeGenCSource(CSourceContext& context) {
        context.current()->print("if (");

        this->condition()->codeGenCSource(context);

        context.current()->printLineAndIndent(") {");

        this->codeGenCSourceForChildren(context);

        context.current()->decreaseIndentation();
        context.current()->printNewLine();

        if (this->elseStatement()) {
            context.current()->print("} else {");
            context.current()->increaseIndentation();
            context.current()->printNewLine();

            this->elseStatement()->codeGenCSourceForChildren(context);

            context.current()->decreaseIndentation();
            context.current()->printNewLine();
        }

        context.current()->print("}");
    }
}
<commit_msg>Improvements to C codegen of if statements<commit_after>#include "IfNode.h"
#include "../Parser.h"

#include <assert.h>

namespace Language {
    IfNode* IfNode::parse(Parser& parser) {
        IfNode* node = new IfNode();

        node->setStatement(true);

        assert(parser.next().type() == Token::Type::KeywordIf);

        // parse the condition
        node->_conditionNode = parser.parseExpression();

        parser.parseNewline();

        // and now, parse the body
        while (true) {
            Token t = parser.peek();

            if (t.type() == Token::Type::KeywordEnd || t.type() == Token::Type::KeywordElse) {
                break;
            }

            node->addChild(parser.parseStatement());
        }

        if (parser.peek().type() == Token::Type::KeywordElse) {
            node->_elseNode = ElseNode::parse(parser);
        } else {
            assert(parser.next().type() == Token::Type::KeywordEnd);
        }

        return node;
    }

    ASTNode* IfNode::parseTailing(Parser& parser, ASTNode* node) {
        if (parser.peek().type() != Token::Type::KeywordIf) {
            return node;
        }

        assert(parser.next().type() == Token::Type::KeywordIf);

        IfNode* ifNode = new IfNode();

        ifNode->addChild(node);

        ifNode->_conditionNode = parser.parseExpression();

        return ifNode;
    }

    IfNode::IfNode() : _elseNode(NULL) {
    }

    std::string IfNode::name() const {
        return "If";
    }

    ASTNode* IfNode::condition() const {
        return _conditionNode;
    }

    ElseNode* IfNode::elseStatement() const {
        return _elseNode;
    }

    void IfNode::codeGenCSource(CSourceContext& context) {
        context.current()->print("if (");

        this->condition()->codeGenCSource(context);

        context.current()->printLineAndIndent(") {");

        this->codeGenCSourceForChildren(context);

        if (this->elseStatement()) {
            context.current()->outdentAndPrintLine("} else {");
            context.current()->increaseIndentation();

            this->elseStatement()->codeGenCSourceForChildren(context);
        }

        context.current()->outdentAndPrintLine("}");
    }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SC_MATRIX_HXX
#define SC_MATRIX_HXX

#include "global.hxx"
#include "types.hxx"
#include "formula/errorcodes.hxx"
#include "scdllapi.h"
#include <rtl/ustring.hxx>

#include <boost/intrusive_ptr.hpp>

class ScInterpreter;
class SvNumberFormatter;
class ScMatrixImpl;

typedef sal_uInt8 ScMatValType;
const ScMatValType SC_MATVAL_VALUE     = 0x00;
const ScMatValType SC_MATVAL_BOOLEAN   = 0x01;
const ScMatValType SC_MATVAL_STRING    = 0x02;
const ScMatValType SC_MATVAL_EMPTY     = SC_MATVAL_STRING | 0x04; // STRING plus flag
const ScMatValType SC_MATVAL_EMPTYPATH = SC_MATVAL_EMPTY | 0x08;  // EMPTY plus flag
const ScMatValType SC_MATVAL_NONVALUE  = SC_MATVAL_EMPTYPATH;     // mask of all non-value bits

struct ScMatrixValue
{
    union {
        double fVal;
        const ::rtl::OUString* pS;
    };
    ScMatValType nType;

    /// Only valid if ScMatrix methods indicate so!
    const ::rtl::OUString& GetString() const { return pS ? *pS : EMPTY_OUSTRING; }

    /// Only valid if ScMatrix methods indicate that this is no string!
    sal_uInt16 GetError() const         { return GetDoubleErrorValue( fVal); }

    /// Only valid if ScMatrix methods indicate that this is a boolean
    bool GetBoolean() const         { return fVal != 0.0; }

    ScMatrixValue() : fVal(0.0), nType(SC_MATVAL_EMPTY) {}

    ScMatrixValue(const ScMatrixValue& r) : fVal(r.fVal), nType(r.nType)
    {
        if (nType == SC_MATVAL_STRING)
            // This is probably not necessary but just in case...
            pS = r.pS;
    }

    bool operator== (const ScMatrixValue& r) const
    {
        if (nType != r.nType)
            return false;

        switch (nType)
        {
            case SC_MATVAL_VALUE:
            case SC_MATVAL_BOOLEAN:
                return fVal == r.fVal;
            break;
            default:
                ;
        }
        if (!pS)
            return r.pS == NULL;

        return GetString().equals(r.GetString());
    }

    bool operator!= (const ScMatrixValue& r) const
    {
        return !operator==(r);
    }

    ScMatrixValue& operator= (const ScMatrixValue& r)
    {
        nType = r.nType;
        fVal = r.fVal;

        if (nType == SC_MATVAL_STRING)
            // This is probably not necessary but just in case...
            pS = r.pS;

        return *this;
    }
};

/**
 * Matrix data type that can store values of mixed types.  Each element can
 * be one of the following types: numeric, string, boolean, empty, and empty
 * path.
 *
 * This class also supports four different density types: filled zero,
 * filled empty, sparse zero, and sparse empty.  The filled density type
 * allocates memory for every single element at all times, whereas the
 * sparse density types allocates memory only for non-default elements.
 */
class SC_DLLPUBLIC ScMatrix
{
    ScMatrixImpl*   pImpl;
    mutable size_t  nRefCnt;    // reference count

    // only delete via Delete()
    ~ScMatrix();

    // not implemented, prevent usage
    ScMatrix( const ScMatrix& );
    ScMatrix& operator=( const ScMatrix&);

public:
    enum DensityType
    {
        FILLED_ZERO,
        FILLED_EMPTY,
        SPARSE_ZERO,
        SPARSE_EMPTY
    };

    /**
     * When adding all numerical matrix elements for a scalar result such as
     * summation, the interpreter wants to separate the first non-zero value
     * with the rest of the summed values.
     *
     * TODO: Find out if we still need to do this.  If not, we can re-write
     * ScInterpreter::IterateParameters() to make it simpler and remove this
     * struct.
     */
    struct IterateResult
    {
        double mfFirst;
        double mfRest;
        size_t mnCount;

        IterateResult(double fFirst, double fRest, size_t nCount) :
            mfFirst(fFirst), mfRest(fRest), mnCount(nCount) {}

        IterateResult(const IterateResult& r) :
            mfFirst(r.mfFirst), mfRest(r.mfRest), mnCount(r.mnCount) {}
    };

    /// The maximum number of elements a matrix may have at runtime.
    inline static size_t GetElementsMax()
    {
        // TODO: Fix me.
        return 0x08000000;
#if 0
        // Roughly 125MB in total, divided by 8+1 per element => 14M elements.
        const size_t nMemMax = 0x08000000 / (sizeof(ScMatrixValue) + sizeof(ScMatValType));
        // With MAXROWCOUNT==65536 and 128 columns => 8M elements ~72MB.
        const size_t nArbitraryLimit = (size_t)MAXROWCOUNT * 128;
        // Stuffed with a million rows would limit this to 14 columns.
        return nMemMax < nArbitraryLimit ? nMemMax : nArbitraryLimit;
#endif
    }

    /// Value or boolean.
    inline static bool IsValueType( ScMatValType nType )
    {
        return nType <= SC_MATVAL_BOOLEAN;
    }

    /// Boolean.
    inline static bool IsBooleanType( ScMatValType nType )
    {
        return nType == SC_MATVAL_BOOLEAN;
    }

    /// String, empty or empty path, but not value nor boolean.
    inline static bool IsNonValueType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) != 0;
    }

    /** String, but not empty or empty path or any other type.
        Not named IsStringType to prevent confusion because previously
        IsNonValueType was named IsStringType. */
    inline static bool IsRealStringType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_STRING;
    }

    /// Empty, but not empty path or any other type.
    inline static bool IsEmptyType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTY;
    }

    /// Empty path, but not empty or any other type.
    inline static bool IsEmptyPathType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTYPATH;
    }

    ScMatrix(SCSIZE nC, SCSIZE nR);
    ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal);

    /** Clone the matrix. */
    ScMatrix* Clone() const;

    /** Clone the matrix if mbCloneIfConst (immutable) is set, otherwise
        return _this_ matrix, to be assigned to a ScMatrixRef. */
    ScMatrix* CloneIfConst();

    /** Set the matrix to (im)mutable for CloneIfConst(), only the interpreter
        should do this and know the consequences. */
    void SetImmutable( bool bVal );

    /**
     * Resize the matrix to specified new dimension.
     */
    void Resize( SCSIZE nC, SCSIZE nR);

    void Resize(SCSIZE nC, SCSIZE nR, double fVal);

    /** Clone the matrix and extend it to the new size. nNewCols and nNewRows
        MUST be at least of the size of the original matrix. */
    ScMatrix* CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const;

    inline void IncRef() const
    {
        ++nRefCnt;
    }
    inline void DecRef() const
    {
        --nRefCnt;
        if (nRefCnt == 0)
            delete this;
    }

    void SetErrorInterpreter( ScInterpreter* p);
    void GetDimensions( SCSIZE& rC, SCSIZE& rR) const;
    SCSIZE GetElementCount() const;
    bool ValidColRow( SCSIZE nC, SCSIZE nR) const;
    SCSIZE CalcOffset( SCSIZE nC, SCSIZE nR) const;

    /** For a row vector or column vector, if the position does not point into
        the vector but is a valid column or row offset it is adapted such that
        it points to an element to be replicated, same column row 0 for a row
        vector, same row column 0 for a column vector. Else, for a 2D matrix,
        returns false.
     */
    bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const;

    /** Checks if the matrix position is within the matrix. If it is not, for a
        row vector or column vector the position is adapted such that it points
        to an element to be replicated, same column row 0 for a row vector,
        same row column 0 for a column vector. Else, for a 2D matrix and
        position not within matrix, returns false.
     */
    bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const;

    void PutDouble( double fVal, SCSIZE nC, SCSIZE nR);
    void PutDouble( double fVal, SCSIZE nIndex);
    void PutString( const ::rtl::OUString& rStr, SCSIZE nC, SCSIZE nR);
    void PutString( const ::rtl::OUString& rStr, SCSIZE nIndex);
    void PutEmpty( SCSIZE nC, SCSIZE nR);
    /// Jump FALSE without path
    void PutEmptyPath( SCSIZE nC, SCSIZE nR);
    void PutError( sal_uInt16 nErrorCode, SCSIZE nC, SCSIZE nR );
    void PutBoolean( bool bVal, SCSIZE nC, SCSIZE nR);

    void FillDouble( double fVal,
            SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );

    /** May be used before obtaining the double value of an element to avoid
        passing its NAN around.
        @ATTENTION: MUST NOT be used if the element is a string!
                    Use GetErrorIfNotString() instead if not sure.
        @returns 0 if no error, else one of err... constants */
    sal_uInt16 GetError( SCSIZE nC, SCSIZE nR) const;

    /** Use in ScInterpreter to obtain the error code, if any.
        @returns 0 if no error or string element, else one of err... constants */
    sal_uInt16 GetErrorIfNotString( SCSIZE nC, SCSIZE nR) const
        { return IsValue( nC, nR) ? GetError( nC, nR) : 0; }

    /// @return 0.0 if empty or empty path, else value or DoubleError.
    double GetDouble( SCSIZE nC, SCSIZE nR) const;
    /// @return 0.0 if empty or empty path, else value or DoubleError.
    double GetDouble( SCSIZE nIndex) const;

    /// @return empty string if empty or empty path, else string content.
    rtl::OUString GetString( SCSIZE nC, SCSIZE nR) const;
    /// @return empty string if empty or empty path, else string content.
    rtl::OUString GetString( SCSIZE nIndex) const;

    /** @returns the matrix element's string if one is present, otherwise the
        numerical value formatted as string, or in case of an error the error
        string is returned; an empty string for empty, a "FALSE" string for
        empty path. */
    ::rtl::OUString GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const;

    /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate
    /// an empty string!
    ScMatrixValue Get( SCSIZE nC, SCSIZE nR) const;

    /// @return <TRUE/> if string or empty or empty path, in fact non-value.
    sal_Bool IsString( SCSIZE nIndex ) const;

    /// @return <TRUE/> if string or empty or empty path, in fact non-value.
    sal_Bool IsString( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if empty or empty path.
    sal_Bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if empty path.
    sal_Bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if value or boolean.
    sal_Bool IsValue( SCSIZE nIndex ) const;

    /// @return <TRUE/> if value or boolean.
    sal_Bool IsValue( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if value or boolean or empty or empty path.
    sal_Bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if boolean.
    sal_Bool IsBoolean( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties
    sal_Bool IsNumeric() const;

    void MatTrans( ScMatrix& mRes) const;
    void MatCopy ( ScMatrix& mRes) const;

    // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values
    void CompareEqual();
    void CompareNotEqual();
    void CompareLess();
    void CompareGreater();
    void CompareLessEqual();
    void CompareGreaterEqual();

    double And() const;       // logical AND of all matrix values, or NAN
    double Or() const;        // logical OR of all matrix values, or NAN

    IterateResult Sum(bool bTextAsZero) const;
    IterateResult SumSquare(bool bTextAsZero) const;
    IterateResult Product(bool bTextAsZero) const;
    size_t Count(bool bCountStrings) const;

    // All other matrix functions  MatMult, MInv, ...  are in ScInterpreter
    // to be numerically safe.
};

inline void intrusive_ptr_add_ref(const ScMatrix* p)
{
    p->IncRef();
}

inline void intrusive_ptr_release(const ScMatrix* p)
{
    p->DecRef();
}

#endif  // SC_MATRIX_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>This is no longer true.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SC_MATRIX_HXX
#define SC_MATRIX_HXX

#include "global.hxx"
#include "types.hxx"
#include "formula/errorcodes.hxx"
#include "scdllapi.h"
#include <rtl/ustring.hxx>

#include <boost/intrusive_ptr.hpp>

class ScInterpreter;
class SvNumberFormatter;
class ScMatrixImpl;

typedef sal_uInt8 ScMatValType;
const ScMatValType SC_MATVAL_VALUE     = 0x00;
const ScMatValType SC_MATVAL_BOOLEAN   = 0x01;
const ScMatValType SC_MATVAL_STRING    = 0x02;
const ScMatValType SC_MATVAL_EMPTY     = SC_MATVAL_STRING | 0x04; // STRING plus flag
const ScMatValType SC_MATVAL_EMPTYPATH = SC_MATVAL_EMPTY | 0x08;  // EMPTY plus flag
const ScMatValType SC_MATVAL_NONVALUE  = SC_MATVAL_EMPTYPATH;     // mask of all non-value bits

struct ScMatrixValue
{
    union {
        double fVal;
        const ::rtl::OUString* pS;
    };
    ScMatValType nType;

    /// Only valid if ScMatrix methods indicate so!
    const ::rtl::OUString& GetString() const { return pS ? *pS : EMPTY_OUSTRING; }

    /// Only valid if ScMatrix methods indicate that this is no string!
    sal_uInt16 GetError() const         { return GetDoubleErrorValue( fVal); }

    /// Only valid if ScMatrix methods indicate that this is a boolean
    bool GetBoolean() const         { return fVal != 0.0; }

    ScMatrixValue() : fVal(0.0), nType(SC_MATVAL_EMPTY) {}

    ScMatrixValue(const ScMatrixValue& r) : fVal(r.fVal), nType(r.nType)
    {
        if (nType == SC_MATVAL_STRING)
            // This is probably not necessary but just in case...
            pS = r.pS;
    }

    bool operator== (const ScMatrixValue& r) const
    {
        if (nType != r.nType)
            return false;

        switch (nType)
        {
            case SC_MATVAL_VALUE:
            case SC_MATVAL_BOOLEAN:
                return fVal == r.fVal;
            break;
            default:
                ;
        }
        if (!pS)
            return r.pS == NULL;

        return GetString().equals(r.GetString());
    }

    bool operator!= (const ScMatrixValue& r) const
    {
        return !operator==(r);
    }

    ScMatrixValue& operator= (const ScMatrixValue& r)
    {
        nType = r.nType;
        fVal = r.fVal;

        if (nType == SC_MATVAL_STRING)
            // This is probably not necessary but just in case...
            pS = r.pS;

        return *this;
    }
};

/**
 * Matrix data type that can store values of mixed types.  Each element can
 * be one of the following types: numeric, string, boolean, empty, and empty
 * path.
 */
class SC_DLLPUBLIC ScMatrix
{
    ScMatrixImpl*   pImpl;
    mutable size_t  nRefCnt;    // reference count

    // only delete via Delete()
    ~ScMatrix();

    // not implemented, prevent usage
    ScMatrix( const ScMatrix& );
    ScMatrix& operator=( const ScMatrix&);

public:
    enum DensityType
    {
        FILLED_ZERO,
        FILLED_EMPTY,
        SPARSE_ZERO,
        SPARSE_EMPTY
    };

    /**
     * When adding all numerical matrix elements for a scalar result such as
     * summation, the interpreter wants to separate the first non-zero value
     * with the rest of the summed values.
     *
     * TODO: Find out if we still need to do this.  If not, we can re-write
     * ScInterpreter::IterateParameters() to make it simpler and remove this
     * struct.
     */
    struct IterateResult
    {
        double mfFirst;
        double mfRest;
        size_t mnCount;

        IterateResult(double fFirst, double fRest, size_t nCount) :
            mfFirst(fFirst), mfRest(fRest), mnCount(nCount) {}

        IterateResult(const IterateResult& r) :
            mfFirst(r.mfFirst), mfRest(r.mfRest), mnCount(r.mnCount) {}
    };

    /// The maximum number of elements a matrix may have at runtime.
    inline static size_t GetElementsMax()
    {
        // TODO: Fix me.
        return 0x08000000;
#if 0
        // Roughly 125MB in total, divided by 8+1 per element => 14M elements.
        const size_t nMemMax = 0x08000000 / (sizeof(ScMatrixValue) + sizeof(ScMatValType));
        // With MAXROWCOUNT==65536 and 128 columns => 8M elements ~72MB.
        const size_t nArbitraryLimit = (size_t)MAXROWCOUNT * 128;
        // Stuffed with a million rows would limit this to 14 columns.
        return nMemMax < nArbitraryLimit ? nMemMax : nArbitraryLimit;
#endif
    }

    /// Value or boolean.
    inline static bool IsValueType( ScMatValType nType )
    {
        return nType <= SC_MATVAL_BOOLEAN;
    }

    /// Boolean.
    inline static bool IsBooleanType( ScMatValType nType )
    {
        return nType == SC_MATVAL_BOOLEAN;
    }

    /// String, empty or empty path, but not value nor boolean.
    inline static bool IsNonValueType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) != 0;
    }

    /** String, but not empty or empty path or any other type.
        Not named IsStringType to prevent confusion because previously
        IsNonValueType was named IsStringType. */
    inline static bool IsRealStringType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_STRING;
    }

    /// Empty, but not empty path or any other type.
    inline static bool IsEmptyType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTY;
    }

    /// Empty path, but not empty or any other type.
    inline static bool IsEmptyPathType( ScMatValType nType )
    {
        return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTYPATH;
    }

    ScMatrix(SCSIZE nC, SCSIZE nR);
    ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal);

    /** Clone the matrix. */
    ScMatrix* Clone() const;

    /** Clone the matrix if mbCloneIfConst (immutable) is set, otherwise
        return _this_ matrix, to be assigned to a ScMatrixRef. */
    ScMatrix* CloneIfConst();

    /** Set the matrix to (im)mutable for CloneIfConst(), only the interpreter
        should do this and know the consequences. */
    void SetImmutable( bool bVal );

    /**
     * Resize the matrix to specified new dimension.
     */
    void Resize( SCSIZE nC, SCSIZE nR);

    void Resize(SCSIZE nC, SCSIZE nR, double fVal);

    /** Clone the matrix and extend it to the new size. nNewCols and nNewRows
        MUST be at least of the size of the original matrix. */
    ScMatrix* CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const;

    inline void IncRef() const
    {
        ++nRefCnt;
    }
    inline void DecRef() const
    {
        --nRefCnt;
        if (nRefCnt == 0)
            delete this;
    }

    void SetErrorInterpreter( ScInterpreter* p);
    void GetDimensions( SCSIZE& rC, SCSIZE& rR) const;
    SCSIZE GetElementCount() const;
    bool ValidColRow( SCSIZE nC, SCSIZE nR) const;
    SCSIZE CalcOffset( SCSIZE nC, SCSIZE nR) const;

    /** For a row vector or column vector, if the position does not point into
        the vector but is a valid column or row offset it is adapted such that
        it points to an element to be replicated, same column row 0 for a row
        vector, same row column 0 for a column vector. Else, for a 2D matrix,
        returns false.
     */
    bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const;

    /** Checks if the matrix position is within the matrix. If it is not, for a
        row vector or column vector the position is adapted such that it points
        to an element to be replicated, same column row 0 for a row vector,
        same row column 0 for a column vector. Else, for a 2D matrix and
        position not within matrix, returns false.
     */
    bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const;

    void PutDouble( double fVal, SCSIZE nC, SCSIZE nR);
    void PutDouble( double fVal, SCSIZE nIndex);
    void PutString( const ::rtl::OUString& rStr, SCSIZE nC, SCSIZE nR);
    void PutString( const ::rtl::OUString& rStr, SCSIZE nIndex);
    void PutEmpty( SCSIZE nC, SCSIZE nR);
    /// Jump FALSE without path
    void PutEmptyPath( SCSIZE nC, SCSIZE nR);
    void PutError( sal_uInt16 nErrorCode, SCSIZE nC, SCSIZE nR );
    void PutBoolean( bool bVal, SCSIZE nC, SCSIZE nR);

    void FillDouble( double fVal,
            SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );

    /** May be used before obtaining the double value of an element to avoid
        passing its NAN around.
        @ATTENTION: MUST NOT be used if the element is a string!
                    Use GetErrorIfNotString() instead if not sure.
        @returns 0 if no error, else one of err... constants */
    sal_uInt16 GetError( SCSIZE nC, SCSIZE nR) const;

    /** Use in ScInterpreter to obtain the error code, if any.
        @returns 0 if no error or string element, else one of err... constants */
    sal_uInt16 GetErrorIfNotString( SCSIZE nC, SCSIZE nR) const
        { return IsValue( nC, nR) ? GetError( nC, nR) : 0; }

    /// @return 0.0 if empty or empty path, else value or DoubleError.
    double GetDouble( SCSIZE nC, SCSIZE nR) const;
    /// @return 0.0 if empty or empty path, else value or DoubleError.
    double GetDouble( SCSIZE nIndex) const;

    /// @return empty string if empty or empty path, else string content.
    rtl::OUString GetString( SCSIZE nC, SCSIZE nR) const;
    /// @return empty string if empty or empty path, else string content.
    rtl::OUString GetString( SCSIZE nIndex) const;

    /** @returns the matrix element's string if one is present, otherwise the
        numerical value formatted as string, or in case of an error the error
        string is returned; an empty string for empty, a "FALSE" string for
        empty path. */
    ::rtl::OUString GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const;

    /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate
    /// an empty string!
    ScMatrixValue Get( SCSIZE nC, SCSIZE nR) const;

    /// @return <TRUE/> if string or empty or empty path, in fact non-value.
    sal_Bool IsString( SCSIZE nIndex ) const;

    /// @return <TRUE/> if string or empty or empty path, in fact non-value.
    sal_Bool IsString( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if empty or empty path.
    sal_Bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if empty path.
    sal_Bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if value or boolean.
    sal_Bool IsValue( SCSIZE nIndex ) const;

    /// @return <TRUE/> if value or boolean.
    sal_Bool IsValue( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if value or boolean or empty or empty path.
    sal_Bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if boolean.
    sal_Bool IsBoolean( SCSIZE nC, SCSIZE nR ) const;

    /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties
    sal_Bool IsNumeric() const;

    void MatTrans( ScMatrix& mRes) const;
    void MatCopy ( ScMatrix& mRes) const;

    // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values
    void CompareEqual();
    void CompareNotEqual();
    void CompareLess();
    void CompareGreater();
    void CompareLessEqual();
    void CompareGreaterEqual();

    double And() const;       // logical AND of all matrix values, or NAN
    double Or() const;        // logical OR of all matrix values, or NAN

    IterateResult Sum(bool bTextAsZero) const;
    IterateResult SumSquare(bool bTextAsZero) const;
    IterateResult Product(bool bTextAsZero) const;
    size_t Count(bool bCountStrings) const;

    // All other matrix functions  MatMult, MInv, ...  are in ScInterpreter
    // to be numerically safe.
};

inline void intrusive_ptr_add_ref(const ScMatrix* p)
{
    p->IncRef();
}

inline void intrusive_ptr_release(const ScMatrix* p)
{
    p->DecRef();
}

#endif  // SC_MATRIX_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#pragma once

// `krbn::grabber_alerts_monitor` can be used safely in a multi-threaded environment.

#include "constants.hpp"
#include "file_monitor.hpp"
#include "filesystem.hpp"
#include "json_utility.hpp"
#include "logger.hpp"
#include <fstream>

namespace krbn {
class grabber_alerts_monitor final {
public:
  // Signals

  boost::signals2::signal<void(const nlohmann::json& alerts)> alerts_changed;

  // Methods

  grabber_alerts_monitor(const grabber_alerts_monitor&) = delete;

  grabber_alerts_monitor(const std::string& grabber_alerts_json_file_path) {
    std::vector<std::string> targets = {
        grabber_alerts_json_file_path,
    };

    file_monitor_ = std::make_unique<file_monitor>(targets);

    file_monitor_->file_changed.connect([this](auto&& changed_file_path, auto&& file_body) {
      if (file_body) {
        try {
          auto json = nlohmann::json::parse(*file_body);

          // json example
          //
          // {
          //     "alerts": [
          //         "system_policy_prevents_loading_kext"
          //     ]
          // }

          if (auto v = json_utility::find_array(json, "alerts")) {
            auto s = v->dump();
            if (last_json_string_ != s) {
              last_json_string_ = s;
              alerts_changed(*v);
            }
          }
        } catch (std::exception& e) {
          logger::get_logger().error("parse error in {0}: {1}", changed_file_path, e.what());
        }
      }
    });
  }

  void async_start(void) {
    file_monitor_->async_start();
  }

private:
  std::unique_ptr<file_monitor> file_monitor_;
  boost::optional<std::string> last_json_string_;
};
} // namespace krbn
<commit_msg>update for file_changed updates<commit_after>#pragma once

// `krbn::grabber_alerts_monitor` can be used safely in a multi-threaded environment.

#include "constants.hpp"
#include "file_monitor.hpp"
#include "filesystem.hpp"
#include "json_utility.hpp"
#include "logger.hpp"
#include <fstream>

namespace krbn {
class grabber_alerts_monitor final {
public:
  // Signals

  boost::signals2::signal<void(const nlohmann::json& alerts)> alerts_changed;

  // Methods

  grabber_alerts_monitor(const grabber_alerts_monitor&) = delete;

  grabber_alerts_monitor(const std::string& grabber_alerts_json_file_path) {
    std::vector<std::string> targets = {
        grabber_alerts_json_file_path,
    };

    file_monitor_ = std::make_unique<file_monitor>(targets);

    file_monitor_->file_changed.connect([this](auto&& changed_file_path, auto&& weak_changed_file_body) {
      if (auto file_body = weak_changed_file_body.lock()) {
        try {
          auto json = nlohmann::json::parse(*file_body);

          // json example
          //
          // {
          //     "alerts": [
          //         "system_policy_prevents_loading_kext"
          //     ]
          // }

          if (auto v = json_utility::find_array(json, "alerts")) {
            auto s = v->dump();
            if (last_json_string_ != s) {
              last_json_string_ = s;
              alerts_changed(*v);
            }
          }
        } catch (std::exception& e) {
          logger::get_logger().error("parse error in {0}: {1}", changed_file_path, e.what());
        }
      }
    });
  }

  void async_start(void) {
    file_monitor_->async_start();
  }

private:
  std::unique_ptr<file_monitor> file_monitor_;
  boost::optional<std::string> last_json_string_;
};
} // namespace krbn
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS mav09 (1.5.82); FILE MERGED 2004/07/15 10:50:00 mba 1.5.82.1: #i27773#: XMLFilter needs additional parameter<commit_after><|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
** This file is part of the Ovi services plugin for the Maps and
** Navigation API.  The use of these services, whether by use of the
** plugin or by other means, is governed by the terms and conditions
** described by the file OVI_SERVICES_TERMS_AND_CONDITIONS.txt in
** this package, located in the directory containing the Ovi services
** plugin source code.
**
****************************************************************************/

#include "qgeocodingmanagerengine_nokia.h"
#include "qgeocodereply_nokia.h"
#include "marclanguagecodes.h"

#include <qgeoaddress.h>
#include <qgeocoordinate.h>
#include <QNetworkProxy>
#include <QUrl>
#include <QMap>

QT_BEGIN_NAMESPACE

QGeocodingManagerEngineNokia::QGeocodingManagerEngineNokia(const QMap<QString, QVariant> &parameters, QGeoServiceProvider::Error *error, QString *errorString)
        : QGeocodingManagerEngine(parameters),
        m_host("loc.desktop.maps.svc.ovi.com"),
        m_token(QGeoServiceProviderFactoryNokia::defaultToken),
        m_referer(QGeoServiceProviderFactoryNokia::defaultReferer)
{
    m_networkManager = new QNetworkAccessManager(this);

    if (parameters.contains("places.proxy")) {
        QString proxy = parameters.value("places.proxy").toString();
        if (!proxy.isEmpty()) {
            QUrl proxyUrl(proxy);
            if (proxyUrl.isValid()) {
                m_networkManager->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,

                    proxyUrl.host(),
                    proxyUrl.port(8080),
                    proxyUrl.userName(),
                    proxyUrl.password()));
            }
        }
    }

    if (parameters.contains("places.host")) {
        QString host = parameters.value("places.host").toString();
        if (!host.isEmpty())
            m_host = host;
    }

    if (parameters.contains("places.referer")) {
        m_referer = parameters.value("places.referer").toString();
    }

    if (parameters.contains("places.token")) {
        m_token = parameters.value("places.token").toString();
    }
    else if (parameters.contains("token")) {
        m_token = parameters.value("token").toString();
    }

    if (error)
        *error = QGeoServiceProvider::NoError;

    if (errorString)
        *errorString = "";
}

QGeocodingManagerEngineNokia::~QGeocodingManagerEngineNokia() {}

QGeocodeReply* QGeocodingManagerEngineNokia::geocode(const QGeoAddress &address,
        const QGeoBoundingArea &bounds)
{
    QString requestString = "http://";
    requestString += m_host;
    requestString += "/geocoder/gc/2.0?referer=" + m_referer;

    if (!m_token.isNull())
        requestString += "&token=" + m_token;

    requestString += "&lg=";
    requestString += languageToMarc(locale().language());

    requestString += "&country=";
    requestString += address.country();

    if (!address.state().isEmpty()) {
        requestString += "&state=";
        requestString += address.state();
    }

    if (!address.city().isEmpty()) {
        requestString += "&city=";
        requestString += address.city();
    }

    if (!address.postalCode().isEmpty()) {
        requestString += "&zip=";
        requestString += address.postalCode();
    }

    if (!address.street().isEmpty()) {
        requestString += "&street=";
        requestString += address.street();
    }

    // TODO?
    // street number has been removed from QGeoAddress
    // do we need to try to split it out from QGeoAddress::street
    // in order to geocode properly

    // Old code:
//    if (!address.streetNumber().isEmpty()) {
//        requestString += "&number=";
//        requestString += address.streetNumber();
//    }

    return geocode(requestString, bounds);
}

QGeocodeReply* QGeocodingManagerEngineNokia::reverseGeocode(const QGeoCoordinate &coordinate,
        const QGeoBoundingArea &bounds)
{
    QString requestString = "http://";
    requestString += m_host;
    requestString += "/geocoder/rgc/2.0?referer=" + m_referer;
    if (!m_token.isNull())
        requestString += "&token=" + m_token;
    requestString += "&long=";
    requestString += trimDouble(coordinate.longitude());
    requestString += "&lat=";
    requestString += trimDouble(coordinate.latitude());

    requestString += "&lg=";
    requestString += languageToMarc(locale().language());

    return geocode(requestString, bounds);
}

QGeocodeReply* QGeocodingManagerEngineNokia::geocode(const QString &address,
        int limit,
        int offset,
        const QGeoBoundingArea &bounds)
{
    QString requestString = "http://";
    requestString += m_host;
    requestString += "/geocoder/gc/2.0?referer=" + m_referer;

    if (!m_token.isNull())
        requestString += "&token=" + m_token;

    requestString += "&lg=";
    requestString += languageToMarc(locale().language());

    requestString += "&obloc=";
    requestString += address;

    if (limit > 0) {
        requestString += "&total=";
        requestString += QString::number(limit);
    }

    if (offset > 0) {
        requestString += "&offset=";
        requestString += QString::number(offset);
    }

    return geocode(requestString, bounds, limit, offset);
}

QGeocodeReply* QGeocodingManagerEngineNokia::geocode(QString requestString,
        const QGeoBoundingArea &bounds,
        int limit,
        int offset)
{
    QNetworkReply *networkReply = m_networkManager->get(QNetworkRequest(QUrl(requestString)));
    QGeocodeReplyNokia *reply = new QGeocodeReplyNokia(networkReply, limit, offset, bounds, this);

    connect(reply,
            SIGNAL(finished()),
            this,
            SLOT(placesFinished()));

    connect(reply,
            SIGNAL(error(QGeocodeReply::Error, QString)),
            this,
            SLOT(placesError(QGeocodeReply::Error, QString)));

    return reply;
}

QString QGeocodingManagerEngineNokia::trimDouble(double degree, int decimalDigits)
{
    QString sDegree = QString::number(degree, 'g', decimalDigits);

    int index = sDegree.indexOf('.');

    if (index == -1)
        return sDegree;
    else
        return QString::number(degree, 'g', decimalDigits + index);
}

void QGeocodingManagerEngineNokia::placesFinished()
{
    QGeocodeReply *reply = qobject_cast<QGeocodeReply*>(sender());

    if (!reply)
        return;

    if (receivers(SIGNAL(finished(QGeocodeReply*))) == 0) {
        reply->deleteLater();
        return;
    }

    emit finished(reply);
}

void QGeocodingManagerEngineNokia::placesError(QGeocodeReply::Error error, const QString &errorString)
{
    QGeocodeReply *reply = qobject_cast<QGeocodeReply*>(sender());

    if (!reply)
        return;

    if (receivers(SIGNAL(error(QGeocodeReply*, QGeocodeReply::Error, QString))) == 0) {
        reply->deleteLater();
        return;
    }

    emit this->error(reply, error, errorString);
}

QString QGeocodingManagerEngineNokia::languageToMarc(QLocale::Language language)
{
    uint offset = 3 * (uint(language));
    if (language == QLocale::C || offset + 3 > sizeof(marc_language_code_list))
        return QLatin1String("eng");

    const unsigned char *c = marc_language_code_list + offset;
    if (c[0] == 0)
        return QLatin1String("eng");

    QString code(3, Qt::Uninitialized);
    code[0] = ushort(c[0]);
    code[1] = ushort(c[1]);
    code[2] = ushort(c[2]);

    return code;
}

QT_END_NAMESPACE
<commit_msg>Unexpected Error status of GeocodeModel<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
** This file is part of the Ovi services plugin for the Maps and
** Navigation API.  The use of these services, whether by use of the
** plugin or by other means, is governed by the terms and conditions
** described by the file OVI_SERVICES_TERMS_AND_CONDITIONS.txt in
** this package, located in the directory containing the Ovi services
** plugin source code.
**
****************************************************************************/

#include "qgeocodingmanagerengine_nokia.h"
#include "qgeocodereply_nokia.h"
#include "marclanguagecodes.h"

#include <qgeoaddress.h>
#include <qgeocoordinate.h>
#include <QNetworkProxy>
#include <QUrl>
#include <QMap>
#include <QStringList>

QT_BEGIN_NAMESPACE

QGeocodingManagerEngineNokia::QGeocodingManagerEngineNokia(const QMap<QString, QVariant> &parameters, QGeoServiceProvider::Error *error, QString *errorString)
        : QGeocodingManagerEngine(parameters),
        m_host("loc.desktop.maps.svc.ovi.com"),
        m_token(QGeoServiceProviderFactoryNokia::defaultToken),
        m_referer(QGeoServiceProviderFactoryNokia::defaultReferer)
{
    m_networkManager = new QNetworkAccessManager(this);

    if (parameters.contains("places.proxy")) {
        QString proxy = parameters.value("places.proxy").toString();
        if (!proxy.isEmpty()) {
            QUrl proxyUrl(proxy);
            if (proxyUrl.isValid()) {
                m_networkManager->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,

                    proxyUrl.host(),
                    proxyUrl.port(8080),
                    proxyUrl.userName(),
                    proxyUrl.password()));
            }
        }
    }

    if (parameters.contains("places.host")) {
        QString host = parameters.value("places.host").toString();
        if (!host.isEmpty())
            m_host = host;
    }

    if (parameters.contains("places.referer")) {
        m_referer = parameters.value("places.referer").toString();
    }

    if (parameters.contains("places.token")) {
        m_token = parameters.value("places.token").toString();
    }
    else if (parameters.contains("token")) {
        m_token = parameters.value("token").toString();
    }

    if (error)
        *error = QGeoServiceProvider::NoError;

    if (errorString)
        *errorString = "";
}

QGeocodingManagerEngineNokia::~QGeocodingManagerEngineNokia() {}

QGeocodeReply* QGeocodingManagerEngineNokia::geocode(const QGeoAddress &address,
        const QGeoBoundingArea &bounds)
{
    QString requestString = "http://";
    requestString += m_host;
    requestString += "/geocoder/gc/2.0?referer=" + m_referer;

    if (!m_token.isNull())
        requestString += "&token=" + m_token;

    requestString += "&lg=";
    requestString += languageToMarc(locale().language());

    if (address.country().isEmpty()) {
        QStringList parts;

        if (!address.state().isEmpty())
            parts << address.state();

        if (!address.city().isEmpty())
            parts << address.city();

        if (!address.postalCode().isEmpty())
            parts << address.postalCode();

        if (!address.street().isEmpty())
            parts << address.street();

        requestString += "&obloc=";
        requestString += parts.join(" ");
    } else {
        requestString += "&country=";
        requestString += address.country();

        if (!address.state().isEmpty()) {
            requestString += "&state=";
            requestString += address.state();
        }

        if (!address.city().isEmpty()) {
            requestString += "&city=";
            requestString += address.city();
        }

        if (!address.postalCode().isEmpty()) {
            requestString += "&zip=";
            requestString += address.postalCode();
        }

        if (!address.street().isEmpty()) {
            requestString += "&street=";
            requestString += address.street();
        }
    }

    // TODO?
    // street number has been removed from QGeoAddress
    // do we need to try to split it out from QGeoAddress::street
    // in order to geocode properly

    // Old code:
//    if (!address.streetNumber().isEmpty()) {
//        requestString += "&number=";
//        requestString += address.streetNumber();
//    }

    return geocode(requestString, bounds);
}

QGeocodeReply* QGeocodingManagerEngineNokia::reverseGeocode(const QGeoCoordinate &coordinate,
        const QGeoBoundingArea &bounds)
{
    QString requestString = "http://";
    requestString += m_host;
    requestString += "/geocoder/rgc/2.0?referer=" + m_referer;
    if (!m_token.isNull())
        requestString += "&token=" + m_token;
    requestString += "&long=";
    requestString += trimDouble(coordinate.longitude());
    requestString += "&lat=";
    requestString += trimDouble(coordinate.latitude());

    requestString += "&lg=";
    requestString += languageToMarc(locale().language());

    return geocode(requestString, bounds);
}

QGeocodeReply* QGeocodingManagerEngineNokia::geocode(const QString &address,
        int limit,
        int offset,
        const QGeoBoundingArea &bounds)
{
    QString requestString = "http://";
    requestString += m_host;
    requestString += "/geocoder/gc/2.0?referer=" + m_referer;

    if (!m_token.isNull())
        requestString += "&token=" + m_token;

    requestString += "&lg=";
    requestString += languageToMarc(locale().language());

    requestString += "&obloc=";
    requestString += address;

    if (limit > 0) {
        requestString += "&total=";
        requestString += QString::number(limit);
    }

    if (offset > 0) {
        requestString += "&offset=";
        requestString += QString::number(offset);
    }

    return geocode(requestString, bounds, limit, offset);
}

QGeocodeReply* QGeocodingManagerEngineNokia::geocode(QString requestString,
        const QGeoBoundingArea &bounds,
        int limit,
        int offset)
{
    QNetworkReply *networkReply = m_networkManager->get(QNetworkRequest(QUrl(requestString)));
    QGeocodeReplyNokia *reply = new QGeocodeReplyNokia(networkReply, limit, offset, bounds, this);

    connect(reply,
            SIGNAL(finished()),
            this,
            SLOT(placesFinished()));

    connect(reply,
            SIGNAL(error(QGeocodeReply::Error, QString)),
            this,
            SLOT(placesError(QGeocodeReply::Error, QString)));

    return reply;
}

QString QGeocodingManagerEngineNokia::trimDouble(double degree, int decimalDigits)
{
    QString sDegree = QString::number(degree, 'g', decimalDigits);

    int index = sDegree.indexOf('.');

    if (index == -1)
        return sDegree;
    else
        return QString::number(degree, 'g', decimalDigits + index);
}

void QGeocodingManagerEngineNokia::placesFinished()
{
    QGeocodeReply *reply = qobject_cast<QGeocodeReply*>(sender());

    if (!reply)
        return;

    if (receivers(SIGNAL(finished(QGeocodeReply*))) == 0) {
        reply->deleteLater();
        return;
    }

    emit finished(reply);
}

void QGeocodingManagerEngineNokia::placesError(QGeocodeReply::Error error, const QString &errorString)
{
    QGeocodeReply *reply = qobject_cast<QGeocodeReply*>(sender());

    if (!reply)
        return;

    if (receivers(SIGNAL(error(QGeocodeReply*, QGeocodeReply::Error, QString))) == 0) {
        reply->deleteLater();
        return;
    }

    emit this->error(reply, error, errorString);
}

QString QGeocodingManagerEngineNokia::languageToMarc(QLocale::Language language)
{
    uint offset = 3 * (uint(language));
    if (language == QLocale::C || offset + 3 > sizeof(marc_language_code_list))
        return QLatin1String("eng");

    const unsigned char *c = marc_language_code_list + offset;
    if (c[0] == 0)
        return QLatin1String("eng");

    QString code(3, Qt::Uninitialized);
    code[0] = ushort(c[0]);
    code[1] = ushort(c[1]);
    code[2] = ushort(c[2]);

    return code;
}

QT_END_NAMESPACE
<|endoftext|>