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

#include <miopen/config.h>
#include <miopen/kernel_info.hpp>
#include <miopen/common.hpp>
#include <miopen/invoker_cache.hpp>
#include <miopen/kernel.hpp>
#include <miopen/miopen.h>
#include <miopen/names.hpp>
#include <miopen/object.hpp>
#include <miopen/allocator.hpp>
#include <miopen/simple_hash.hpp>
#include <miopen/solver_id.hpp>
#include <miopen/stringutils.hpp>
#include <miopen/target_properties.hpp>

#include <boost/range/adaptor/transformed.hpp>

#include <cstdio>
#include <cstring>
#include <ios>
#include <sstream>
#include <memory>
#include <vector>
#include <unordered_map>

#if MIOPEN_USE_ROCBLAS
#include <miopen/manage_ptr.hpp>
#if MIOPEN_ROCBLAS_VERSION_FLAT < 2045000
#include <rocblas.h>
#else
#include <rocblas/rocblas.h>
#endif
#endif

namespace miopen {

struct HandleImpl;
#if MIOPEN_USE_MIOPENGEMM
struct GemmGeometry;
using GemmKey = std::pair<std::string, std::string>;
#endif

#if MIOPEN_USE_ROCBLAS
using rocblas_handle_ptr = MIOPEN_MANAGE_PTR(rocblas_handle, rocblas_destroy_handle);
#endif

struct Handle : miopenHandle
{
    friend struct TargetProperties;

    Handle();
    Handle(miopenAcceleratorQueue_t stream);
    Handle(Handle&&) noexcept;
    ~Handle();

    miopenAcceleratorQueue_t GetStream() const;
    void SetStream(miopenAcceleratorQueue_t streamID) const;

    void SetAllocator(miopenAllocatorFunction allocator,
                      miopenDeallocatorFunction deallocator,
                      void* allocatorContext) const;

    void EnableProfiling(bool enable = true) const;

    void ResetKernelTime() const;
    void AccumKernelTime(float curr_time) const;

    float GetKernelTime() const;
    bool IsProfilingEnabled() const;

    KernelInvoke AddKernel(const std::string& algorithm,
                           const std::string& network_config,
                           const std::string& program_name,
                           const std::string& kernel_name,
                           const std::vector<size_t>& vld,
                           const std::vector<size_t>& vgd,
                           const std::string& params,
                           std::size_t cache_index       = 0,
                           bool is_kernel_str            = false,
                           const std::string& kernel_src = "") const;

    bool HasKernel(const std::string& algorithm, const std::string& network_config) const;

    void ClearKernels(const std::string& algorithm, const std::string& network_config) const;

    auto GetKernels(const std::string& algorithm, const std::string& network_config) const
    {
        return this->GetKernelsImpl(algorithm, network_config) |
               boost::adaptors::transformed([this](Kernel k) { return this->Run(k); });
    }
    KernelInvoke GetKernel(const std::string& algorithm, const std::string& network_config) const
    {
        auto ks = this->GetKernelsImpl(algorithm, network_config);
        if(ks.empty())
        {
            MIOPEN_THROW("looking for default kernel (does not exist): " + algorithm + ", " +
                         network_config);
        }
        return this->Run(ks.front());
    }

    KernelInvoke Run(Kernel k) const;
    const std::vector<Kernel>& GetKernelsImpl(const std::string& algorithm,
                                              const std::string& network_config) const;

    Program LoadProgram(const std::string& program_name,
                        std::string params,
                        bool is_kernel_str,
                        const std::string& kernel_src) const;

    bool HasProgram(const std::string& program_name, const std::string& params) const;
    void ClearProgram(const std::string& program_name, const std::string& params) const;
    void AddProgram(Program prog, const std::string& program_name, const std::string& params) const;

    void Finish() const;
    void Flush() const;

    std::size_t GetLocalMemorySize() const;
    std::size_t GetGlobalMemorySize() const;
    std::size_t GetImage3dMaxWidth() const;
    std::size_t GetWavefrontWidth() const;
    std::size_t GetMaxComputeUnits() const;
    std::size_t GetMaxHardwareComputeUnits() const
    {
        std::size_t num_cu = this->GetMaxComputeUnits();
        std::string name   = this->GetDeviceName();
        return StartsWith(name, "gfx1") ? num_cu * 2 /* CUs per WGP */ : num_cu;
    }

    std::size_t m_MaxMemoryAllocSizeCached = 0;
    std::size_t GetMaxMemoryAllocSize();

    std::string GetDeviceName() const;
    const TargetProperties& GetTargetProperties() const;

private:
    std::string GetDeviceNameImpl() const;

public:
    std::ostream& Print(std::ostream& os) const;
    void Copy(ConstData_t src, Data_t dest, std::size_t size) const;

    Allocator::ManageDataPtr Create(std::size_t sz) const;
    Allocator::ManageDataPtr&
    WriteTo(const void* data, Allocator::ManageDataPtr& ddata, std::size_t sz) const;
    void ReadTo(void* data, const Allocator::ManageDataPtr& ddata, std::size_t sz) const;
    shared<Data_t> CreateSubBuffer(Data_t data, std::size_t offset, std::size_t size) const;
#if MIOPEN_BACKEND_HIP
    shared<ConstData_t>
    CreateSubBuffer(ConstData_t data, std::size_t offset, std::size_t size) const;
#endif

    template <class T>
    Allocator::ManageDataPtr Create(std::size_t sz)
    {
        return this->Create(sz * sizeof(T));
    }

    template <class Container>
    Allocator::ManageDataPtr Write(const Container& c)
    {
        using type = typename Container::value_type;
        auto buf   = this->Create<type>(c.size());
        return std::move(
            this->WriteTo(reinterpret_cast<const void*>(c.data()), buf, c.size() * sizeof(type)));
    }

    template <class T>
    std::vector<T> Read(const Allocator::ManageDataPtr& ddata, std::size_t sz)
    {
        std::vector<T> result(sz);
        this->ReadTo(result.data(), ddata, sz * sizeof(T));
        return result;
    }

    static std::string GetDbBasename(const TargetProperties& target, size_t num_cu)
    {
        auto ret = target.DbId() + [&]() {
            std::ostringstream ss;
            if(num_cu <= 64)
                ss << '_' << num_cu;
            else
                ss << std::hex << num_cu;
            return std::string(ss.str());
        }();
        return ret;
    }

    std::string GetDbBasename() const
    {
        return GetDbBasename(GetTargetProperties(), GetMaxComputeUnits());
    }

    std::unique_ptr<HandleImpl> impl;
    std::unordered_map<std::string, std::vector<miopenConvSolution_t>> find_map;
#if MIOPEN_USE_MIOPENGEMM
    std::unordered_map<GemmKey, std::unique_ptr<GemmGeometry>, SimpleHash> geo_map;
#endif

    Invoker PrepareInvoker(const InvokerFactory& factory,
                           const std::vector<solver::KernelInfo>& kernels) const;

    void RegisterInvoker(const Invoker& invoker,
                         const NetworkConfig& config,
                         const std::string& solver,
                         const boost::optional<AlgorithmName>& algo = boost::none)
    {
        invokers.Register({config, solver}, invoker);
        if(algo.has_value())
            invokers.SetAsFound1_0(config, *algo, solver);
    }

    boost::optional<const Invoker&>
    GetInvoker(const NetworkConfig& config,
               const boost::optional<solver::Id>& solver,
               const boost::optional<AlgorithmName>& algo = boost::none) const
    {
        assert(solver || algo);
        assert(!(solver && algo));
        if(solver)
        {
            MIOPEN_LOG_I2("Returning an invoker for problem " << config.ToString() << " and solver "
                                                              << solver->ToString());
            return invokers[std::make_pair(config.ToString(), solver->ToString())];
        }
        MIOPEN_LOG_I2("Returning an invoker for problem " << config.ToString() << " and algorithm "
                                                          << algo->ToString());
        return invokers.GetFound1_0(config, *algo);
    }

    boost::optional<const std::string&> GetFound1_0SolverId(const NetworkConfig& config,
                                                            const AlgorithmName& algo) const
    {
        return invokers.GetFound1_0SolverId(config, algo);
    }

#if MIOPEN_USE_ROCBLAS
    const rocblas_handle_ptr& rhandle() const { return rhandle_; }

private:
    rocblas_handle_ptr CreateRocblasHandle() const;
    rocblas_handle_ptr rhandle_;
#else
private:
#endif
    InvokerCache invokers;
};

inline std::ostream& operator<<(std::ostream& os, const Handle& handle) { return handle.Print(os); }

struct AutoEnableProfiling
{
    AutoEnableProfiling(const Handle& x) : h(x)
    {
        prev_state = h.IsProfilingEnabled();
        h.EnableProfiling();
    }

    ~AutoEnableProfiling()
    {
        h.EnableProfiling(prev_state);
        h.ResetKernelTime();
    }

private:
    const Handle& h;
    bool prev_state;
};

} // namespace miopen
MIOPEN_DEFINE_OBJECT(miopenHandle, miopen::Handle);

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

#include <miopen/config.h>
#include <miopen/kernel_info.hpp>
#include <miopen/common.hpp>
#include <miopen/invoker_cache.hpp>
#include <miopen/kernel.hpp>
#include <miopen/miopen.h>
#include <miopen/names.hpp>
#include <miopen/object.hpp>
#include <miopen/allocator.hpp>
#include <miopen/simple_hash.hpp>
#include <miopen/solver_id.hpp>
#include <miopen/stringutils.hpp>
#include <miopen/target_properties.hpp>

#include <boost/range/adaptor/transformed.hpp>

