<commit_before>/*################################################################################
  ##
  ##   Copyright (C) 2016-2017 Keith O'Hara
  ##
  ##   This file is part of the OptimLib C++ library.
  ##
  ##   OptimLib is free software: you can redistribute it and/or modify
  ##   it under the terms of the GNU General Public License as published by
  ##   the Free Software Foundation, either version 2 of the License, or
  ##   (at your option) any later version.
  ##
  ##   OptimLib 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.
  ##
  ################################################################################*/

/*
 * Differential Evolution (DE) optimization
 *
 * Keith O'Hara
 * 12/19/2016
 *
 * This version:
 * 07/19/2017
 */

#include "optim.hpp"

bool
optim::de_int(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, double* value_out, optim_opt_settings* opt_params)
{
    bool success = false;

    const double BIG_POS_VAL = OPTIM_BIG_POS_NUM;

    const int conv_failure_switch = (opt_params) ? opt_params->conv_failure_switch : OPTIM_CONV_FAILURE_POLICY;
    const double err_tol = (opt_params) ? opt_params->err_tol : OPTIM_DEFAULT_ERR_TOL;

    const int n_gen = (opt_params) ? opt_params->de_n_gen : OPTIM_DEFAULT_DE_NGEN;
    const int check_freq = (opt_params) ? opt_params->de_check_freq : 20;
    const double par_F  = (opt_params) ? opt_params->de_par_F  : OPTIM_DEFAULT_DE_PAR_F; // tuning parameters
    const double par_CR = (opt_params) ? opt_params->de_par_CR : OPTIM_DEFAULT_DE_PAR_CR;
    //
    const int n_vals = init_out_vals.n_elem;
    const int N = n_vals*10;

    int c_1, c_2, c_3, j, k;
    //
    double prop_objfn_val = 0.0;
    arma::vec X_prop = init_out_vals, past_objfn_vals(N), rand_unif(n_vals);
    arma::mat X(N,n_vals);

    for (int i=0; i < N; i++) {
        X.row(i) = init_out_vals.t() + arma::randu(1,n_vals) - 0.5; // initial values + U[-0.5,0.5]

        prop_objfn_val = opt_objfn(X.row(i).t(),nullptr,opt_data);

        if (std::isnan(prop_objfn_val)) {
            prop_objfn_val = BIG_POS_VAL;
        }

        past_objfn_vals(i) = prop_objfn_val;
    }

    double best_objfn_val = past_objfn_vals.min();
    //
    int iter = 0;
    double err = 2*err_tol;

    while (err > err_tol && iter < n_gen) {
        iter++;
        //
        for (int i=0; i < N; i++) {
            do { // 'r_1' in paper's notation
                c_1 = arma::as_scalar(arma::randi(1, arma::distr_param(0, N-1)));
            } while(c_1==i);

            do { // 'r_2' in paper's notation
                c_2 = arma::as_scalar(arma::randi(1, arma::distr_param(0, N-1)));
            } while(c_2==i || c_2==c_1);

            do { // 'r_3' in paper's notation
                c_3 = arma::as_scalar(arma::randi(1, arma::distr_param(0, N-1)));
            } while(c_3==i || c_3==c_1 || c_3==c_2);

            //

            j = arma::as_scalar(arma::randi(1, arma::distr_param(0, n_vals-1)));

            rand_unif = arma::randu(n_vals);
            k = 0;
            do {
                X_prop(j) = X(c_3,j) + par_F*(X(c_1,j) - X(c_2,j));

                j = (j+1)%n_vals;
                k++;
            } while((k < n_vals) && (rand_unif(k) < par_CR));

            //

            prop_objfn_val = opt_objfn(X_prop,nullptr,opt_data);

            if (prop_objfn_val <= past_objfn_vals(i)) {
                X.row(i) = X_prop.t();
                past_objfn_vals(i) = prop_objfn_val;
            } else {
                X_prop = X.row(i).t();
            }
        }
        //
        if (iter%check_freq == 0) {
            err = std::abs(past_objfn_vals.min() - best_objfn_val);
            best_objfn_val = past_objfn_vals.min();
        }
    }
    //
    arma::uword min_i = past_objfn_vals.index_min();
    X_prop = X.row(min_i).t();

    error_reporting(init_out_vals,X_prop,opt_objfn,opt_data,success,value_out,err,err_tol,iter,n_gen,conv_failure_switch);
    //
    return success;
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data)
{
    return de_int(init_out_vals,opt_objfn,opt_data,nullptr,nullptr);
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, optim_opt_settings& opt_params)
{
    return de_int(init_out_vals,opt_objfn,opt_data,nullptr,&opt_params);
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, double& value_out)
{
    return de_int(init_out_vals,opt_objfn,opt_data,&value_out,nullptr);
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, double& value_out, optim_opt_settings& opt_params)
{
    return de_int(init_out_vals,opt_objfn,opt_data,&value_out,&opt_params);
}
<commit_msg>update DE<commit_after>/*################################################################################
  ##
  ##   Copyright (C) 2016-2017 Keith O'Hara
  ##
  ##   This file is part of the OptimLib C++ library.
  ##
  ##   OptimLib is free software: you can redistribute it and/or modify
  ##   it under the terms of the GNU General Public License as published by
  ##   the Free Software Foundation, either version 2 of the License, or
  ##   (at your option) any later version.
  ##
  ##   OptimLib 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.
  ##
  ################################################################################*/

/*
 * Differential Evolution (DE) optimization
 *
 * Keith O'Hara
 * 12/19/2016
 *
 * This version:
 * 07/19/2017
 */

#include "optim.hpp"

bool
optim::de_int(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, double* value_out, optim_opt_settings* opt_params)
{
    bool success = false;

    const double BIG_POS_VAL = OPTIM_BIG_POS_NUM;

    const int conv_failure_switch = (opt_params) ? opt_params->conv_failure_switch : OPTIM_CONV_FAILURE_POLICY;
    const double err_tol = (opt_params) ? opt_params->err_tol : OPTIM_DEFAULT_ERR_TOL;

    const int n_gen = (opt_params) ? opt_params->de_n_gen : OPTIM_DEFAULT_DE_NGEN;
    const int check_freq = (opt_params) ? opt_params->de_check_freq : 20;
    const double par_F  = (opt_params) ? opt_params->de_par_F  : OPTIM_DEFAULT_DE_PAR_F; // tuning parameters
    const double par_CR = (opt_params) ? opt_params->de_par_CR : OPTIM_DEFAULT_DE_PAR_CR;
    //
    const int n_vals = init_out_vals.n_elem;
    const int N = n_vals*10;

    int c_1, c_2, c_3, j, k;
    //
    double prop_objfn_val = 0.0;
    arma::vec X_prop = init_out_vals, past_objfn_vals(N), rand_unif(n_vals);
    arma::mat X(N,n_vals), X_next(N,n_vals);

    for (int i=0; i < N; i++) {
        X_next.row(i) = init_out_vals.t() + arma::randu(1,n_vals) - 0.5; // initial values + U[-0.5,0.5]

        prop_objfn_val = opt_objfn(X_next.row(i).t(),nullptr,opt_data);

        if (std::isnan(prop_objfn_val)) {
            prop_objfn_val = BIG_POS_VAL;
        }

        past_objfn_vals(i) = prop_objfn_val;
    }

    double best_objfn_val = past_objfn_vals.min();
    //
    int iter = 0;
    double err = 2*err_tol;

    while (err > err_tol && iter < n_gen) {
        iter++;
        //
        X = X_next;

        for (int i=0; i < N; i++) {
            do { // 'r_2' in paper's notation
                c_1 = arma::as_scalar(arma::randi(1, arma::distr_param(0, N-1)));
            } while(c_1==i);

            do { // 'r_3' in paper's notation
                c_2 = arma::as_scalar(arma::randi(1, arma::distr_param(0, N-1)));
            } while(c_2==i || c_2==c_1);

            do { // 'r_1' in paper's notation
                c_3 = arma::as_scalar(arma::randi(1, arma::distr_param(0, N-1)));
            } while(c_3==i || c_3==c_1 || c_3==c_2);

            //

            j = arma::as_scalar(arma::randi(1, arma::distr_param(0, n_vals-1)));

            rand_unif = arma::randu(n_vals);
            k = 0;
            do {
                X_prop(j) = X(c_3,j) + par_F*(X(c_1,j) - X(c_2,j));

                j = (j+1)%n_vals;
                k++;
            } while((k < n_vals) && (rand_unif(k) < par_CR));

            //

            prop_objfn_val = opt_objfn(X_prop,nullptr,opt_data);

            if (prop_objfn_val <= past_objfn_vals(i)) {
                X_next.row(i) = X_prop.t();
                past_objfn_vals(i) = prop_objfn_val;
            } else {
                X_prop = X.row(i).t();
            }
        }
        //
        if (iter%check_freq == 0) {
            err = std::abs(past_objfn_vals.min() - best_objfn_val) / (std::abs(best_objfn_val) + 1E-08);
            best_objfn_val = past_objfn_vals.min();
        }
    }
    //
    arma::uword min_i = past_objfn_vals.index_min();
    X_prop = X_next.row(min_i).t();

    error_reporting(init_out_vals,X_prop,opt_objfn,opt_data,success,value_out,err,err_tol,iter,n_gen,conv_failure_switch);
    //
    return success;
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data)
{
    return de_int(init_out_vals,opt_objfn,opt_data,nullptr,nullptr);
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, optim_opt_settings& opt_params)
{
    return de_int(init_out_vals,opt_objfn,opt_data,nullptr,&opt_params);
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, double& value_out)
{
    return de_int(init_out_vals,opt_objfn,opt_data,&value_out,nullptr);
}