#include <cstdio>
#include <cstring>
#include <ios>
#include <sstream>
#include <memory>
#include <vector>
#include <unordered_map>

#if MIOPEN_USE_ROCBLAS
#include <miopen/manage_ptr.hpp>
#if MIOPEN_ROCBLAS_VERSION_FLAT < 2045000
#include <rocblas.h>
#else
#include <rocblas/rocblas.h>
#endif
#endif

namespace miopen {

struct HandleImpl;
#if MIOPEN_USE_MIOPENGEMM
struct GemmGeometry;
using GemmKey = std::pair<std::string, std::string>;
#endif

#if MIOPEN_USE_ROCBLAS
using rocblas_handle_ptr = MIOPEN_MANAGE_PTR(rocblas_handle, rocblas_destroy_handle);
#endif

struct Handle : miopenHandle
{
    friend struct TargetProperties;

    Handle();
    Handle(miopenAcceleratorQueue_t stream);
    Handle(Handle&&) noexcept;
    ~Handle();

    miopenAcceleratorQueue_t GetStream() const;
    void SetStream(miopenAcceleratorQueue_t streamID) const;

    void SetAllocator(miopenAllocatorFunction allocator,
                      miopenDeallocatorFunction deallocator,
                      void* allocatorContext) const;

    void EnableProfiling(bool enable = true) const;

    void ResetKernelTime() const;
    void AccumKernelTime(float curr_time) const;

    float GetKernelTime() const;
    bool IsProfilingEnabled() const;

    KernelInvoke AddKernel(const std::string& algorithm,
                           const std::string& network_config,
                           const std::string& program_name,
                           const std::string& kernel_name,
                           const std::vector<size_t>& vld,
                           const std::vector<size_t>& vgd,
                           const std::string& params,
                           std::size_t cache_index       = 0,
                           bool is_kernel_str            = false,
                           const std::string& kernel_src = "") const;

    bool HasKernel(const std::string& algorithm, const std::string& network_config) const;

    void ClearKernels(const std::string& algorithm, const std::string& network_config) const;

    auto GetKernels(const std::string& algorithm, const std::string& network_config) const
    {
        return this->GetKernelsImpl(algorithm, network_config) |
               boost::adaptors::transformed([this](Kernel k) { return this->Run(k); });
    }
    KernelInvoke GetKernel(const std::string& algorithm, const std::string& network_config) const
    {
        auto ks = this->GetKernelsImpl(algorithm, network_config);
        if(ks.empty())
        {
            MIOPEN_THROW("looking for default kernel (does not exist): " + algorithm + ", " +
                         network_config);
        }
        return this->Run(ks.front());
    }

    KernelInvoke Run(Kernel k) const;
    const std::vector<Kernel>& GetKernelsImpl(const std::string& algorithm,
                                              const std::string& network_config) const;

    Program LoadProgram(const std::string& program_name,
                        std::string params,
                        bool is_kernel_str,
                        const std::string& kernel_src) const;

    bool HasProgram(const std::string& program_name, const std::string& params) const;
    void ClearProgram(const std::string& program_name, const std::string& params) const;
    void AddProgram(Program prog, const std::string& program_name, const std::string& params) const;

    void Finish() const;
    void Flush() const;

    std::size_t GetLocalMemorySize() const;
    std::size_t GetGlobalMemorySize() const;
    std::size_t GetImage3dMaxWidth() const;
    std::size_t GetWavefrontWidth() const;
    std::size_t GetMaxComputeUnits() const;
    std::size_t GetMaxHardwareComputeUnits() const
    {
        std::size_t num_cu = this->GetMaxComputeUnits();
        std::string name   = this->GetDeviceName();
        return StartsWith(name, "gfx1") ? num_cu * 2 /* CUs per WGP */ : num_cu;
    }

    std::size_t m_MaxMemoryAllocSizeCached = 0;
    std::size_t GetMaxMemoryAllocSize();

    std::string GetDeviceName() const;
    const TargetProperties& GetTargetProperties() const;

private:
    std::string GetDeviceNameImpl() const;

public:
    std::ostream& Print(std::ostream& os) const;
    void Copy(ConstData_t src, Data_t dest, std::size_t size) const;

    Allocator::ManageDataPtr Create(std::size_t sz) const;
    Allocator::ManageDataPtr&
    WriteTo(const void* data, Allocator::ManageDataPtr& ddata, std::size_t sz) const;
    void ReadTo(void* data, const Allocator::ManageDataPtr& ddata, std::size_t sz) const;
    shared<Data_t> CreateSubBuffer(Data_t data, std::size_t offset, std::size_t size) const;
#if MIOPEN_BACKEND_HIP
    shared<ConstData_t>
    CreateSubBuffer(ConstData_t data, std::size_t offset, std::size_t size) const;
#endif

    template <class T>
    Allocator::ManageDataPtr Create(std::size_t sz)
    {
        return this->Create(sz * sizeof(T));
    }

    template <class Container>
    Allocator::ManageDataPtr Write(const Container& c)
    {
        using type = typename Container::value_type;
        auto buf   = this->Create<type>(c.size());
        return std::move(
            this->WriteTo(reinterpret_cast<const void*>(c.data()), buf, c.size() * sizeof(type)));
    }

    template <class T>
    std::vector<T> Read(const Allocator::ManageDataPtr& ddata, std::size_t sz)
    {
        std::vector<T> result(sz);
        this->ReadTo(result.data(), ddata, sz * sizeof(T));
        return result;
    }

    static std::string GetDbBasename(const TargetProperties& target, size_t num_cu)
    {
        auto ret = target.DbId() + [&]() {
            std::ostringstream ss;
            if(num_cu <= 64)
                ss << '_' << num_cu;
            else
                ss << std::hex << num_cu;
            return std::string(ss.str());
        }();
        return ret;
    }

    std::string GetDbBasename() const
    {
        return GetDbBasename(GetTargetProperties(), GetMaxComputeUnits());
    }

    std::unique_ptr<HandleImpl> impl;
    std::unordered_map<std::string, std::vector<miopenConvSolution_t>> find_map;
#if MIOPEN_USE_MIOPENGEMM
    std::unordered_map<GemmKey, std::unique_ptr<GemmGeometry>, SimpleHash> geo_map;
#endif

    Invoker PrepareInvoker(const InvokerFactory& factory,
                           const std::vector<solver::KernelInfo>& kernels) const;

    void RegisterInvoker(const Invoker& invoker,
                         const NetworkConfig& config,
                         const std::string& solver,
                         const boost::optional<AlgorithmName>& algo = boost::none)
    {
        invokers.Register({config, solver}, invoker);
        if(algo.has_value())
            invokers.SetAsFound1_0(config, *algo, solver);
    }

    boost::optional<const Invoker&>
    GetInvoker(const NetworkConfig& config,
               const boost::optional<solver::Id>& solver,
               const boost::optional<AlgorithmName>& algo = boost::none) const
    {
        assert(solver || algo);
        assert(!(solver && algo));
        if(solver)
        {
            MIOPEN_LOG_I2("Returning an invoker for problem " << config.ToString() << " and solver "
                                                              << solver->ToString());
            return invokers[std::make_pair(config.ToString(), solver->ToString())];
        }
        MIOPEN_LOG_I2("Returning an invoker for problem " << config.ToString() << " and algorithm "
                                                          << algo->ToString());
        return invokers.GetFound1_0(config, *algo);
    }

    boost::optional<const std::string&> GetFound1_0SolverId(const NetworkConfig& config,
                                                            const AlgorithmName& algo) const
    {
        return invokers.GetFound1_0SolverId(config, algo);
    }

#if MIOPEN_USE_ROCBLAS
    const rocblas_handle_ptr& rhandle() const { return rhandle_; }

private:
    rocblas_handle_ptr CreateRocblasHandle() const;
    rocblas_handle_ptr rhandle_;
#else
private:
#endif
    InvokerCache invokers;
};

inline std::ostream& operator<<(std::ostream& os, const Handle& handle) { return handle.Print(os); }

struct AutoEnableProfiling
{
    AutoEnableProfiling(const Handle& x) : h(x)
    {
        prev_state = h.IsProfilingEnabled();
        h.EnableProfiling();
    }

    ~AutoEnableProfiling()
    {
        h.EnableProfiling(prev_state);
        h.ResetKernelTime();
    }

private:
    const Handle& h;
    bool prev_state;
};

} // namespace miopen
MIOPEN_DEFINE_OBJECT(miopenHandle, miopen::Handle);

#endif // GUARD_MIOPEN_HANDLE_HPP_
<|endoftext|>


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

#ifndef __TYTI_STEAM_VDF_PARSER_H__
#define __TYTI_STEAM_VDF_PARSER_H__

#include <unordered_map>
#include <utility>
#include <fstream>
#include <memory>

#include <system_error>
#include <exception>

//for wstring support
#include <locale>
#include <codecvt>
#include <string>

// internal
#include <stack>

//VS < 2015 has only partial C++11 support
#if defined(_MSC_VER) && _MSC_VER < 1900
#ifndef CONSTEXPR
#define CONSTEXPR
#endif

#ifndef NOEXCEPT
#define NOEXCEPT
#endif
#else
#ifndef CONSTEXPR
#define CONSTEXPR constexpr
#define TYTI_UNDEF_CONSTEXPR
#endif

#ifndef NOEXCEPT
#define NOEXCEPT noexcept
#define TYTI_UNDEF_NOEXCEPT
#endif

#endif

namespace tyti
{
    namespace vdf
    {
        namespace detail
        {
            ///////////////////////////////////////////////////////////////////////////
            //  Helper functions selecting the right encoding (char/wchar_T)
            ///////////////////////////////////////////////////////////////////////////

            template<typename T>
            struct literal_macro_help
            {
                static CONSTEXPR const char* result(const char* c, const wchar_t* wc) NOEXCEPT
                {
                    return c;
                }
                static CONSTEXPR const char result(const char c, const wchar_t wc) NOEXCEPT
                {
                    return c;
                }
            };

            template<>
            struct literal_macro_help<wchar_t>
            {
                static CONSTEXPR const wchar_t* result(const char* c, const wchar_t* wc) NOEXCEPT
                {
                    return wc;
                }
                static CONSTEXPR const wchar_t result(const char c, const wchar_t wc) NOEXCEPT
                {
                    return wc;
                }
            };
#define TYTI_L(type, text) vdf::detail::literal_macro_help<type>::result(text, L##text)

            inline std::string string_converter(const std::string& w) NOEXCEPT
            {
                return w;
            }

            inline std::string string_converter(const std::wstring& w)
            {
                std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1; // maybe wrong econding
                return conv1.to_bytes(w);
            }

            ///////////////////////////////////////////////////////////////////////////
            //  Writer helper functions
            ///////////////////////////////////////////////////////////////////////////

            template<typename charT>
            class tabs
            {
                size_t t;
            public:
                explicit tabs(size_t i) :t( i ) {}
                std::basic_string<charT> print() const { return std::basic_string<charT>(t, TYTI_L(charT,'\t')); }
                tabs operator+(size_t i) const NOEXCEPT
                {
                    tabs r(*this);
                    r.t += i;
                    return r;
                }
            };

            template<typename oStreamT>
            oStreamT& operator<<(oStreamT& s, const tabs<typename oStreamT::char_type> t)
            {
                s << t.print();
                return s;
            }
        } // end namespace detail

        ///////////////////////////////////////////////////////////////////////////
        //  Interface
        ///////////////////////////////////////////////////////////////////////////

        /// basic object node. Every object has a name and can contains attributes saved as key_value pairs or childrens
        template<typename CharT>
        struct basic_object
        {
            typedef CharT char_type;
            std::basic_string<char_type> name;
            std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type> > attribs;
            std::unordered_map<std::basic_string<char_type>, std::shared_ptr< basic_object<char_type> > > childs;
        };

        typedef basic_object<char> object;
        typedef basic_object<wchar_t> wobject;

        /** \brief writes given object tree in vdf format to given stream.
        Uses tabs instead of whitespaces.
        */
        template<typename oStreamT>
        void write(oStreamT& s, const basic_object<typename oStreamT::char_type>& r,
            const detail::tabs<typename oStreamT::char_type> tab = detail::tabs<typename oStreamT::char_type>( 0 ))
        {
            typedef typename oStreamT::char_type charT;
            using namespace detail;
            typedef tabs<charT> tabs;
            s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab << TYTI_L(charT, "{\n");
            for (const auto& i : r.attribs)
                s << tab+1 << TYTI_L(charT, '"') << i.first << TYTI_L(charT, "\"\t\t\"") << i.second << TYTI_L(charT, "\"\n");
            for (const auto& i : r.childs)
                write(s, *i.second, tab+1 );
            s << tab << TYTI_L(charT, "}\n");
        }

        //forward decls
        //forward decl
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream, std::error_code& ec);

        /** \brief Read VDF formatted sequences defined by the range [first, last).
        If the file is mailformatted, parser will try to read it until it can.
        @param first begin iterator
        @param end end iterator
        @param ec output bool. 0 if ok, otherwise, holds an system error code

        Possible error codes:
            std::errc::protocol_error: file is mailformatted
            std::errc::not_enough_memory: not enough space
            std::errc::invalid_argument: iterators throws e.g. out of range
        */

        template<typename IterT>
        basic_object<typename IterT::value_type> read(IterT first, IterT last, std::error_code& ec) NOEXCEPT
        {
            typedef typename IterT::value_type charT;
            ec.clear();

            basic_object<charT> root;
            basic_object<charT>* cur = &root;
            std::stack< basic_object<charT>* > lvls;
            //read header
            // first, quoted name
            auto b = std::find(first, last, TYTI_L(charT, '\"'));
            auto bend = std::find(b + 1, last, TYTI_L(charT, '\"'));
            root.name = std::basic_string<charT>(b + 1, bend);
            // second, get {}
            b = std::find(bend, last, TYTI_L(charT, '{'));
            try
            {
                if (b == last)
                {
                    ec = std::make_error_code(std::errc::protocol_error);
                    return root;
                }
                else
                    lvls.push(&root);
                while (!lvls.empty() && b != last)
                {
                    const std::basic_string<charT> startsym = TYTI_L(charT, "\"}");

                    //find first starting attrib/child, or ending
                    b = std::find_first_of(b, last, std::begin(startsym), std::end(startsym));
                    if (*b == '\"')
                    {

                        // get key
                        bend = std::find(b + 1, last, TYTI_L(charT, '\"'));
                        if (bend == last)
                        {
                            ec = std::make_error_code(std::errc::protocol_error);// could not find end of name
                            return root;
                        }

                        std::basic_string<charT> key(b + 1, bend);
                        b = bend + 1;

                        const std::basic_string<charT> ecspsym = TYTI_L(charT, "\"{");
                        b = std::find_first_of(b, last, std::begin(ecspsym), std::end(ecspsym));
                        if (b == last)
                        {
                            ec = std::make_error_code(std::errc::protocol_error);// could not find 2nd part of pair
                            return root;
                        }

                        // get value
                        if (*b == '\"')
                        {
                            bend = std::find(b + 1, last, TYTI_L(charT, '\"'));
                            if (bend == last)
                            {
                                ec = std::make_error_code(std::errc::protocol_error);//could not find end of name
                                return root;
                            }

                            auto value = std::basic_string<charT>(b + 1, bend);
                            b = bend + 1;

                            // process value
                            if (key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base"))
                            {
                                cur->attribs[key] = std::move(value);
                            }
                            else
                            {
                                std::basic_ifstream<charT> i(detail::string_converter(std::move(value)));
                                auto n = std::make_shared<basic_object<charT>>(read(i, ec));
                                if (ec) return root;
                                cur->childs[n->name] = std::move(n);
                            }
                        }
                        else if (*b == '{')
                        {
                            lvls.push(cur);
                            auto n = std::make_shared<basic_object<charT>>();
                            cur->childs[key] = n;
                            cur = n.get();
                            cur->name = std::move(key);
                            ++b;
                        }
                    }
                    else if (*b == '}')
                    {
                        cur = lvls.top();
                        lvls.pop();
                        ++b;
                    }
                }

            }
            catch (std::bad_alloc& )
            {
                ec = std::make_error_code(std::errc::not_enough_memory);
            }
            catch (...)
            {
                ec = std::make_error_code(std::errc::invalid_argument);
            }
            return root;
        }

        /** \brief Read VDF formatted sequences defined by the range [first, last).
        If the file is mailformatted, parser will try to read it until it can.
        @param first begin iterator
        @param end end iterator
        @param ok output bool. true, if parser successed, false, if parser failed
        */
        template<typename IterT>
        basic_object<typename IterT::value_type> read(IterT first, const IterT last, bool* ok) NOEXCEPT
        {
            std::error_code ec;
            auto r = read(first, last, ec);
            if (ok) *ok = !ec;
            return r;
        }

        /** \brief Read VDF formatted sequences defined by the range [first, last).
        If the file is mailformatted, parser will try to read it until it can.
        @param first begin iterator
        @param end end iterator

        throws a "std::system_error" if a parsing error occured
        */
        template<typename IterT>
        basic_object<typename IterT::value_type> read(IterT first, const IterT last)
        {
            std::error_code ec;
            const auto r = read(first, last, ec);
            if (!ec)
                throw std::system_error(ec);
            return r;
        }

        /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
            throws "std::bad_alloc" if file buffer could not be allocated
        */
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream, std::error_code& ec)
        {
            // cache the file
            typedef typename iStreamT::char_type charT;
            std::basic_string<charT> str;
            inStream.seekg(0, std::ios::end);
            str.resize(static_cast<size_t>(inStream.tellg()));
            if (str.empty())
                return basic_object<charT>();

            inStream.seekg(0, std::ios::beg);
            inStream.read(&str[0], str.size());
            inStream.close();

            // parse it
            return read(str.begin(), str.end(), ec);
        }

        /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
            throws "std::bad_alloc" if file buffer could not be allocated
            ok == false, if a parsing error occured
        */
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream, bool* ok)
        {
            std::error_code ec;
            const auto r = read(inStream, ec);
            if (ok) *ok = !ec;
            return r;
        }

        /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
            throws "std::bad_alloc" if file buffer could not be allocated
            throws "std::system_error" if a parsing error occured
        */
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream)
        {
            std::error_code ec;
            const auto r = read(inStream, ec);
            if (!ec) throw std::system_error(ec);
            return r;
        }

    } // end namespace vdf
} // end namespace tyti
#ifndef TYTI_NO_L_UNDEF
#undef TYTI_L
#endif

#ifdef TYTI_UNDEF_CONSTEXPR
#undef CONSTEXPR
#endif

#ifdef TYTI_UNDEF_NOTHROW
#undef NOTHROW
#endif

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

#ifndef __TYTI_STEAM_VDF_PARSER_H__
#define __TYTI_STEAM_VDF_PARSER_H__

#include <unordered_map>
#include <utility>
#include <fstream>
#include <memory>

#include <system_error>
#include <exception>

//for wstring support
#include <locale>
#include <codecvt>
#include <string>

// internal
#include <stack>

//VS < 2015 has only partial C++11 support
#if defined(_MSC_VER) && _MSC_VER < 1900
#ifndef CONSTEXPR
#define CONSTEXPR
#endif