bool
optim::de(arma::vec& init_out_vals, std::function<double (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)> opt_objfn, void* opt_data, double& value_out, optim_opt_settings& opt_params)
{
    return de_int(init_out_vals,opt_objfn,opt_data,&value_out,&opt_params);
}
<|endoftext|>


<commit_before>/*
Copyright 2016 Colin Girling

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef OCL_GUARD_TEST_TESTSTRING_HPP
#define OCL_GUARD_TEST_TESTSTRING_HPP

#include "TestMemoryUtility.hpp"
#include "TestStringUtility.hpp"
#include <cstddef>
#include <cstdlib>
#include <cstring>

namespace ocl
{

/*
 * String class for test harness, with an interface complete enough for general usage.
 */

class TestString
{
public:
    typedef TestStringUtility::size_type size_type;

    /// size_type has the potential of being signed or unsigned,
    /// so ensure signed/unsigned mismatch compiler warnings are suppressed.
    static size_type const size_type_default = static_cast<size_type>(0);

public:
    TestString(char const* str = NULL)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        if (str != NULL)
            TestStringUtility::UnsafeAllocateCopy(m_string, m_length, str);
    }

    TestString(char ch, size_type len)
        : m_length(len)
        , m_string(NULL)
    {
        if (len > size_type_default)
        {
            TestStringUtility::Allocate(m_string, len);
            if (m_string != NULL)
                TestStringUtility::UnsafeFill(m_string, ch, len);
            else
                m_length = size_type_default;
        }
    }

    TestString(TestString const& str)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        TestStringUtility::SafeAllocateCopy(m_string, m_length, str.m_string, str.m_length);
    }

    ~TestString()
    {
        TestStringUtility::FastFree(m_string);
    }

    TestString& operator =(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
            TestStringUtility::SafeReallocCopy(m_string, m_length, str);
        else
            Clear();
        return *this;
    }

    TestString& operator =(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocCopy(m_string,
                                               m_length,
                                               str.m_string,
                                               str.m_length);
        }
        else
            Clear();

        return *this;
    }

    TestString& operator +=(char const* str)
    {
        Append(str);
        return *this;
    }

    TestString& operator +=(TestString const& str)
    {
        Append(str);
        return *this;
    }

    char operator [](size_type index) const
    {
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : '\0';
    }

    char& operator [](size_type index)
    {
        static char spare = '\0';
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : spare;
    }

    operator char const*() const throw()
    {
        return Ptr();
    }

    bool operator ==(char const* str) const
    {
        if (m_string == NULL)
            return (str == NULL) || (*str == '\0');
        return ::strcmp(m_string, str) == 0;
    }

    bool operator ==(TestString const& str) const
    {
        if (m_string == NULL)
            return str.m_string == NULL;
        return ::strcmp(m_string, str.Ptr()) == 0;
    }

public:
    char const* Ptr() const throw()
    {
        return m_string != NULL ? m_string : "";
    }

    size_type GetLength() const throw()
    {
        return m_length;
    }

    bool IsEmpty() const throw()
    {
        return m_string == NULL;
    }

    void Clear()
    {
        TestStringUtility::FastFree(m_string);
        m_string = NULL;
        m_length = size_type_default;
    }

    bool Find(char ch, size_type& pos, size_type start = size_type_default) const
    {
        if (m_string != NULL)
            return TestStringUtility::UnsafeFind(m_string, ch, pos, start);
        return false;
    }

    /// Extract a partial string, and optionally remove the partial string
    /// from this string.
    /// If count is 0 then get the sub string from start to the end.
    void GetSubString(TestString& sub_str,
                      size_type start,
                      size_type count,
                      bool remove = false)
    {
        sub_str.Clear();
        if (start + count <= m_length)
        {
            if (count == 0)
                count = m_length - start;

            TestStringUtility::SafeReallocCopy(sub_str.m_string,
                                               sub_str.m_length,
                                               m_string + start,
                                               count);
            if (remove)
            {
                size_type chars_remaining = m_length - sub_str.m_length - start;
                ::memmove(m_string + start, m_string + start + count, chars_remaining);
                *(m_string + start + chars_remaining) = '\0';
                m_length -= count;
                if (m_length == 0)
                    TestStringUtility::SafeFree(m_string);
            }
        }
    }

    /// Replace the current sting with str.
    void Assign(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
            TestStringUtility::SafeReallocCopy(m_string, m_length, str);
        else
            Clear();
    }

    /// Replace the current sting with str.
    void Assign(TestString const& str)
    {
        TestStringUtility::SafeReallocCopy(m_string, m_length, str.m_string);
    }

    /// Move str into this string.
    void Move(char*& str, size_type len)
    {
        TestStringUtility::FastFree(m_string);
        m_string = str;
        m_length = len;
        str = NULL;
    }

    void Prepend(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str),
                                                 m_string,
                                                 m_length);
        }
    }

    void Append(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str));
        }
    }

    void Append(char const* str, size_type count)
    {
        if ((str != NULL) && (*str != '\0') &&
            (count > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 count);
        }
    }

    void Append(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str.m_string,
                                                 str.m_length);
        }
    }

    /// Append a boolean converted to a "true" ot "false" string.
    void Append(bool value)
    {
        char const* str = value ? "true" : "false";
        Append(str);
    }

    /// Append a single character.
    void Append(char value)
    {
        char str[2];
        str[0] = value;
        str[1] = '\0';
        Append(str);
    }

    /// Append number of characters.
    void Append(char value, size_type count)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = value;
                Append(start, count);
                TestStringUtility::FastFree(start);
            }
            else
                Append(value);
        }
    }

    /// Append number of characters then a string value.
    void Append(char ch, size_type count, char const* value, size_type len)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count + len);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = ch;
                ::memcpy(str, value, len + 1);
                Append(start, count + len);
                TestStringUtility::FastFree(start);
            }
            else
                Append(ch);
        }
        else
            Append(value, len);
    }

    void Append(signed char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

private:
    template<typename T>
    void privateAppendValue(T value, size_type pad)
    {
        size_type length = size_type_default;
        char* str = TestStringUtility::GetString(value, length);
        if (str != NULL)
        {
            if (IsEmpty() && (pad == size_type_default))
                Move(str, length);
            else
            {
                if (pad > length)
                    Append('0', pad - length, str, length);
                else
                    Append(str, length);
                TestStringUtility::FastFree(str);
            }
        }
    }

    size_type privateSafeLength(char const* str)
    {
        return TestStringUtility::SafeLength(str);
    }

private:
    size_type m_length;
    char* m_string;
};

} // namespace ocl