#ifndef NOEXCEPT
#define NOEXCEPT
#endif
#else
#ifndef CONSTEXPR
#define CONSTEXPR constexpr
#define TYTI_UNDEF_CONSTEXPR
#endif

#ifndef NOEXCEPT
#define NOEXCEPT noexcept
#define TYTI_UNDEF_NOEXCEPT
#endif

#endif

namespace tyti
{
    namespace vdf
    {
        namespace detail
        {
            ///////////////////////////////////////////////////////////////////////////
            //  Helper functions selecting the right encoding (char/wchar_T)
            ///////////////////////////////////////////////////////////////////////////

            template<typename T>
            struct literal_macro_help
            {
                static CONSTEXPR const char* result(const char* c, const wchar_t* wc) NOEXCEPT
                {
                    return c;
                }
                static CONSTEXPR const char result(const char c, const wchar_t wc) NOEXCEPT
                {
                    return c;
                }
            };

            template<>
            struct literal_macro_help<wchar_t>
            {
                static CONSTEXPR const wchar_t* result(const char* c, const wchar_t* wc) NOEXCEPT
                {
                    return wc;
                }
                static CONSTEXPR const wchar_t result(const char c, const wchar_t wc) NOEXCEPT
                {
                    return wc;
                }
            };
#define TYTI_L(type, text) vdf::detail::literal_macro_help<type>::result(text, L##text)

            inline std::string string_converter(const std::string& w) NOEXCEPT
            {
                return w;
            }

            inline std::string string_converter(const std::wstring& w)
            {
                std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1; // maybe wrong econding
                return conv1.to_bytes(w);
            }

            ///////////////////////////////////////////////////////////////////////////
            //  Writer helper functions
            ///////////////////////////////////////////////////////////////////////////

            template<typename charT>
            class tabs
            {
                size_t t;
            public:
                explicit tabs(size_t i) :t( i ) {}
                std::basic_string<charT> print() const { return std::basic_string<charT>(t, TYTI_L(charT,'\t')); }
                tabs operator+(size_t i) const NOEXCEPT
                {
                    tabs r(*this);
                    r.t += i;
                    return r;
                }
            };

            template<typename oStreamT>
            oStreamT& operator<<(oStreamT& s, const tabs<typename oStreamT::char_type> t)
            {
                s << t.print();
                return s;
            }
        } // end namespace detail

        ///////////////////////////////////////////////////////////////////////////
        //  Interface
        ///////////////////////////////////////////////////////////////////////////

        /// basic object node. Every object has a name and can contains attributes saved as key_value pairs or childrens
        template<typename CharT>
        struct basic_object
        {
            typedef CharT char_type;
            std::basic_string<char_type> name;
            std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type> > attribs;
            std::unordered_map<std::basic_string<char_type>, std::shared_ptr< basic_object<char_type> > > childs;
        };

        typedef basic_object<char> object;
        typedef basic_object<wchar_t> wobject;

        /** \brief writes given object tree in vdf format to given stream.
        Uses tabs instead of whitespaces.
        */
        template<typename oStreamT>
        void write(oStreamT& s, const basic_object<typename oStreamT::char_type>& r,
            const detail::tabs<typename oStreamT::char_type> tab = detail::tabs<typename oStreamT::char_type>( 0 ))
        {
            typedef typename oStreamT::char_type charT;
            using namespace detail;
            typedef tabs<charT> tabs;
            s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab << TYTI_L(charT, "{\n");
            for (const auto& i : r.attribs)
                s << tab+1 << TYTI_L(charT, '"') << i.first << TYTI_L(charT, "\"\t\t\"") << i.second << TYTI_L(charT, "\"\n");
            for (const auto& i : r.childs)
                write(s, *i.second, tab+1 );
            s << tab << TYTI_L(charT, "}\n");
        }

        //forward decls
        //forward decl
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream, std::error_code& ec);

        /** \brief Read VDF formatted sequences defined by the range [first, last).
        If the file is mailformatted, parser will try to read it until it can.
        @param first begin iterator
        @param end end iterator
        @param ec output bool. 0 if ok, otherwise, holds an system error code

        Possible error codes:
            std::errc::protocol_error: file is mailformatted
            std::errc::not_enough_memory: not enough space
            std::errc::invalid_argument: iterators throws e.g. out of range
        */

        template<typename IterT>
        basic_object<typename IterT::value_type> read(IterT first, IterT last, std::error_code& ec) NOEXCEPT
        {
            typedef typename IterT::value_type charT;
            ec.clear();

            basic_object<charT> root;
            basic_object<charT>* cur = &root;
            std::stack< basic_object<charT>* > lvls;
            //read header
            // first, quoted name
            auto b = std::find(first, last, TYTI_L(charT, '\"'));
            auto bend = std::find(b + 1, last, TYTI_L(charT, '\"'));
            root.name = std::basic_string<charT>(b + 1, bend);
            // second, get {}
            b = std::find(bend, last, TYTI_L(charT, '{'));
            try
            {
                if (b == last)
                {
                    ec = std::make_error_code(std::errc::protocol_error);
                    return root;
                }
                else
                    lvls.push(&root);
                while (!lvls.empty() && b != last)
                {
                    const std::basic_string<charT> startsym = TYTI_L(charT, "\"}");

                    //find first starting attrib/child, or ending
                    b = std::find_first_of(b, last, std::begin(startsym), std::end(startsym));
                    if (*b == '\"')
                    {

                        // get key
                        bend = std::find(b + 1, last, TYTI_L(charT, '\"'));
                        if (bend == last)
                        {
                            ec = std::make_error_code(std::errc::protocol_error);// could not find end of name
                            return root;
                        }

                        std::basic_string<charT> key(b + 1, bend);
                        b = bend + 1;

                        const std::basic_string<charT> ecspsym = TYTI_L(charT, "\"{");
                        b = std::find_first_of(b, last, std::begin(ecspsym), std::end(ecspsym));
                        if (b == last)
                        {
                            ec = std::make_error_code(std::errc::protocol_error);// could not find 2nd part of pair
                            return root;
                        }

                        // get value
                        if (*b == '\"')
                        {
                            bend = std::find(b + 1, last, TYTI_L(charT, '\"'));
                            if (bend == last)
                            {
                                ec = std::make_error_code(std::errc::protocol_error);//could not find end of name
                                return root;
                            }

                            auto value = std::basic_string<charT>(b + 1, bend);
                            b = bend + 1;

                            // process value
                            if (key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base"))
                            {
                                cur->attribs[key] = std::move(value);
                            }
                            else
                            {
                                std::basic_ifstream<charT> i(detail::string_converter(std::move(value)));
                                auto n = std::make_shared<basic_object<charT>>(read(i, ec));
                                if (ec) return root;
                                cur->childs[n->name] = std::move(n);
                            }
                        }
                        else if (*b == '{')
                        {
                            lvls.push(cur);
                            auto n = std::make_shared<basic_object<charT>>();
                            cur->childs[key] = n;
                            cur = n.get();
                            cur->name = std::move(key);
                            ++b;
                        }
                    }
                    else if (*b == '}')
                    {
                        cur = lvls.top();
                        lvls.pop();
                        ++b;
                    }
                }

            }
            catch (std::bad_alloc& )
            {
                ec = std::make_error_code(std::errc::not_enough_memory);
            }
            catch (...)
            {
                ec = std::make_error_code(std::errc::invalid_argument);
            }
            return root;
        }

        /** \brief Read VDF formatted sequences defined by the range [first, last).
        If the file is mailformatted, parser will try to read it until it can.
        @param first begin iterator
        @param end end iterator
        @param ok output bool. true, if parser successed, false, if parser failed
        */
        template<typename IterT>
        basic_object<typename IterT::value_type> read(IterT first, const IterT last, bool* ok) NOEXCEPT
        {
            std::error_code ec;
            auto r = read(first, last, ec);
            if (ok) *ok = !ec;
            return r;
        }

        /** \brief Read VDF formatted sequences defined by the range [first, last).
        If the file is mailformatted, parser will try to read it until it can.
        @param first begin iterator
        @param end end iterator

        throws a "std::system_error" if a parsing error occured
        */
        template<typename IterT>
        basic_object<typename IterT::value_type> read(IterT first, const IterT last)
        {
            std::error_code ec;
            const auto r = read(first, last, ec);
            if (!ec)
                throw std::system_error(ec);
            return r;
        }

        /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
            throws "std::bad_alloc" if file buffer could not be allocated
        */
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream, std::error_code& ec)
        {
            // cache the file
            typedef typename iStreamT::char_type charT;
            std::basic_string<charT> str;
            inStream.seekg(0, std::ios::end);
            str.resize(static_cast<size_t>(inStream.tellg()));
            if (str.empty())
                return basic_object<charT>();

            inStream.seekg(0, std::ios::beg);
            inStream.read(&str[0], str.size());
            inStream.close();

            // parse it
            return read(str.begin(), str.end(), ec);
        }

        /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
            throws "std::bad_alloc" if file buffer could not be allocated
            ok == false, if a parsing error occured
        */
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream, bool* ok)
        {
            std::error_code ec;
            const auto r = read(inStream, ec);
            if (ok) *ok = !ec;
            return r;
        }

        /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
            throws "std::bad_alloc" if file buffer could not be allocated
            throws "std::system_error" if a parsing error occured
        */
        template<typename iStreamT>
        basic_object<typename iStreamT::char_type> read(iStreamT& inStream)
        {
            std::error_code ec;
            const auto r = read(inStream, ec);
            if (!ec) throw std::system_error(ec);
            return r;
        }

    } // end namespace vdf
} // end namespace tyti
#ifndef TYTI_NO_L_UNDEF
#undef TYTI_L
#endif

#ifdef TYTI_UNDEF_CONSTEXPR
#undef CONSTEXPR
#undef TYTI_NO_L_UNDEF
#endif

#ifdef TYTI_UNDEF_NOTHROW
#undef NOTHROW
#undef TYTI_UNDEF_NOTHROW
#endif

#endif //__TYTI_STEAM_VDF_PARSER_H__
<|endoftext|>


<commit_before>/* indivudal.cpp - CS 472 Project #2: Genetic Programming
 * Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for individual namespace
 */

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <memory>
#include <tuple>
#include <vector>

#include "individual.hpp"
#include "../options/options.hpp"
#include "../random_generator/random_generator.hpp"

namespace individual {
  using std::vector;
  using std::string;
  using options::Options;
  using namespace random_generator;

  // vectors of same-arity function enums
  vector<Function> nullaries{constant, input};
  vector<Function> unaries{sqrt, sin, cos, log, exp};
  vector<Function> binaries{add, subtract, multiply, divide, pow};
  vector<Function> quadnaries{lesser, greater};
  vector<Function> internals{sin, cos, add, subtract, multiply, divide, lesser, greater};

  template<typename I, typename S> bool contains(const I & item, const S & set) {
    return std::find(set.begin(), set.end(), item) != set.end();
  }

  Function get_internal() {
    int_dist dist{0, int(internals.size()) - 1}; // closed interval
    return Function(internals[dist(rg.engine)]);
  }

  Function get_leaf() {
    int_dist dist{0, int(nullaries.size()) - 1}; // closed interval
    return Function(nullaries[dist(rg.engine)]);
  }

  double get_constant(const double & min, const double & max) {
    real_dist dist{min, max};
    return dist(rg.engine);
  }

  int get_arity(const Function & function) {
    if (contains(function, nullaries)) return 0;
    else if (contains(function, unaries)) return 1;
    else if (contains(function, binaries)) return 2;
    else if (contains(function, quadnaries)) return 4;
    assert(false);
  }

  Node::Node(const Options & options, const Method & method, const int & max_depth) {
    real_dist dist{0, 1};
    double grow_chance = double(nullaries.size()) / double(nullaries.size() + internals.size());
    if (max_depth == 0 or (method == grow and dist(rg.engine) < grow_chance)) {
      function = get_leaf();
      arity = get_arity(function);
      assert(arity == 0);
      // setup constant function; input is provided on evaluation
      if (function == constant) {
	// choose a random value between the options's min and max
	k = get_constant(options.constant_min, options.constant_max);
      }
    }
    else {
      function = get_internal();
      assert(contains(function, internals));
      // determine node's arity
      arity = get_arity(function);
      assert(arity != 0);
      // recursively create subtrees
      for (int i = 0; i < arity; ++i)
	children.emplace_back(Node{options, method, max_depth - 1});
    }
    assert(int(children.size()) == arity); // ensure arity
    assert(function != null); // do not create null types
  }

  string Node::represent() const {
    switch(function) {
    case null:
      assert(false); // never represent empty node
    case constant:
      return std::to_string(k);
    case input:
      return "x";
    case sqrt:
      return "sqrt";
    case sin:
      return "sin";
    case cos:
      return "cos";
    case log:
      return "log";
    case exp:
      return "exp";
    case add:
      return "+";
    case subtract:
      return "-";
    case multiply:
      return "*";
    case divide:
      return "%";
    case pow:
      return "^";
    case lesser:
      return "<";
    case greater:
      return ">";
    }
    assert(false);
  }

  string Node::print() const {
    // Pre-order traversal print of expression in Polish/prefix notation
    if (children.size() == 0) return represent();
    string formula = "(" + represent();
    for (const Node & child : children)
      formula += " " + child.print();
    return formula + ")";
  }

  double Node::evaluate(const double & x) const {
    // depth-first post-order recursive evaluation tree
    double a, b;
    if (arity == 1)
      a = children[0].evaluate(x);
    else if (arity == 2 or arity == 4) {
      // children c and d are evaluated conditionally
      a = children[0].evaluate(x);
      b = children[1].evaluate(x);
    }
    // calculate the result
    switch(function) {
    case null:
      assert(false); // never calculate empty node
    case constant:
      assert(arity == 0);
      return k;
    case input:
      assert(arity == 0);
      return x;
    case sqrt:
      assert(arity == 1);
      return std::sqrt(std::abs(a)); // protected
    case sin:
      assert(arity == 1);
      return std::sin(a);
    case cos:
      assert(arity == 1);
      return std::cos(a);
    case log:
      assert(arity == 1);
      return (a == 0) ? 0 : std::log(std::abs(a)); // protected
    case exp:
      assert(arity == 1);
      return std::exp(a);
    case add:
      assert(arity == 2);
      return a + b;
    case subtract:
      assert(arity == 2);
      return a - b;
    case multiply:
      assert(arity == 2);
      return a * b;
    case divide:
      assert(arity == 2);
      return (b == 0) ? 1 : a / b; // protected
    case pow:
      assert(arity == 2);
      return std::pow(std::abs(a), std::abs(b)); // protected
    case lesser:
      assert(arity == 4);
      return (a < b) ? children[2].evaluate(x) : children[3].evaluate(x);
    case greater:
      assert(arity == 4);
      return (a > b) ? children[2].evaluate(x) : children[3].evaluate(x);
    }
    assert(false);
  }

  const Size Node::size() const {
    // recursively count children via post-order traversal
    // keep track of internals and leafs via Size struct
    Size size;
    for (const Node & child : children) {
      Size temp = child.size(); // is this micro-optimizing?
      size.internals += temp.internals;
      size.leafs += temp.leafs;
    }
    if (children.size() == 0) ++size.leafs;
    else ++size.internals;
    return size;
  }

  Node empty;

  Node & Node::visit(const Size & i, Size & visiting) {
    // depth-first search for taget node, either internal or leaf
    for (Node & child : children) {
      // increase relevant count
      if (child.children.size() == 0) ++visiting.leafs;
      else ++visiting.internals;
      // return node reference if found
      if (visiting.internals == i.internals or visiting.leafs == i.leafs)
	return child;
      Node & temp = child.visit(i, visiting); // mark each node
      if (temp.function != null) return temp; // return found node
    }
    return empty; // need to indicate "not-found"
  }

  void Node::mutate_self() {
    // single node mutation to different function of same arity
    if (arity == 0) {
      // mutate constant to a value in its neighborhood, don't switch functions
      if (function == constant) {
	normal_dist dist{0, 1};
	k *= 1 + dist(rg.engine);
      }
    }
    else if (arity == 1) {
      int_dist dist{0, int(unaries.size()) - 1};
      Function prior = function;
      // ensure we're using a specified available function
      while (function == prior or not contains(function, internals))
	function = Function(unaries[dist(rg.engine)]);
    }
    else if (arity == 2) {
      int_dist dist{0, int(binaries.size()) - 1};
      Function prior = function;
      while (function == prior or not contains(function, internals))
	function = Function(binaries[dist(rg.engine)]);
    }
    else if (arity == 4) {
      int_dist dist{0, int(quadnaries.size()) - 1};
      Function prior = function;
      while (function == prior or not contains(function, internals))
	function = Function(quadnaries[dist(rg.engine)]);
    }
    assert(function != null);
  }

  void Node::mutate_tree(const double & chance) {
    // recursively mutate nodes with options.mutate_chance probability
    real_dist dist{0, 1};
    for (Node & child : children) {
      if (dist(rg.engine) < chance) child.mutate_self();
      child.mutate_tree(chance);
    }
  }

  Individual::Individual(const Options & options, const Method method, const int depth): root{Node{options, method, depth}} {
    evaluate(options.values);
  }

  string Individual::print() const {
    using std::to_string;
    string info = "Size " + to_string(get_total())
      + ", with " + to_string(get_internals())
      + " internals, and " + to_string(get_leafs()) + " leafs.\n"
      + "Raw fitness: " + to_string(get_fitness())
      + ", and adjusted: " + to_string(get_adjusted()) + ".\n";
    return info;
  }

  string Individual::print_formula() const {
    return "Formula: " + root.print() + "\n";
  }

  string Individual::evaluate(const options::pairs & values, const double & penalty, const bool & print) {
    using std::to_string;
    using std::get;
    string calculation = "# x - y - expected - error\n";
    // update size on evaluation because it's incredibly convenient
    size = root.size();
    fitness = penalty * get_total(); // reset fitness and apply scaled size penalty
    for (auto pair : values) {
      double x = std::get<0>(pair);
      double y = root.evaluate(x);
      assert(not std::isnan(y) and not std::isinf(y));
      double expected = std::get<1>(pair);
      double error = std::pow(y - expected, 2);
      fitness += error;
      if (print)
	calculation += to_string(x) + "\t"
	  + to_string(y) + "\t"
	  + to_string(expected) + "\t"
	  + to_string(error) + "\n";
    }
    return calculation;
  }

  void Individual::mutate(const double & chance) {
    // mutate each node with a options.mutate_chance probability
    root.mutate_tree(chance);
  }

  Node & Individual::operator[](const Size & i) {
    assert(i.internals <= get_internals());
    assert(i.leafs <= get_leafs());
    Size visiting;
    if (i.internals == 0 and i.leafs == 0) // seeking root
      return root;
    return root.visit(i, visiting);
  }