#endif // OCL_GUARD_TEST_TESTSTRING_HPP
<commit_msg>Added ability to move TestString object into another TestString object.<commit_after>/*
Copyright 2016 Colin Girling

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef OCL_GUARD_TEST_TESTSTRING_HPP
#define OCL_GUARD_TEST_TESTSTRING_HPP

#include "TestMemoryUtility.hpp"
#include "TestStringUtility.hpp"
#include <cstddef>
#include <cstdlib>
#include <cstring>

namespace ocl
{

/*
 * String class for test harness, with an interface complete enough for general usage.
 */

class TestString
{
public:
    typedef TestStringUtility::size_type size_type;

    /// size_type has the potential of being signed or unsigned,
    /// so ensure signed/unsigned mismatch compiler warnings are suppressed.
    static size_type const size_type_default = static_cast<size_type>(0);

public:
    TestString(char const* str = NULL)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        if (str != NULL)
            TestStringUtility::UnsafeAllocateCopy(m_string, m_length, str);
    }

    TestString(char ch, size_type len)
        : m_length(len)
        , m_string(NULL)
    {
        if (len > size_type_default)
        {
            TestStringUtility::Allocate(m_string, len);
            if (m_string != NULL)
                TestStringUtility::UnsafeFill(m_string, ch, len);
            else
                m_length = size_type_default;
        }
    }

    TestString(TestString const& str)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        TestStringUtility::SafeAllocateCopy(m_string, m_length, str.m_string, str.m_length);
    }

    ~TestString()
    {
        TestStringUtility::FastFree(m_string);
    }

    TestString& operator =(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
            TestStringUtility::SafeReallocCopy(m_string, m_length, str);
        else
            Clear();
        return *this;
    }

    TestString& operator =(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocCopy(m_string,
                                               m_length,
                                               str.m_string,
                                               str.m_length);
        }
        else
            Clear();

        return *this;
    }

    TestString& operator +=(char const* str)
    {
        Append(str);
        return *this;
    }

    TestString& operator +=(TestString const& str)
    {
        Append(str);
        return *this;
    }

    char operator [](size_type index) const
    {
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : '\0';
    }

    char& operator [](size_type index)
    {
        static char spare = '\0';
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : spare;
    }

    operator char const*() const throw()
    {
        return Ptr();
    }

    bool operator ==(char const* str) const
    {
        if (m_string == NULL)
            return (str == NULL) || (*str == '\0');
        return ::strcmp(m_string, str) == 0;
    }

    bool operator ==(TestString const& str) const
    {
        if (m_string == NULL)
            return str.m_string == NULL;
        return ::strcmp(m_string, str.Ptr()) == 0;
    }

public:
    char const* Ptr() const throw()
    {
        return m_string != NULL ? m_string : "";
    }

    size_type GetLength() const throw()
    {
        return m_length;
    }

    bool IsEmpty() const throw()
    {
        return m_string == NULL;
    }

    void Clear()
    {
        TestStringUtility::FastFree(m_string);
        m_string = NULL;
        m_length = size_type_default;
    }

    bool Find(char ch, size_type& pos, size_type start = size_type_default) const
    {
        if (m_string != NULL)
            return TestStringUtility::UnsafeFind(m_string, ch, pos, start);
        return false;
    }

    /// Extract a partial string, and optionally remove the partial string
    /// from this string.
    /// If count is 0 then get the sub string from start to the end.
    void GetSubString(TestString& sub_str,
                      size_type start,
                      size_type count,
                      bool remove = false)
    {
        sub_str.Clear();
        if (start + count <= m_length)
        {
            if (count == 0)
                count = m_length - start;

            TestStringUtility::SafeReallocCopy(sub_str.m_string,
                                               sub_str.m_length,
                                               m_string + start,
                                               count);
            if (remove)
            {
                size_type chars_remaining = m_length - sub_str.m_length - start;
                ::memmove(m_string + start, m_string + start + count, chars_remaining);
                *(m_string + start + chars_remaining) = '\0';
                m_length -= count;
                if (m_length == 0)
                    TestStringUtility::SafeFree(m_string);
            }
        }
    }

    /// Replace the current sting with str.
    void Assign(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
            TestStringUtility::SafeReallocCopy(m_string, m_length, str);
        else
            Clear();
    }

    /// Replace the current sting with str.
    void Assign(TestString const& str)
    {
        TestStringUtility::SafeReallocCopy(m_string, m_length, str.m_string);
    }

    /// Move str into this string.
    void Move(char*& str, size_type len)
    {
        TestStringUtility::FastFree(m_string);
        m_string = str;
        m_length = len;
        str = NULL;
    }

    void Move(TestString& str)
    {
        TestStringUtility::FastFree(m_string);
        m_string = str.m_string;
        m_length = str.m_length;
        str.m_string = NULL;
        str.m_length = 0U;
    }

    void Prepend(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str),
                                                 m_string,
                                                 m_length);
        }
    }

    void Append(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str));
        }
    }

    void Append(char const* str, size_type count)
    {
        if ((str != NULL) && (*str != '\0') &&
            (count > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 count);
        }
    }

    void Append(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str.m_string,
                                                 str.m_length);
        }
    }

    /// Append a boolean converted to a "true" ot "false" string.
    void Append(bool value)
    {
        char const* str = value ? "true" : "false";
        Append(str);
    }

    /// Append a single character.
    void Append(char value)
    {
        char str[2];
        str[0] = value;
        str[1] = '\0';
        Append(str);
    }

    /// Append number of characters.
    void Append(char value, size_type count)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = value;
                Append(start, count);
                TestStringUtility::FastFree(start);
            }
            else
                Append(value);
        }
    }

    /// Append number of characters then a string value.
    void Append(char ch, size_type count, char const* value, size_type len)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count + len);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = ch;
                ::memcpy(str, value, len + 1);
                Append(start, count + len);
                TestStringUtility::FastFree(start);
            }
            else
                Append(ch);
        }
        else
            Append(value, len);
    }

    void Append(signed char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

private:
    template<typename T>
    void privateAppendValue(T value, size_type pad)
    {
        size_type length = size_type_default;
        char* str = TestStringUtility::GetString(value, length);
        if (str != NULL)
        {
            if (IsEmpty() && (pad == size_type_default))
                Move(str, length);
            else
            {
                if (pad > length)
                    Append('0', pad - length, str, length);
                else
                    Append(str, length);
                TestStringUtility::FastFree(str);
            }
        }
    }

    size_type privateSafeLength(char const* str)
    {
        return TestStringUtility::SafeLength(str);
    }

private:
    size_type m_length;
    char* m_string;
};

} // namespace ocl

#endif // OCL_GUARD_TEST_TESTSTRING_HPP
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2007 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "ShotPath.h"

/* system headers */
#include <assert.h>

/* local implementation headers */
#include "SegmentedShotStrategy.h"
#include "GuidedMissleStrategy.h"
#include "ShockWaveStrategy.h"

//
// ShotPath
//

ShotPath::ShotPath(const FiringInfo& info) :
				firingInfo(info),
				reloadTime(BZDB.eval(StateDatabase::BZDB_RELOADTIME)),
				startTime(TimeKeeper::getTick()),
				currentTime(TimeKeeper::getTick()),
				expiring(false),
				expired(false)
{
  // eek!  a giant switch statement, how un-object-oriented!
  // each flag should be a flyweight object derived from a
  // base Flag class with a virtual makeShotStrategy() member.
  // just remember -- it's only a game.
  if (firingInfo.flagType->flagShot == NormalShot)
    strategy = new NormalShotStrategy(this);
  else {
    if (firingInfo.flagType == Flags::RapidFire)
      strategy = new RapidFireStrategy(this);
    else if (firingInfo.flagType == Flags::MachineGun)
      strategy = new MachineGunStrategy(this);
    else if (firingInfo.flagType == Flags::GuidedMissile)
      strategy = new GuidedMissileStrategy(this);
    else if (firingInfo.flagType == Flags::Laser)
      strategy = new LaserStrategy(this);
    else if (firingInfo.flagType == Flags::Ricochet)
      strategy = new RicochetStrategy(this);
    else if (firingInfo.flagType == Flags::SuperBullet)
      strategy = new SuperBulletStrategy(this);
    else if (firingInfo.flagType == Flags::ShockWave)
      strategy = new ShockWaveStrategy(this);
    else if (firingInfo.flagType == Flags::Thief)
      strategy = new ThiefStrategy(this);
    else if (firingInfo.flagType == Flags::PhantomZone)
      strategy = new PhantomBulletStrategy(this);
    else
      assert(0);    // shouldn't happen
  }
}

ShotPath::~ShotPath()
{
  delete strategy;
}

float			ShotPath::checkHit(const BaseLocalPlayer* player,
							float position[3]) const
{
  return strategy->checkHit(player, position);
}

bool			ShotPath::isStoppedByHit() const
{
  return strategy->isStoppedByHit();
}

void			ShotPath::addShot(SceneDatabase* scene,
						bool colorblind)
{
  strategy->addShot(scene, colorblind);
}

void			ShotPath::radarRender() const
{
  if (!isExpired()) strategy->radarRender();
}

void			ShotPath::updateShot(float dt)
{
  // get new time step and set current time
  currentTime += dt;

  // update shot
  if (!expired) {
    if (expiring) setExpired();
    else getStrategy()->update(dt);
  }
}

void			ShotPath::setReloadTime(float _reloadTime)
{
  reloadTime = _reloadTime;
}

void			ShotPath::setPosition(const float* p)
{
  firingInfo.shot.pos[0] = p[0];
  firingInfo.shot.pos[1] = p[1];
  firingInfo.shot.pos[2] = p[2];
}

void			ShotPath::setVelocity(const float* v)
{
  firingInfo.shot.vel[0] = v[0];
  firingInfo.shot.vel[1] = v[1];
  firingInfo.shot.vel[2] = v[2];
}

void			ShotPath::setExpiring()
{
  expiring = true;
}

void			ShotPath::setExpired()
{
  expiring = true;
  expired = true;
  getStrategy()->expire();
}

void			ShotPath::boostReloadTime(float dt)
{
  reloadTime += dt;
}

//
// LocalShotPath
//

LocalShotPath::LocalShotPath(const FiringInfo& info) :
				ShotPath(info)
{
  // do nothing
}

LocalShotPath::~LocalShotPath()
{
  // do nothing
}

void			LocalShotPath::update(float dt)
{
  getFiringInfo().shot.dt += dt;
  updateShot(dt);

  // send updates if necessary
  getStrategy()->sendUpdate(getFiringInfo());
}

//
// RemoteShotPath
//

RemoteShotPath::RemoteShotPath(const FiringInfo& info) :
				ShotPath(info)
{
  // do nothing
}

RemoteShotPath::~RemoteShotPath()
{
  // do nothing
}

void			RemoteShotPath::update(float dt)
{
  // update shot
  updateShot(dt);
}