  void crossover(const double & chance, Individual & a, Individual & b) {
    real_dist probability{0, 1};
    Size target_a, target_b;
    // guaranteed to have at least 1 leaf, but may have 0 internals (root as leaf)
    if (a.get_internals() != 0 and probability(rg.engine) < chance) {
      // choose an internal node
      int_dist dist{0, a.get_internals() - 1};
      target_a.internals = dist(rg.engine);
    } else {
      // otherwise we choose a leaf node
      int_dist dist{0, a.get_leafs() - 1};
      target_a.leafs = dist(rg.engine);
    }
    // do the same thing for the second individual
    if (b.get_internals() != 0 and probability(rg.engine) < chance) {
      int_dist dist{0, b.get_internals() - 1};
      target_b.internals = dist(rg.engine);
    } else {
      int_dist dist{0, b.get_leafs() - 1};
      target_b.leafs = dist(rg.engine);
    }
    // replace nodes
    std::swap(a[target_a], b[target_b]);
  }
}
<commit_msg>Prepending "#" to lines from print() and print_formula()<commit_after>/* indivudal.cpp - CS 472 Project #2: Genetic Programming
 * Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for individual namespace
 */

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <memory>
#include <tuple>
#include <vector>

#include "individual.hpp"
#include "../options/options.hpp"
#include "../random_generator/random_generator.hpp"

namespace individual {
  using std::vector;
  using std::string;
  using options::Options;
  using namespace random_generator;

  // vectors of same-arity function enums
  vector<Function> nullaries{constant, input};
  vector<Function> unaries{sqrt, sin, cos, log, exp};
  vector<Function> binaries{add, subtract, multiply, divide, pow};
  vector<Function> quadnaries{lesser, greater};
  vector<Function> internals{sin, cos, add, subtract, multiply, divide, lesser, greater};

  template<typename I, typename S> bool contains(const I & item, const S & set) {
    return std::find(set.begin(), set.end(), item) != set.end();
  }

  Function get_internal() {
    int_dist dist{0, int(internals.size()) - 1}; // closed interval
    return Function(internals[dist(rg.engine)]);
  }

  Function get_leaf() {
    int_dist dist{0, int(nullaries.size()) - 1}; // closed interval
    return Function(nullaries[dist(rg.engine)]);
  }

  double get_constant(const double & min, const double & max) {
    real_dist dist{min, max};
    return dist(rg.engine);
  }

  int get_arity(const Function & function) {
    if (contains(function, nullaries)) return 0;
    else if (contains(function, unaries)) return 1;
    else if (contains(function, binaries)) return 2;
    else if (contains(function, quadnaries)) return 4;
    assert(false);
  }

  Node::Node(const Options & options, const Method & method, const int & max_depth) {
    real_dist dist{0, 1};
    double grow_chance = double(nullaries.size()) / double(nullaries.size() + internals.size());
    if (max_depth == 0 or (method == grow and dist(rg.engine) < grow_chance)) {
      function = get_leaf();
      arity = get_arity(function);
      assert(arity == 0);
      // setup constant function; input is provided on evaluation
      if (function == constant) {
	// choose a random value between the options's min and max
	k = get_constant(options.constant_min, options.constant_max);
      }
    }
    else {
      function = get_internal();
      assert(contains(function, internals));
      // determine node's arity
      arity = get_arity(function);
      assert(arity != 0);
      // recursively create subtrees
      for (int i = 0; i < arity; ++i)
	children.emplace_back(Node{options, method, max_depth - 1});
    }
    assert(int(children.size()) == arity); // ensure arity
    assert(function != null); // do not create null types
  }

  string Node::represent() const {
    switch(function) {
    case null:
      assert(false); // never represent empty node
    case constant:
      return std::to_string(k);
    case input:
      return "x";
    case sqrt:
      return "sqrt";
    case sin:
      return "sin";
    case cos:
      return "cos";
    case log:
      return "log";
    case exp:
      return "exp";
    case add:
      return "+";
    case subtract:
      return "-";
    case multiply:
      return "*";
    case divide:
      return "%";
    case pow:
      return "^";
    case lesser:
      return "<";
    case greater:
      return ">";
    }
    assert(false);
  }

  string Node::print() const {
    // Pre-order traversal print of expression in Polish/prefix notation
    if (children.size() == 0) return represent();
    string formula = "(" + represent();
    for (const Node & child : children)
      formula += " " + child.print();
    return formula + ")";
  }

  double Node::evaluate(const double & x) const {
    // depth-first post-order recursive evaluation tree
    double a, b;
    if (arity == 1)
      a = children[0].evaluate(x);
    else if (arity == 2 or arity == 4) {
      // children c and d are evaluated conditionally
      a = children[0].evaluate(x);
      b = children[1].evaluate(x);
    }
    // calculate the result
    switch(function) {
    case null:
      assert(false); // never calculate empty node
    case constant:
      assert(arity == 0);
      return k;
    case input:
      assert(arity == 0);
      return x;
    case sqrt:
      assert(arity == 1);
      return std::sqrt(std::abs(a)); // protected
    case sin:
      assert(arity == 1);
      return std::sin(a);
    case cos:
      assert(arity == 1);
      return std::cos(a);
    case log:
      assert(arity == 1);
      return (a == 0) ? 0 : std::log(std::abs(a)); // protected
    case exp:
      assert(arity == 1);
      return std::exp(a);
    case add:
      assert(arity == 2);
      return a + b;
    case subtract:
      assert(arity == 2);
      return a - b;
    case multiply:
      assert(arity == 2);
      return a * b;
    case divide:
      assert(arity == 2);
      return (b == 0) ? 1 : a / b; // protected
    case pow:
      assert(arity == 2);
      return std::pow(std::abs(a), std::abs(b)); // protected
    case lesser:
      assert(arity == 4);
      return (a < b) ? children[2].evaluate(x) : children[3].evaluate(x);
    case greater:
      assert(arity == 4);
      return (a > b) ? children[2].evaluate(x) : children[3].evaluate(x);
    }
    assert(false);
  }

  const Size Node::size() const {
    // recursively count children via post-order traversal
    // keep track of internals and leafs via Size struct
    Size size;
    for (const Node & child : children) {
      Size temp = child.size(); // is this micro-optimizing?
      size.internals += temp.internals;
      size.leafs += temp.leafs;
    }
    if (children.size() == 0) ++size.leafs;
    else ++size.internals;
    return size;
  }

  Node empty;

  Node & Node::visit(const Size & i, Size & visiting) {
    // depth-first search for taget node, either internal or leaf
    for (Node & child : children) {
      // increase relevant count
      if (child.children.size() == 0) ++visiting.leafs;
      else ++visiting.internals;
      // return node reference if found
      if (visiting.internals == i.internals or visiting.leafs == i.leafs)
	return child;
      Node & temp = child.visit(i, visiting); // mark each node
      if (temp.function != null) return temp; // return found node
    }
    return empty; // need to indicate "not-found"
  }

  void Node::mutate_self() {
    // single node mutation to different function of same arity
    if (arity == 0) {
      // mutate constant to a value in its neighborhood, don't switch functions
      if (function == constant) {
	normal_dist dist{0, 1};
	k *= 1 + dist(rg.engine);
      }
    }
    else if (arity == 1) {
      int_dist dist{0, int(unaries.size()) - 1};
      Function prior = function;
      // ensure we're using a specified available function
      while (function == prior or not contains(function, internals))
	function = Function(unaries[dist(rg.engine)]);
    }
    else if (arity == 2) {
      int_dist dist{0, int(binaries.size()) - 1};
      Function prior = function;
      while (function == prior or not contains(function, internals))
	function = Function(binaries[dist(rg.engine)]);
    }
    else if (arity == 4) {
      int_dist dist{0, int(quadnaries.size()) - 1};
      Function prior = function;
      while (function == prior or not contains(function, internals))
	function = Function(quadnaries[dist(rg.engine)]);
    }
    assert(function != null);
  }

  void Node::mutate_tree(const double & chance) {
    // recursively mutate nodes with options.mutate_chance probability
    real_dist dist{0, 1};
    for (Node & child : children) {
      if (dist(rg.engine) < chance) child.mutate_self();
      child.mutate_tree(chance);
    }
  }

  Individual::Individual(const Options & options, const Method method, const int depth): root{Node{options, method, depth}} {
    evaluate(options.values);
  }

  string Individual::print() const {
    using std::to_string;
    string info = "# Size " + to_string(get_total())
      + ", with " + to_string(get_internals())
      + " internals, and " + to_string(get_leafs()) + " leafs.\n"
      + "# Raw fitness: " + to_string(get_fitness())
      + ", and adjusted: " + to_string(get_adjusted()) + ".\n";
    return info;
  }

  string Individual::print_formula() const {
    return "# Formula: " + root.print() + "\n";
  }

  string Individual::evaluate(const options::pairs & values, const double & penalty, const bool & print) {
    using std::to_string;
    using std::get;
    string calculation = "# x - y - expected - error\n";
    // update size on evaluation because it's incredibly convenient
    size = root.size();
    fitness = penalty * get_total(); // reset fitness and apply scaled size penalty
    for (auto pair : values) {
      double x = std::get<0>(pair);
      double y = root.evaluate(x);
      assert(not std::isnan(y) and not std::isinf(y));
      double expected = std::get<1>(pair);
      double error = std::pow(y - expected, 2);
      fitness += error;
      if (print)
	calculation += to_string(x) + "\t"
	  + to_string(y) + "\t"
	  + to_string(expected) + "\t"
	  + to_string(error) + "\n";
    }
    return calculation;
  }

  void Individual::mutate(const double & chance) {
    // mutate each node with a options.mutate_chance probability
    root.mutate_tree(chance);
  }

  Node & Individual::operator[](const Size & i) {
    assert(i.internals <= get_internals());
    assert(i.leafs <= get_leafs());
    Size visiting;
    if (i.internals == 0 and i.leafs == 0) // seeking root
      return root;
    return root.visit(i, visiting);
  }

  void crossover(const double & chance, Individual & a, Individual & b) {
    real_dist probability{0, 1};
    Size target_a, target_b;
    // guaranteed to have at least 1 leaf, but may have 0 internals (root as leaf)
    if (a.get_internals() != 0 and probability(rg.engine) < chance) {
      // choose an internal node
      int_dist dist{0, a.get_internals() - 1};
      target_a.internals = dist(rg.engine);
    } else {
      // otherwise we choose a leaf node
      int_dist dist{0, a.get_leafs() - 1};
      target_a.leafs = dist(rg.engine);
    }
    // do the same thing for the second individual
    if (b.get_internals() != 0 and probability(rg.engine) < chance) {
      int_dist dist{0, b.get_internals() - 1};
      target_b.internals = dist(rg.engine);
    } else {
      int_dist dist{0, b.get_leafs() - 1};
      target_b.leafs = dist(rg.engine);
    }
    // replace nodes
    std::swap(a[target_a], b[target_b]);
  }
}
<|endoftext|>


<commit_before>#include "unittest.h"
#include "rapidjson/document.h"
#include "rapidjson/reader.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"

using namespace rapidjson;

TEST(Writer, Compact) {
	StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ");
	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);
	Reader reader;
	reader.Parse<0>(s, writer);
	EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", buffer.GetString());
	EXPECT_EQ(77u, buffer.GetSize());
}

// json -> parse -> writer -> json
#define TEST_ROUNDTRIP(json) \
	{ \
		StringStream s(json); \
		StringBuffer buffer; \
		Writer<StringBuffer> writer(buffer); \
		Reader reader; \
		reader.Parse<0>(s, writer); \
		EXPECT_STREQ(json, buffer.GetString()); \
	}

TEST(Writer, Int) {
	TEST_ROUNDTRIP("[-1]");
	TEST_ROUNDTRIP("[-123]");
	TEST_ROUNDTRIP("[-2147483648]");
}

TEST(Writer, UInt) {
	TEST_ROUNDTRIP("[0]");
	TEST_ROUNDTRIP("[1]");
	TEST_ROUNDTRIP("[123]");
	TEST_ROUNDTRIP("[2147483647]");
	TEST_ROUNDTRIP("[4294967295]");
}

TEST(Writer, Int64) {
	TEST_ROUNDTRIP("[-1234567890123456789]");
	TEST_ROUNDTRIP("[-9223372036854775808]");
}

TEST(Writer, Uint64) {
	TEST_ROUNDTRIP("[1234567890123456789]");
	TEST_ROUNDTRIP("[9223372036854775807]");
}

TEST(Writer, String) {
	TEST_ROUNDTRIP("[\"Hello\"]");
	TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
	TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
}

TEST(Writer,DoublePrecision) {
	const char json[] = "[1.2345,1.2345678,0.123456789012,1234567.8]";

	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);

	const int kDefaultDoublePrecision = 6;
	// handling the double precision
	EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
	writer.SetDoublePrecision(17);
	EXPECT_EQ(writer.GetDoublePrecision(), 17);
	writer.SetDoublePrecision(-1); // negative equivalent to reset
	EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
	writer.SetDoublePrecision(1);
	writer.SetDoublePrecision();   // reset again
	EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);

	{ // write with explicitly increased precision
		StringStream s(json);
		Reader reader;
		reader.Parse<0>(s, writer.SetDoublePrecision(12));
		EXPECT_EQ(writer.GetDoublePrecision(), 12);
		EXPECT_STREQ(json, buffer.GetString());
		buffer.Clear();
	}
	{ // explicit individual double precisions
		writer.SetDoublePrecision(2)
			.StartArray()
			.Double(1.2345,5)
			.Double(1.2345678,9)
			.Double(0.123456789012,12)
			.Double(1234567.8,8)
			.EndArray();

		EXPECT_EQ(writer.GetDoublePrecision(), 2);
		EXPECT_STREQ(json, buffer.GetString());
		buffer.Clear();
	}
	{ // write with default precision (output with precision loss)
		Document d;
		d.Parse<0>(json);
		d.Accept(writer.SetDoublePrecision());

		// parsed again to avoid platform-dependent floating point outputs
		// (e.g. width of exponents)
		d.Parse<0>(buffer.GetString());
		EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
		EXPECT_DOUBLE_EQ(d[0u].GetDouble(), 1.2345);
		EXPECT_DOUBLE_EQ(d[1u].GetDouble(), 1.23457);
		EXPECT_DOUBLE_EQ(d[2u].GetDouble(), 0.123457);
		EXPECT_DOUBLE_EQ(d[3u].GetDouble(), 1234570);
		buffer.Clear();
	}
}

TEST(Writer, Transcode) {
	// UTF8 -> UTF16 -> UTF8
	StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"dollar\":\"\x24\", \"cents\":\"\xC2\xA2\", \"euro\":\"\xE2\x82\xAC\", \"gclef\":\"\xF0\x9D\x84\x9E\" } ");
	StringBuffer buffer;
	Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
	GenericReader<UTF8<>, UTF16<> > reader;
	reader.Parse<0>(s, writer);
	EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}", buffer.GetString());
}

#include <sstream>

class OStreamWrapper {
public:
	typedef char Ch;

	OStreamWrapper(std::ostream& os) : os_(os) {}

	Ch Peek() const { assert(false); return '\0'; }
	Ch Take() { assert(false); return '\0'; }
	size_t Tell() const {  }

	Ch* PutBegin() { assert(false); return 0; }
	void Put(Ch c) { os_.put(c); }
	void Flush() { os_.flush(); }
	size_t PutEnd(Ch*) { assert(false); return 0; }

private:
	OStreamWrapper(const OStreamWrapper&);
	OStreamWrapper& operator=(const OStreamWrapper&);

	std::ostream& os_;
};

TEST(Writer, OStreamWrapper) {
	StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ");

	std::stringstream ss;
	OStreamWrapper os(ss);

	Writer<OStreamWrapper> writer(os);

	Reader reader;
	reader.Parse<0>(s, writer);

	std::string actual = ss.str();
	EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str());
}
<commit_msg>Fixes compilation error.<commit_after>#include "unittest.h"
#include "rapidjson/document.h"
#include "rapidjson/reader.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"

using namespace rapidjson;

TEST(Writer, Compact) {
	StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ");
	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);
	Reader reader;
	reader.Parse<0>(s, writer);
	EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", buffer.GetString());
	EXPECT_EQ(77u, buffer.GetSize());
}

// json -> parse -> writer -> json
#define TEST_ROUNDTRIP(json) \
	{ \
		StringStream s(json); \
		StringBuffer buffer; \
		Writer<StringBuffer> writer(buffer); \
		Reader reader; \
		reader.Parse<0>(s, writer); \
		EXPECT_STREQ(json, buffer.GetString()); \
	}

TEST(Writer, Int) {
	TEST_ROUNDTRIP("[-1]");
	TEST_ROUNDTRIP("[-123]");
	TEST_ROUNDTRIP("[-2147483648]");
}

TEST(Writer, UInt) {
	TEST_ROUNDTRIP("[0]");
	TEST_ROUNDTRIP("[1]");
	TEST_ROUNDTRIP("[123]");
	TEST_ROUNDTRIP("[2147483647]");
	TEST_ROUNDTRIP("[4294967295]");
}

TEST(Writer, Int64) {
	TEST_ROUNDTRIP("[-1234567890123456789]");
	TEST_ROUNDTRIP("[-9223372036854775808]");
}

TEST(Writer, Uint64) {
	TEST_ROUNDTRIP("[1234567890123456789]");
	TEST_ROUNDTRIP("[9223372036854775807]");
}

TEST(Writer, String) {
	TEST_ROUNDTRIP("[\"Hello\"]");
	TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
	TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
}

TEST(Writer,DoublePrecision) {
	const char json[] = "[1.2345,1.2345678,0.123456789012,1234567.8]";

	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);

	const int kDefaultDoublePrecision = 6;
	// handling the double precision
	EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
	writer.SetDoublePrecision(17);
	EXPECT_EQ(writer.GetDoublePrecision(), 17);
	writer.SetDoublePrecision(-1); // negative equivalent to reset
	EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
	writer.SetDoublePrecision(1);
	writer.SetDoublePrecision();   // reset again
	EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);

	{ // write with explicitly increased precision
		StringStream s(json);
		Reader reader;
		reader.Parse<0>(s, writer.SetDoublePrecision(12));
		EXPECT_EQ(writer.GetDoublePrecision(), 12);
		EXPECT_STREQ(json, buffer.GetString());
		buffer.Clear();
	}
	{ // explicit individual double precisions
		writer.SetDoublePrecision(2)
			.StartArray()
			.Double(1.2345,5)
			.Double(1.2345678,9)
			.Double(0.123456789012,12)
			.Double(1234567.8,8)
			.EndArray();

		EXPECT_EQ(writer.GetDoublePrecision(), 2);
		EXPECT_STREQ(json, buffer.GetString());
		buffer.Clear();
	}
	{ // write with default precision (output with precision loss)
		Document d;
		d.Parse<0>(json);
		d.Accept(writer.SetDoublePrecision());

		// parsed again to avoid platform-dependent floating point outputs
		// (e.g. width of exponents)
		d.Parse<0>(buffer.GetString());
		EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
		EXPECT_DOUBLE_EQ(d[0u].GetDouble(), 1.2345);
		EXPECT_DOUBLE_EQ(d[1u].GetDouble(), 1.23457);
		EXPECT_DOUBLE_EQ(d[2u].GetDouble(), 0.123457);
		EXPECT_DOUBLE_EQ(d[3u].GetDouble(), 1234570);
		buffer.Clear();
	}
}