void			RemoteShotPath::update(const ShotUpdate& shot,
				uint16_t code, void* msg)
{
  // update shot info
  getFiringInfo().shot = shot;

  // let the strategy see the message
  getStrategy()->readUpdate(code, msg);
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>remove the mostly-no-longer-relevant comment.. giant switch was switched to something else.  should still remember it's only a game, but lets take that out too since it'd be out of place.<commit_after>/* bzflag
 * Copyright (c) 1993 - 2007 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "ShotPath.h"

/* system headers */
#include <assert.h>

/* local implementation headers */
#include "SegmentedShotStrategy.h"
#include "GuidedMissleStrategy.h"
#include "ShockWaveStrategy.h"

//
// ShotPath
//

ShotPath::ShotPath(const FiringInfo& info) :
				firingInfo(info),
				reloadTime(BZDB.eval(StateDatabase::BZDB_RELOADTIME)),
				startTime(TimeKeeper::getTick()),
				currentTime(TimeKeeper::getTick()),
				expiring(false),
				expired(false)
{
  if (firingInfo.flagType->flagShot == NormalShot)
    strategy = new NormalShotStrategy(this);
  else {
    if (firingInfo.flagType == Flags::RapidFire)
      strategy = new RapidFireStrategy(this);
    else if (firingInfo.flagType == Flags::MachineGun)
      strategy = new MachineGunStrategy(this);
    else if (firingInfo.flagType == Flags::GuidedMissile)
      strategy = new GuidedMissileStrategy(this);
    else if (firingInfo.flagType == Flags::Laser)
      strategy = new LaserStrategy(this);
    else if (firingInfo.flagType == Flags::Ricochet)
      strategy = new RicochetStrategy(this);
    else if (firingInfo.flagType == Flags::SuperBullet)
      strategy = new SuperBulletStrategy(this);
    else if (firingInfo.flagType == Flags::ShockWave)
      strategy = new ShockWaveStrategy(this);
    else if (firingInfo.flagType == Flags::Thief)
      strategy = new ThiefStrategy(this);
    else if (firingInfo.flagType == Flags::PhantomZone)
      strategy = new PhantomBulletStrategy(this);
    else
      assert(0);    // shouldn't happen
  }
}

ShotPath::~ShotPath()
{
  delete strategy;
}

float			ShotPath::checkHit(const BaseLocalPlayer* player,
							float position[3]) const
{
  return strategy->checkHit(player, position);
}

bool			ShotPath::isStoppedByHit() const
{
  return strategy->isStoppedByHit();
}

void			ShotPath::addShot(SceneDatabase* scene,
						bool colorblind)
{
  strategy->addShot(scene, colorblind);
}

void			ShotPath::radarRender() const
{
  if (!isExpired()) strategy->radarRender();
}

void			ShotPath::updateShot(float dt)
{
  // get new time step and set current time
  currentTime += dt;

  // update shot
  if (!expired) {
    if (expiring) setExpired();
    else getStrategy()->update(dt);
  }
}

void			ShotPath::setReloadTime(float _reloadTime)
{
  reloadTime = _reloadTime;
}

void			ShotPath::setPosition(const float* p)
{
  firingInfo.shot.pos[0] = p[0];
  firingInfo.shot.pos[1] = p[1];
  firingInfo.shot.pos[2] = p[2];
}

void			ShotPath::setVelocity(const float* v)
{
  firingInfo.shot.vel[0] = v[0];
  firingInfo.shot.vel[1] = v[1];
  firingInfo.shot.vel[2] = v[2];
}

void			ShotPath::setExpiring()
{
  expiring = true;
}

void			ShotPath::setExpired()
{
  expiring = true;
  expired = true;
  getStrategy()->expire();
}

void			ShotPath::boostReloadTime(float dt)
{
  reloadTime += dt;
}

//
// LocalShotPath
//

LocalShotPath::LocalShotPath(const FiringInfo& info) :
				ShotPath(info)
{
  // do nothing
}

LocalShotPath::~LocalShotPath()
{
  // do nothing
}

void			LocalShotPath::update(float dt)
{
  getFiringInfo().shot.dt += dt;
  updateShot(dt);

  // send updates if necessary
  getStrategy()->sendUpdate(getFiringInfo());
}

//
// RemoteShotPath
//

RemoteShotPath::RemoteShotPath(const FiringInfo& info) :
				ShotPath(info)
{
  // do nothing
}

RemoteShotPath::~RemoteShotPath()
{
  // do nothing
}

void			RemoteShotPath::update(float dt)
{
  // update shot
  updateShot(dt);
}

void			RemoteShotPath::update(const ShotUpdate& shot,
				uint16_t code, void* msg)
{
  // update shot info
  getFiringInfo().shot = shot;

  // let the strategy see the message
  getStrategy()->readUpdate(code, msg);
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.
#ifndef UNITTEST_RDB_ENV_HPP_
#define UNITTEST_RDB_ENV_HPP_

#include <stdexcept>
#include <set>
#include <map>
#include <string>

#include "errors.hpp"
#include <boost/variant.hpp>

#include "clustering/administration/main/ports.hpp"
#include "clustering/administration/main/watchable_fields.hpp"
#include "clustering/administration/metadata.hpp"
#include "concurrency/cross_thread_watchable.hpp"
#include "concurrency/watchable.hpp"
#include "extproc/extproc_pool.hpp"
#include "extproc/extproc_spawner.hpp"
#include "rdb_protocol/env.hpp"
#include "rpc/connectivity/multiplexer.hpp"
#include "rpc/directory/read_manager.hpp"
#include "rpc/directory/write_manager.hpp"
#include "rpc/semilattice/view/field.hpp"
#include "rpc/semilattice/watchable.hpp"
#include "unittest/dummy_metadata_controller.hpp"
#include "unittest/test_cluster_group.hpp"
#include "unittest/unittest_utils.hpp"

namespace unittest {

// These classes are used to provide a mock environment for running reql queries

class mock_namespace_repo_t;

// The mock namespace interface handles all read and write calls, using a simple in-
//  memory map of store_key_t to scoped_cJSON_t.  The get_data function allows a test to
//  read or modify the dataset to prepare for a query or to check that changes were made.
class mock_namespace_interface_t : public namespace_interface_t {
private:
    std::map<store_key_t, scoped_cJSON_t*> data;
    mock_namespace_repo_t *parent;

public:
    explicit mock_namespace_interface_t(mock_namespace_repo_t *_parent);
    virtual ~mock_namespace_interface_t();

    void read(const read_t &query,
              read_response_t *response,
              UNUSED order_token_t tok,
              signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, cannot_perform_query_exc_t);

    void read_outdated(const read_t &query,
                       read_response_t *response,
                       signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, cannot_perform_query_exc_t);

    void write(const write_t &query,
               write_response_t *response,
               UNUSED order_token_t tok,
               signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, cannot_perform_query_exc_t);

    std::map<store_key_t, scoped_cJSON_t *> *get_data();

    std::set<region_t> get_sharding_scheme() THROWS_ONLY(cannot_perform_query_exc_t);

private:
    cond_t ready_cond;

    struct read_visitor_t : public boost::static_visitor<void> {
        void operator()(const point_read_t &get);
        void NORETURN operator()(const changefeed_subscribe_t &);
        void NORETURN operator()(const changefeed_stamp_t &);
        void NORETURN operator()(UNUSED const rget_read_t &rget);
        void NORETURN operator()(UNUSED const distribution_read_t &dg);
        void NORETURN operator()(UNUSED const sindex_list_t &sl);
        void NORETURN operator()(UNUSED const sindex_status_t &ss);

        read_visitor_t(std::map<store_key_t, scoped_cJSON_t*> *_data, read_response_t *_response);

        std::map<store_key_t, scoped_cJSON_t*> *data;
        read_response_t *response;
    };

    struct write_visitor_t : public boost::static_visitor<void> {
        void operator()(const batched_replace_t &br);
        void operator()(const batched_insert_t &br);
        void NORETURN operator()(UNUSED const point_write_t &w);
        void NORETURN operator()(UNUSED const point_delete_t &d);
        void NORETURN operator()(UNUSED const sindex_create_t &s);
        void NORETURN operator()(UNUSED const sindex_drop_t &s);
        void NORETURN operator()(UNUSED const sync_t &s);

        write_visitor_t(std::map<store_key_t, scoped_cJSON_t*> *_data, ql::env_t *_env, write_response_t *_response);

        std::map<store_key_t, scoped_cJSON_t*> *data;
        ql::env_t *env;
        write_response_t *response;
    };
};

// This stuff isn't really designed for concurrency, use for single-threaded tests
class mock_namespace_repo_t : public base_namespace_repo_t {
public:
    mock_namespace_repo_t();
    virtual ~mock_namespace_repo_t();

    void set_env(ql::env_t *_env);
    ql::env_t *get_env();

    mock_namespace_interface_t* get_ns_if(const namespace_id_t &ns_id);

private:
    namespace_cache_entry_t *get_cache_entry(const namespace_id_t &ns_id);

    struct mock_namespace_cache_entry_t {
        explicit mock_namespace_cache_entry_t(mock_namespace_repo_t *ns_repo) :
            mock_ns_if(ns_repo) { }
        namespace_cache_entry_t entry;
        mock_namespace_interface_t mock_ns_if;
    };

    ql::env_t *env;
    std::map<namespace_id_t, mock_namespace_cache_entry_t*> cache;
};

class invalid_name_exc_t : public std::exception {
public:
    explicit invalid_name_exc_t(const std::string& name) :
        error_string(strprintf("invalid name string: %s", name.c_str())) { }
    ~invalid_name_exc_t() throw () { }
    const char *what() const throw () {
        return error_string.c_str();
    }
private:
    const std::string error_string;
};

// Because of how internal objects are meant to be instantiated, the proper order of
//  instantiation is to create a test_rdb_env_t at the top-level of the test (before
//  entering the thread pool), then to call make_env() on the object once inside the
//  thread pool.  From there, the instance can provide a pointer to the rdb_env_t.
// At the moment, this mocks everything except the directory (which is a huge bitch to
//  do, but you're welcome to try), so metaqueries will not work, but everything else
//  should be good.  That is, you can specify databases and tables, but you can't create
//  or destroy them using reql in this environment.  As such, you should create any
//  necessary databases and tables BEFORE creating the instance_t by using the
//  add_table and add_database functions.
class test_rdb_env_t {
public:
    test_rdb_env_t();
    ~test_rdb_env_t();

    // The initial_data parameter allows a test to provide a starting dataset.  At the moment,
    //  it just takes a set of maps of strings to strings, which will be converted into a set
    //  of JSON structures.  This means that the JSON values will only be strings, but if a
    //  test needs different properties in their objects, this call should be modified.
    namespace_id_t add_table(const std::string &table_name,
                             const uuid_u &db_id,
                             const std::string &primary_key,
                             const std::set<std::map<std::string, std::string> > &initial_data);
    database_id_t add_database(const std::string &db_name);

    class instance_t {
    public:
        explicit instance_t(test_rdb_env_t *test_env);

        ql::env_t *get();
        void interrupt();

        std::map<store_key_t, scoped_cJSON_t*>* get_data(const namespace_id_t &ns_id);

    private:
        dummy_semilattice_controller_t<cluster_semilattice_metadata_t> dummy_semilattice_controller;
        clone_ptr_t<semilattice_watchable_t<cow_ptr_t<namespaces_semilattice_metadata_t> > > namespaces_metadata;
        clone_ptr_t<semilattice_watchable_t<databases_semilattice_metadata_t> > databases_metadata;
        extproc_pool_t extproc_pool;
        scoped_ptr_t<ql::env_t> env;
        reactor_test_cluster_t test_cluster;
        mock_namespace_repo_t rdb_ns_repo;
        cond_t interruptor;
    };

    void make_env(scoped_ptr_t<instance_t> *instance_out);

private:
    friend class instance_t;

    uuid_u machine_id;
    cluster_semilattice_metadata_t metadata;
    extproc_spawner_t extproc_spawner;

    // Initial data for tables are stored here until the instance_t is constructed, at
    //  which point, it is moved into a mock_namespace_interface_t, and this is cleared.
    std::map<namespace_id_t, std::map<store_key_t, scoped_cJSON_t*>*> initial_datas;
};

}

#endif // UNITTEST_RDB_ENV_HPP_
<commit_msg>Some whitespace before pointers...<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.
#ifndef UNITTEST_RDB_ENV_HPP_
#define UNITTEST_RDB_ENV_HPP_

#include <stdexcept>
#include <set>
#include <map>
#include <string>

#include "errors.hpp"
#include <boost/variant.hpp>

#include "clustering/administration/main/ports.hpp"
#include "clustering/administration/main/watchable_fields.hpp"
#include "clustering/administration/metadata.hpp"
#include "concurrency/cross_thread_watchable.hpp"
#include "concurrency/watchable.hpp"
#include "extproc/extproc_pool.hpp"
#include "extproc/extproc_spawner.hpp"
#include "rdb_protocol/env.hpp"
#include "rpc/connectivity/multiplexer.hpp"
#include "rpc/directory/read_manager.hpp"
#include "rpc/directory/write_manager.hpp"
#include "rpc/semilattice/view/field.hpp"
#include "rpc/semilattice/watchable.hpp"
#include "unittest/dummy_metadata_controller.hpp"
#include "unittest/test_cluster_group.hpp"
#include "unittest/unittest_utils.hpp"

namespace unittest {

// These classes are used to provide a mock environment for running reql queries

class mock_namespace_repo_t;

// The mock namespace interface handles all read and write calls, using a simple in-
//  memory map of store_key_t to scoped_cJSON_t.  The get_data function allows a test to
//  read or modify the dataset to prepare for a query or to check that changes were made.
class mock_namespace_interface_t : public namespace_interface_t {
private:
    std::map<store_key_t, scoped_cJSON_t *> data;
    mock_namespace_repo_t *parent;

public:
    explicit mock_namespace_interface_t(mock_namespace_repo_t *_parent);
    virtual ~mock_namespace_interface_t();

    void read(const read_t &query,
              read_response_t *response,
              UNUSED order_token_t tok,
              signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, cannot_perform_query_exc_t);

    void read_outdated(const read_t &query,
                       read_response_t *response,
                       signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, cannot_perform_query_exc_t);

    void write(const write_t &query,
               write_response_t *response,
               UNUSED order_token_t tok,
               signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, cannot_perform_query_exc_t);

    std::map<store_key_t, scoped_cJSON_t *> *get_data();

    std::set<region_t> get_sharding_scheme() THROWS_ONLY(cannot_perform_query_exc_t);

private:
    cond_t ready_cond;

    struct read_visitor_t : public boost::static_visitor<void> {
        void operator()(const point_read_t &get);
        void NORETURN operator()(const changefeed_subscribe_t &);
        void NORETURN operator()(const changefeed_stamp_t &);
        void NORETURN operator()(UNUSED const rget_read_t &rget);
        void NORETURN operator()(UNUSED const distribution_read_t &dg);
        void NORETURN operator()(UNUSED const sindex_list_t &sl);
        void NORETURN operator()(UNUSED const sindex_status_t &ss);

        read_visitor_t(std::map<store_key_t, scoped_cJSON_t *> *_data, read_response_t *_response);

        std::map<store_key_t, scoped_cJSON_t *> *data;
        read_response_t *response;
    };

    struct write_visitor_t : public boost::static_visitor<void> {
        void operator()(const batched_replace_t &br);
        void operator()(const batched_insert_t &br);
        void NORETURN operator()(UNUSED const point_write_t &w);
        void NORETURN operator()(UNUSED const point_delete_t &d);
        void NORETURN operator()(UNUSED const sindex_create_t &s);
        void NORETURN operator()(UNUSED const sindex_drop_t &s);
        void NORETURN operator()(UNUSED const sync_t &s);

        write_visitor_t(std::map<store_key_t, scoped_cJSON_t *> *_data, ql::env_t *_env, write_response_t *_response);

        std::map<store_key_t, scoped_cJSON_t *> *data;
        ql::env_t *env;
        write_response_t *response;
    };
};

// This stuff isn't really designed for concurrency, use for single-threaded tests
class mock_namespace_repo_t : public base_namespace_repo_t {
public:
    mock_namespace_repo_t();
    virtual ~mock_namespace_repo_t();

    void set_env(ql::env_t *_env);
    ql::env_t *get_env();

    mock_namespace_interface_t *get_ns_if(const namespace_id_t &ns_id);

private:
    namespace_cache_entry_t *get_cache_entry(const namespace_id_t &ns_id);

    struct mock_namespace_cache_entry_t {
        explicit mock_namespace_cache_entry_t(mock_namespace_repo_t *ns_repo) :
            mock_ns_if(ns_repo) { }
        namespace_cache_entry_t entry;
        mock_namespace_interface_t mock_ns_if;
    };

    ql::env_t *env;
    std::map<namespace_id_t, mock_namespace_cache_entry_t *> cache;
};

class invalid_name_exc_t : public std::exception {
public:
    explicit invalid_name_exc_t(const std::string& name) :
        error_string(strprintf("invalid name string: %s", name.c_str())) { }
    ~invalid_name_exc_t() throw () { }
    const char *what() const throw () {
        return error_string.c_str();
    }
private:
    const std::string error_string;
};

// Because of how internal objects are meant to be instantiated, the proper order of
//  instantiation is to create a test_rdb_env_t at the top-level of the test (before
//  entering the thread pool), then to call make_env() on the object once inside the
//  thread pool.  From there, the instance can provide a pointer to the rdb_env_t.
// At the moment, this mocks everything except the directory (which is a huge bitch to
//  do, but you're welcome to try), so metaqueries will not work, but everything else
//  should be good.  That is, you can specify databases and tables, but you can't create
//  or destroy them using reql in this environment.  As such, you should create any
//  necessary databases and tables BEFORE creating the instance_t by using the
//  add_table and add_database functions.
class test_rdb_env_t {
public:
    test_rdb_env_t();
    ~test_rdb_env_t();

    // The initial_data parameter allows a test to provide a starting dataset.  At the moment,
    //  it just takes a set of maps of strings to strings, which will be converted into a set
    //  of JSON structures.  This means that the JSON values will only be strings, but if a
    //  test needs different properties in their objects, this call should be modified.
    namespace_id_t add_table(const std::string &table_name,
                             const uuid_u &db_id,
                             const std::string &primary_key,
                             const std::set<std::map<std::string, std::string> > &initial_data);
    database_id_t add_database(const std::string &db_name);

    class instance_t {
    public:
        explicit instance_t(test_rdb_env_t *test_env);

        ql::env_t *get();
        void interrupt();

        std::map<store_key_t, scoped_cJSON_t *> *get_data(const namespace_id_t &ns_id);

    private:
        dummy_semilattice_controller_t<cluster_semilattice_metadata_t> dummy_semilattice_controller;
        clone_ptr_t<semilattice_watchable_t<cow_ptr_t<namespaces_semilattice_metadata_t> > > namespaces_metadata;
        clone_ptr_t<semilattice_watchable_t<databases_semilattice_metadata_t> > databases_metadata;
        extproc_pool_t extproc_pool;
        scoped_ptr_t<ql::env_t> env;
        reactor_test_cluster_t test_cluster;
        mock_namespace_repo_t rdb_ns_repo;
        cond_t interruptor;
    };

    void make_env(scoped_ptr_t<instance_t> *instance_out);

private:
    friend class instance_t;

    uuid_u machine_id;
    cluster_semilattice_metadata_t metadata;
    extproc_spawner_t extproc_spawner;

    // Initial data for tables are stored here until the instance_t is constructed, at
    //  which point, it is moved into a mock_namespace_interface_t, and this is cleared.
    std::map<namespace_id_t, std::map<store_key_t, scoped_cJSON_t *> *> initial_datas;
};

}

#endif // UNITTEST_RDB_ENV_HPP_
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: dbptypes.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2004-05-19 13:40:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _EXTENSIONS_DBP_DBPTYPES_HXX_
#define _EXTENSIONS_DBP_DBPTYPES_HXX_

#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif

//.........................................................................
namespace dbp
{
//.........................................................................

    DECLARE_STL_VECTOR( String, StringArray );
    DECLARE_STL_STDKEY_SET( String, StringBag );
    DECLARE_STL_STDKEY_MAP( sal_uInt32, String, MapInt2String );

//.........................................................................
}   // namespace dbp
//.........................................................................
#endif // _EXTENSIONS_DBP_DBPTYPES_HXX_

<commit_msg>INTEGRATION: CWS visibility03 (1.3.172); FILE MERGED 2005/03/07 19:06:59 mhu 1.3.172.1: #i40092# Added missing include.<commit_after>/*************************************************************************
 *
 *  $RCSfile: dbptypes.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2005-04-13 08:37:50 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _EXTENSIONS_DBP_DBPTYPES_HXX_
#define _EXTENSIONS_DBP_DBPTYPES_HXX_

#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif

#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

//.........................................................................
namespace dbp
{
//.........................................................................

    DECLARE_STL_VECTOR( String, StringArray );
    DECLARE_STL_STDKEY_SET( String, StringBag );
    DECLARE_STL_STDKEY_MAP( sal_uInt32, String, MapInt2String );

//.........................................................................
}   // namespace dbp
//.........................................................................
#endif // _EXTENSIONS_DBP_DBPTYPES_HXX_

<|endoftext|>


<commit_before>#include <okui/views/MarkupView.h>

#include <scraps/net/HTTPRequest.h>

namespace okui {
namespace views {

void MarkupView::load(stdts::string_view markup) {
    _element = _context.load(markup);
    if (_element && _element->view()) {
        addSubview(_element->view());
        layout();
    }
}

void MarkupView::stream(stdts::string_view uri) {
    _lastStreamResponse = {};
    _streamURI = uri.to_string();
    _sendStreamRequest();
    addUpdateHook("MarkupView::_streamUpdateHook", [&] { _streamUpdateHook(); });
}

void MarkupView::layout() {
    if (_element && _element->view()) {
        _element->view()->setBounds(0, 0, bounds().width, bounds().height);
    }
}

void MarkupView::_sendStreamRequest() {
    SCRAPS_ASSERT(_streamURI);
    _lastStreamRequestTime = std::chrono::steady_clock::now();
    _pendingStreamResponse = std::async(std::launch::async, [=, uri = _streamURI, lastStreamResponse = _lastStreamResponse] {
        std::vector<std::string> headers;
        if (lastStreamResponse && lastStreamResponse->etag) {
            headers.emplace_back("If-None-Match: "s + *lastStreamResponse->etag);
            headers.emplace_back("X-Wait-If-Match: true");
        }
        scraps::net::HTTPRequest request(*uri, nullptr, 0, headers);
        request.wait();

        StreamResponse ret;
        if (!request.error()) {
            auto etags = request.responseHeaders("ETag");
            if (etags.size() == 1) {
                ret.etag = etags[0];
            }
            if (request.responseStatus() == 200) {
                ret.markup = request.responseBody();
            }
        }
        return ret;
    });
}

void MarkupView::_streamUpdateHook() {
    if (!_pendingStreamResponse.valid()) {
        if (_streamURI && (!_lastStreamRequestTime || *_lastStreamRequestTime + 5s < std::chrono::steady_clock::now())) {
            _sendStreamRequest();
        }
        return;
    }

    if (_pendingStreamResponse.wait_for(0s) == std::future_status::ready) {
        auto response = _pendingStreamResponse.get();
        if (response.markup) {
            if (!_lastStreamResponse || response.markup != _lastStreamResponse->markup) {
                load(*response.markup);
                if (response.etag) {
                    // we want to reconnect immediately
                    _lastStreamRequestTime = {};
                }
            }
            _lastStreamResponse = response;
        }
    }
}

}} // namespace okui::views
<commit_msg>android fix<commit_after>#include <okui/views/MarkupView.h>

#include <scraps/net/HTTPRequest.h>

namespace okui {
namespace views {

void MarkupView::load(stdts::string_view markup) {
    _element = _context.load(markup);
    if (_element && _element->view()) {
        addSubview(_element->view());
        layout();
    }
}

void MarkupView::stream(stdts::string_view uri) {
    _lastStreamResponse = {};
    _streamURI = uri.to_string();
    _sendStreamRequest();
    addUpdateHook("MarkupView::_streamUpdateHook", [&] { _streamUpdateHook(); });
}

void MarkupView::layout() {
    if (_element && _element->view()) {
        _element->view()->setBounds(0, 0, bounds().width, bounds().height);
    }
}

void MarkupView::_sendStreamRequest() {
    SCRAPS_ASSERT(_streamURI);
    _lastStreamRequestTime = std::chrono::steady_clock::now();
    _pendingStreamResponse = std::async(std::launch::async, [=, uri = _streamURI, lastStreamResponse = _lastStreamResponse] {
        std::vector<std::string> headers;
        if (lastStreamResponse && lastStreamResponse->etag) {
            headers.emplace_back("If-None-Match: "s + *lastStreamResponse->etag);
            headers.emplace_back("X-Wait-If-Match: true");
        }
        scraps::net::HTTPRequest request(*uri, nullptr, 0, headers);
        request.wait();

        StreamResponse ret;
        if (!request.error()) {
            auto etags = request.responseHeaders("ETag");
            if (etags.size() == 1) {
                ret.etag = etags[0];
            }
            if (request.responseStatus() == 200) {
                ret.markup = request.responseBody();
            }
        }
        return ret;
    });
}

void MarkupView::_streamUpdateHook() {
    if (!_pendingStreamResponse.valid()) {
        if (_streamURI && (!_lastStreamRequestTime || *_lastStreamRequestTime + 5s < std::chrono::steady_clock::now())) {
            _sendStreamRequest();
        }
        return;
    }

    if (_pendingStreamResponse.wait_for(0s) == std::future_status::ready) {
        auto response = _pendingStreamResponse.get();
        if (response.markup) {
            if (!_lastStreamResponse || !(response.markup == _lastStreamResponse->markup)) {
                load(*response.markup);
                if (response.etag) {
                    // we want to reconnect immediately
                    _lastStreamRequestTime = {};
                }
            }
            _lastStreamResponse = response;
        }
    }
}

}} // namespace okui::views
<|endoftext|>


<commit_before>#include "visuals/mainmenu.h"
#include "global_constants.h"

#include "allegro5/allegro_font.h"
#include "allegro5/allegro_ttf.h"

#define LEFT_MOUSE_BUTTON 1
#define RIGHT_MOUSE_BUTTON 2

Mainmenu::Mainmenu(ALLEGRO_DISPLAY *display, MenuContainer &owner_) : Menu(display, owner_), spriteloader(false),
                                                                      istypingIP(false), ipfont(nullptr)
{
    background.init("ui/menus/mainmenu/");

    ALLEGRO_FONT *normal_button_font = al_load_font("Vanguard Title Font.ttf", 30, ALLEGRO_TTF_MONOCHROME);
    ALLEGRO_FONT *hovered_button_font = al_load_font("Vanguard Title Font.ttf", 40, ALLEGRO_TTF_MONOCHROME);
    ipfont = al_load_font("Vanguard Text Font.ttf", 10, ALLEGRO_TTF_MONOCHROME);

    int WINDOW_WIDTH = al_get_display_width(display);
    int WINDOW_HEIGHT = al_get_display_height(display);
    int initial_x = WINDOW_WIDTH*0.1;
    int initial_height = WINDOW_HEIGHT*0.4;
    double line_spacing = al_get_font_line_height(hovered_button_font)*1.2;
    int counter = 0;

    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("JOIN SERVER", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::joinlobby, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("HOST SERVER", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::hostserver, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("JOIN SELF (DEBUG)", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::joinself, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("CONNECT MANUALLY", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::connectmanually, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("OPTIONS", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         nullptr, normal_button_font,
                                                                         hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("COMMUNITY", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         nullptr, normal_button_font,
                                                                         hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("CREDITS", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         nullptr, normal_button_font,
                                                                         hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("QUIT", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::quit, this),
                                                                         normal_button_font, hovered_button_font)));
}

void Mainmenu::run(ALLEGRO_DISPLAY *display, ALLEGRO_EVENT_QUEUE *event_queue)
{
    ALLEGRO_EVENT event;
    // Capture events first
    while (al_get_next_event(event_queue, &event))
    {
        if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            // Deliberate closing, not an error
            quit();
        }

        if (istypingIP)
        {
            if (event.type == ALLEGRO_EVENT_KEY_CHAR)
            {
                // Ignore things that are typed outside focus
                if (event.keyboard.display == display)
                {
                    // I'm not going to even try messing with unicode here

                    if (event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL)
                    {
                        if (event.keyboard.keycode == ALLEGRO_KEY_V)
                        {
                            ipstring += al_get_clipboard_text(display);
                        }
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_INSERT)
                    {
                        ipstring += al_get_clipboard_text(display);
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_BACKSPACE)
                    {
                        if (ipstring.length() > 0)
                        {
                            ipstring.pop_back();
                        }
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                    {
                        ipstring = "";
                        istypingIP = false;
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_ENTER)
                    {
                        owner.serverip = ipstring;
                        owner.planned_action = JOIN_SERVER;
                        owner.exitmenus();
                    }
                    else if (event.keyboard.unichar >= 32 and event.keyboard.unichar < 127)
                    {
                        ipstring += static_cast<char>(event.keyboard.unichar);
                    }
                }
            }
        }
        else
        {
            switch (event.type)
            {
                case ALLEGRO_EVENT_KEY_CHAR:
                    if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                    {
                        // Exit menu altogether
                        quit();
                    }

                case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
                    if (event.mouse.button == LEFT_MOUSE_BUTTON)
                    {
                        for (auto& button : buttons)
                        {
                            if (button->ontop(event.mouse.x, event.mouse.y))
                            {
                                button->onclick();
                            }
                        }
                    }
            }
        }
    }

    background.update(MENU_TIMESTEP);

    ALLEGRO_MOUSE_STATE mousestate;
    al_get_mouse_state(&mousestate);

    // use mousestate.x or .y for position of mouse on screen

    // Draw
    al_draw_bitmap(spriteloader.requestsprite(background.getframepath()), 0, 0, 0);
    for (auto& button : buttons)
    {
        button->render(display, mousestate.x, mousestate.y);
    }

    if (istypingIP)
    {
        int WINDOW_WIDTH = al_get_display_width(display);
        int WINDOW_HEIGHT = al_get_display_height(display);
        int textheight = al_get_font_line_height(ipfont);

        al_draw_text(ipfont, al_map_rgb(255, 255, 255), WINDOW_WIDTH/2.0, WINDOW_HEIGHT/2.0 - textheight*2,
                     ALLEGRO_ALIGN_CENTER, "Please enter the server's ip and confirm with enter:");

        al_draw_text(ipfont, al_map_rgb(255, 255, 255), WINDOW_WIDTH/2.0, WINDOW_HEIGHT/2.0, ALLEGRO_ALIGN_CENTER,
                     ipstring.c_str());
    }

    al_flip_display();
}

void Mainmenu::hostserver()
{
    owner.planned_action = POSTMENUACTION::HOST_SERVER;
    owner.exitmenus();
}

void Mainmenu::joinlobby()
{
    owner.planned_action = POSTMENUACTION::OPEN_LOBBY;
}

void Mainmenu::joinself()
{
    owner.planned_action = POSTMENUACTION::JOIN_SERVER;
    owner.serverip = "127.0.0.1";
    owner.serverport = 3226;
    owner.exitmenus();
}

void Mainmenu::connectmanually()
{
    istypingIP = true;
}

void Mainmenu::quit()
{
    owner.planned_action = POSTMENUACTION::QUIT;
    owner.exitmenus();
}<commit_msg>Added background scaling for main menu.<commit_after>#include "visuals/mainmenu.h"
#include "global_constants.h"

#include "allegro5/allegro_font.h"
#include "allegro5/allegro_ttf.h"

#define LEFT_MOUSE_BUTTON 1
#define RIGHT_MOUSE_BUTTON 2

Mainmenu::Mainmenu(ALLEGRO_DISPLAY *display, MenuContainer &owner_) : Menu(display, owner_), spriteloader(false),
                                                                      istypingIP(false), ipfont(nullptr)
{
    background.init("ui/menus/mainmenu/");

    ALLEGRO_FONT *normal_button_font = al_load_font("Vanguard Title Font.ttf", 30, ALLEGRO_TTF_MONOCHROME);
    ALLEGRO_FONT *hovered_button_font = al_load_font("Vanguard Title Font.ttf", 40, ALLEGRO_TTF_MONOCHROME);
    ipfont = al_load_font("Vanguard Text Font.ttf", 10, ALLEGRO_TTF_MONOCHROME);

    int WINDOW_WIDTH = al_get_display_width(display);
    int WINDOW_HEIGHT = al_get_display_height(display);
    int initial_x = WINDOW_WIDTH*0.1;
    int initial_height = WINDOW_HEIGHT*0.4;
    double line_spacing = al_get_font_line_height(hovered_button_font)*1.2;
    int counter = 0;

    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("JOIN SERVER", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::joinlobby, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("HOST SERVER", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::hostserver, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("JOIN SELF (DEBUG)", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::joinself, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("CONNECT MANUALLY", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::connectmanually, this),
                                                                         normal_button_font, hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("OPTIONS", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         nullptr, normal_button_font,
                                                                         hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("COMMUNITY", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         nullptr, normal_button_font,
                                                                         hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("CREDITS", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         nullptr, normal_button_font,
                                                                         hovered_button_font)));
    buttons.push_back(std::unique_ptr<MainmenuButton>(new MainmenuButton("QUIT", initial_x,
                                                                         initial_height + (counter++)*line_spacing,
                                                                         std::bind(&Mainmenu::quit, this),
                                                                         normal_button_font, hovered_button_font)));
}

void Mainmenu::run(ALLEGRO_DISPLAY *display, ALLEGRO_EVENT_QUEUE *event_queue)
{
    ALLEGRO_EVENT event;
    // Capture events first
    while (al_get_next_event(event_queue, &event))
    {
        if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            // Deliberate closing, not an error
            quit();
        }

        if (event.type ==  ALLEGRO_EVENT_DISPLAY_RESIZE)
        {
            al_acknowledge_resize(display);
        }

        if (istypingIP)
        {
            if (event.type == ALLEGRO_EVENT_KEY_CHAR)
            {
                // Ignore things that are typed outside focus
                if (event.keyboard.display == display)
                {
                    // I'm not going to even try messing with unicode here

                    if (event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL)
                    {
                        if (event.keyboard.keycode == ALLEGRO_KEY_V)
                        {
                            ipstring += al_get_clipboard_text(display);
                        }
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_INSERT)
                    {
                        ipstring += al_get_clipboard_text(display);
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_BACKSPACE)
                    {
                        if (ipstring.length() > 0)
                        {
                            ipstring.pop_back();
                        }
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                    {
                        ipstring = "";
                        istypingIP = false;
                    }
                    else if (event.keyboard.keycode == ALLEGRO_KEY_ENTER)
                    {
                        owner.serverip = ipstring;
                        owner.planned_action = JOIN_SERVER;
                        owner.exitmenus();
                    }
                    else if (event.keyboard.unichar >= 32 and event.keyboard.unichar < 127)
                    {
                        ipstring += static_cast<char>(event.keyboard.unichar);
                    }
                }
            }
        }
        else
        {
            switch (event.type)
            {
                case ALLEGRO_EVENT_KEY_CHAR:
                    if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                    {
                        // Exit menu altogether
                        quit();
                    }

                case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
                    if (event.mouse.button == LEFT_MOUSE_BUTTON)
                    {
                        for (auto& button : buttons)
                        {
                            if (button->ontop(event.mouse.x, event.mouse.y))
                            {
                                button->onclick();
                            }
                        }
                    }
            }
        }
    }

    background.update(MENU_TIMESTEP);

    ALLEGRO_MOUSE_STATE mousestate;
    al_get_mouse_state(&mousestate);

    // use mousestate.x or .y for position of mouse on screen

    // Draw
    int WINDOW_WIDTH = al_get_display_width(display);
    int WINDOW_HEIGHT = al_get_display_height(display);
    ALLEGRO_BITMAP* bgsprite = spriteloader.requestsprite(background.getframepath());
    double w = al_get_bitmap_width(bgsprite), h = al_get_bitmap_height(bgsprite);
    al_draw_scaled_bitmap(bgsprite, 0, 0, w, h, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);

    for (auto& button : buttons)
    {
        button->render(display, mousestate.x, mousestate.y);
    }

    if (istypingIP)
    {
        int textheight = al_get_font_line_height(ipfont);

        al_draw_text(ipfont, al_map_rgb(255, 255, 255), WINDOW_WIDTH/2.0, WINDOW_HEIGHT/2.0 - textheight*2,
                     ALLEGRO_ALIGN_CENTER, "Please enter the server's ip and confirm with enter:");

        al_draw_text(ipfont, al_map_rgb(255, 255, 255), WINDOW_WIDTH/2.0, WINDOW_HEIGHT/2.0, ALLEGRO_ALIGN_CENTER,
                     ipstring.c_str());
    }

    al_flip_display();
}

void Mainmenu::hostserver()
{
    owner.planned_action = POSTMENUACTION::HOST_SERVER;
    owner.exitmenus();
}

void Mainmenu::joinlobby()
{
    owner.planned_action = POSTMENUACTION::OPEN_LOBBY;
}

void Mainmenu::joinself()
{
    owner.planned_action = POSTMENUACTION::JOIN_SERVER;
    owner.serverip = "127.0.0.1";
    owner.serverport = 3226;
    owner.exitmenus();
}

void Mainmenu::connectmanually()
{
    istypingIP = true;
}

void Mainmenu::quit()
{
    owner.planned_action = POSTMENUACTION::QUIT;
    owner.exitmenus();
}<|endoftext|>