TEST(Writer, Transcode) {
	// UTF8 -> UTF16 -> UTF8
	StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"dollar\":\"\x24\", \"cents\":\"\xC2\xA2\", \"euro\":\"\xE2\x82\xAC\", \"gclef\":\"\xF0\x9D\x84\x9E\" } ");
	StringBuffer buffer;
	Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
	GenericReader<UTF8<>, UTF16<> > reader;
	reader.Parse<0>(s, writer);
	EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}", buffer.GetString());
}

#include <sstream>

class OStreamWrapper {
public:
	typedef char Ch;

	OStreamWrapper(std::ostream& os) : os_(os) {}

	Ch Peek() const { assert(false); return '\0'; }
	Ch Take() { assert(false); return '\0'; }
	size_t Tell() const { return 0; }

	Ch* PutBegin() { assert(false); return 0; }
	void Put(Ch c) { os_.put(c); }
	void Flush() { os_.flush(); }
	size_t PutEnd(Ch*) { assert(false); return 0; }

private:
	OStreamWrapper(const OStreamWrapper&);
	OStreamWrapper& operator=(const OStreamWrapper&);

	std::ostream& os_;
};

TEST(Writer, OStreamWrapper) {
	StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ");

	std::stringstream ss;
	OStreamWrapper os(ss);

	Writer<OStreamWrapper> writer(os);

	Reader reader;
	reader.Parse<0>(s, writer);

	std::string actual = ss.str();
	EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str());
}
<|endoftext|>


<commit_before>#import <v8.h>
#import <node.h>
#import <AudioToolbox/AudioToolbox.h>
#import <UIKit/UIKit.h>
#import "graphicServices.h"
#import "notifications.h"
#import "telephony.h"
#import "compatibility.h" // ...meh

using namespace node;
using namespace v8;

class Binding {
  public:

  static void Init(v8::Handle<Object> target) {
    HandleScope scope;

    UIDevice *aDevice = [UIDevice currentDevice];
    [aDevice beginGeneratingDeviceOrientationNotifications];
    [aDevice setBatteryMonitoringEnabled:YES];

    NODE_SET_METHOD(target, "vibrate", Vibrate);
    NODE_SET_METHOD(target, "device", Device);
    NODE_SET_METHOD(target, "sendSMS", Telephony::SendSMS);
  }

  static v8::Handle<Value> Vibrate(const Arguments& args) {
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    return Undefined();
  }

  static v8::Handle<Value> Device(const Arguments& args) {
    HandleScope scope;
    Local<Object> result = Object::New();

    UIDevice *aDevice = [UIDevice currentDevice];

    result->Set(String::NewSymbol("batteryLevel"), Number::New([aDevice batteryLevel]));
    result->Set(String::NewSymbol("batteryState"), Integer::New([aDevice batteryState]));
    result->Set(String::NewSymbol("model"), String::NewSymbol([[aDevice model] UTF8String]));
    result->Set(String::NewSymbol("localizedModel"), String::NewSymbol([[aDevice localizedModel] UTF8String]));
    result->Set(String::NewSymbol("orientation"), Integer::New([aDevice orientation]));
    result->Set(String::NewSymbol("name"), String::NewSymbol([[aDevice name] UTF8String]));
    result->Set(String::NewSymbol("systemName"), String::NewSymbol([[aDevice systemName] UTF8String]));
    result->Set(String::NewSymbol("systemVersion"), String::NewSymbol([[aDevice systemVersion] UTF8String]));
    result->Set(String::NewSymbol("uniqueIdentifier"), String::NewSymbol([[aDevice uniqueIdentifier] UTF8String]));

    return scope.Close(result);
  }

};

extern "C" {
  static void init (v8::Handle<Object> target) {
    Binding::Init(target);
    GraphicServices::Init(target);
    Notifications::Init(target);
  }

  NODE_MODULE(binding, init);
}
<commit_msg>Remove call to NODE_MODULES macro. WTF did that do anyways?<commit_after>#import <v8.h>
#import <node.h>
#import <AudioToolbox/AudioToolbox.h>
#import <UIKit/UIKit.h>
#import "graphicServices.h"
#import "notifications.h"
#import "telephony.h"
#import "compatibility.h" // ...meh

using namespace node;
using namespace v8;

class Binding {
  public:

  static void Init(v8::Handle<Object> target) {
    HandleScope scope;

    UIDevice *aDevice = [UIDevice currentDevice];
    [aDevice beginGeneratingDeviceOrientationNotifications];
    [aDevice setBatteryMonitoringEnabled:YES];

    NODE_SET_METHOD(target, "vibrate", Vibrate);
    NODE_SET_METHOD(target, "device", Device);
    NODE_SET_METHOD(target, "sendSMS", Telephony::SendSMS);
  }

  static v8::Handle<Value> Vibrate(const Arguments& args) {
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    return Undefined();
  }

  static v8::Handle<Value> Device(const Arguments& args) {
    HandleScope scope;
    Local<Object> result = Object::New();

    UIDevice *aDevice = [UIDevice currentDevice];

    result->Set(String::NewSymbol("batteryLevel"), Number::New([aDevice batteryLevel]));
    result->Set(String::NewSymbol("batteryState"), Integer::New([aDevice batteryState]));
    result->Set(String::NewSymbol("model"), String::NewSymbol([[aDevice model] UTF8String]));
    result->Set(String::NewSymbol("localizedModel"), String::NewSymbol([[aDevice localizedModel] UTF8String]));
    result->Set(String::NewSymbol("orientation"), Integer::New([aDevice orientation]));
    result->Set(String::NewSymbol("name"), String::NewSymbol([[aDevice name] UTF8String]));
    result->Set(String::NewSymbol("systemName"), String::NewSymbol([[aDevice systemName] UTF8String]));
    result->Set(String::NewSymbol("systemVersion"), String::NewSymbol([[aDevice systemVersion] UTF8String]));
    result->Set(String::NewSymbol("uniqueIdentifier"), String::NewSymbol([[aDevice uniqueIdentifier] UTF8String]));

    return scope.Close(result);
  }

};

extern "C" void init (v8::Handle<Object> target) {
  Binding::Init(target);
  GraphicServices::Init(target);
  Notifications::Init(target);
}
<|endoftext|>


<commit_before>#include "bitmap.h"
#include "except.h"

Bitmap::Bitmap(std::string filepath)
    : _filepath(filepath)
      , _data(nullptr)
      , _width(0)
      , _height(0)
{
    FILE * fptr = fopen(_filepath.c_str(), "rb");
    if (fptr == nullptr)
        throw FileError();

    uint8_t bmp_header[54];
    fread(bmp_header, sizeof(uint8_t), 54, fptr);
    _width = *(int *)&bmp_header[18];
    _height = *(int *)&bmp_header[22];

    size_t num_bytes = 3 * _width * _height;
    _data = new uint8_t[num_bytes];
    fread(_data, sizeof(uint8_t), num_bytes, fptr);

    fclose(fptr);
}

Bitmap::~Bitmap()
{
    save();
    if (_data != nullptr)
        delete [] _data;
}

uint8_t * const Bitmap::get_data() const
{
    return _data;
}

size_t Bitmap::get_width() const
{
    return _width;
}

size_t Bitmap::get_height() const
{
    return _height;
}

std::string Bitmap::save() const
{
    // TODO
    return "";
}
<commit_msg>Issue #14: implemented save method<commit_after>#include "bitmap.h"
#include "except.h"

std::string timestamp(std::string filepath);

Bitmap::Bitmap(std::string filepath)
    : _filepath(filepath)
      , _data(nullptr)
      , _width(0)
      , _height(0)
{
    FILE * fptr = fopen(_filepath.c_str(), "rb");
    if (fptr == nullptr)
        throw FileError();

    uint8_t bmp_header[54];
    fread(bmp_header, sizeof(uint8_t), 54, fptr);
    _width = *(int *)&bmp_header[18];
    _height = *(int *)&bmp_header[22];

    size_t num_bytes = 3 * _width * _height;
    _data = new uint8_t[num_bytes];
    fread(_data, sizeof(uint8_t), num_bytes, fptr);

    fclose(fptr);
}

Bitmap::~Bitmap()
{
    save();
    if (_data != nullptr)
        delete [] _data;
}

uint8_t * const Bitmap::get_data() const
{
    return _data;
}

size_t Bitmap::get_width() const
{
    return _width;
}

size_t Bitmap::get_height() const
{
    return _height;
}

std::string Bitmap::save() const
{
    std::string filepath_ts = timestamp(_filepath);
    FILE * fptr = fopen(filepath_ts.c_str(), "wb");
    if (fptr == nullptr)
        throw FileError();

    unsigned char bmp_header[54] = {'B','M',
                                    0, 0, 0, 0,
                                    0, 0,
                                    0, 0,
                                    54, 0, 0, 0,
                                    40, 0, 0, 0,
                                    0, 0, 0, 0,
                                    0, 0, 0, 0,
                                    1, 0,
                                    24, 0};

    size_t num_bytes = 3 * _width * _height;
    *(int *)&bmp_header[2] = (int)(54 + num_bytes);
    *(int *)&bmp_header[18] = (int) _width;
    *(int *)&bmp_header[22] = (int) _height;

    fwrite(bmp_header, sizeof(uint8_t), 54, fptr);

    fwrite(_data, sizeof(uint8_t), num_bytes, fptr);

    fclose(fptr);

    return filepath_ts;
}

std::string timestamp(std::string filepath)
{
    // TODO
    return "";
}
<|endoftext|>