<commit_before>#ifndef regex_impl_hh_INCLUDED
#define regex_impl_hh_INCLUDED

#include "unicode.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"
#include "vector.hh"
#include "flags.hh"

namespace Kakoune
{

struct CompiledRegex
{
    enum Op : char
    {
        Match,
        Literal,
        LiteralIgnoreCase,
        AnyChar,
        Matcher,
        Jump,
        Split_PrioritizeParent,
        Split_PrioritizeChild,
        Save,
        LineStart,
        LineEnd,
        WordBoundary,
        NotWordBoundary,
        SubjectBegin,
        SubjectEnd,
        LookAhead,
        LookBehind,
        NegativeLookAhead,
        NegativeLookBehind,
    };

    using Offset = unsigned;
    static constexpr Offset search_prefix_size = 3 + 2 * sizeof(Offset);

    explicit operator bool() const { return not bytecode.empty(); }

    Vector<char> bytecode;
    Vector<std::function<bool (Codepoint)>> matchers;
    size_t save_count;
};

CompiledRegex compile_regex(StringView re);

enum class RegexExecFlags
{
    None              = 0,
    Search            = 1 << 0,
    NotBeginOfLine    = 1 << 1,
    NotEndOfLine      = 1 << 2,
    NotBeginOfWord    = 1 << 3,
    NotEndOfWord      = 1 << 4,
    NotBeginOfSubject = 1 << 5,
    NotInitialNull    = 1 << 6,
    AnyMatch          = 1 << 7,
    NoSaves           = 1 << 8,
};

constexpr bool with_bit_ops(Meta::Type<RegexExecFlags>) { return true; }

template<typename Iterator>
struct ThreadedRegexVM
{
    ThreadedRegexVM(const CompiledRegex& program)
      : m_program{program} { kak_assert(m_program); }

    struct Saves
    {
        int refcount;
        Vector<Iterator> pos;
    };

    Saves* clone_saves(Saves* saves)
    {
        if (not m_free_saves.empty())
        {
            Saves* res = m_free_saves.back();
            m_free_saves.pop_back();
            res->refcount = 1;
            res->pos = saves->pos;
            return res;
        }

        m_saves.push_back(std::make_unique<Saves>(Saves{1, saves->pos}));
        return m_saves.back().get();
    }

    struct Thread
    {
        const char* inst;
        Saves* saves;
    };

    enum class StepResult { Consumed, Matched, Failed };
    StepResult step(Thread& thread)
    {
        const auto prog_start = m_program.bytecode.data();
        const auto prog_end = prog_start + m_program.bytecode.size();
        while (true)
        {
            const Codepoint cp = m_pos == m_end ? 0 : *m_pos;
            const CompiledRegex::Op op = (CompiledRegex::Op)*thread.inst++;
            switch (op)
            {
                case CompiledRegex::Literal:
                    if (utf8::read_codepoint(thread.inst, prog_end) == cp)
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::LiteralIgnoreCase:
                    if (utf8::read_codepoint(thread.inst, prog_end) == to_lower(cp))
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::AnyChar:
                    return StepResult::Consumed;
                case CompiledRegex::Jump:
                    thread.inst = prog_start + *reinterpret_cast<const CompiledRegex::Offset*>(thread.inst);
                    break;
                case CompiledRegex::Split_PrioritizeParent:
                {
                    auto parent = thread.inst + sizeof(CompiledRegex::Offset);
                    auto child = prog_start + *reinterpret_cast<const CompiledRegex::Offset*>(thread.inst);
                    thread.inst = parent;
                    if (thread.saves)
                        ++thread.saves->refcount;
                    m_current_threads.push_back({child, thread.saves});
                    break;
                }
                case CompiledRegex::Split_PrioritizeChild:
                {
                    auto parent = thread.inst + sizeof(CompiledRegex::Offset);
                    auto child = prog_start + *reinterpret_cast<const CompiledRegex::Offset*>(thread.inst);
                    thread.inst = child;
                    if (thread.saves)
                        ++thread.saves->refcount;
                    m_current_threads.push_back({parent, thread.saves});
                    break;
                }
                case CompiledRegex::Save:
                {
                    if (thread.saves == nullptr)
                        break;

                    const char index = *thread.inst++;
                    if (thread.saves->refcount > 1)
                    {
                        --thread.saves->refcount;
                        thread.saves = clone_saves(thread.saves);
                    }
                    thread.saves->pos[index] = m_pos.base();
                    break;
                }
                case CompiledRegex::Matcher:
                {
                    const int matcher_id = *thread.inst++;
                    return m_program.matchers[matcher_id](*m_pos) ?
                        StepResult::Consumed : StepResult::Failed;
                }
                case CompiledRegex::LineStart:
                    if (not is_line_start())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LineEnd:
                    if (not is_line_end())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::WordBoundary:
                    if (not is_word_boundary())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::NotWordBoundary:
                    if (is_word_boundary())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectBegin:
                    if (m_pos != m_begin or m_flags & RegexExecFlags::NotBeginOfSubject)
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectEnd:
                    if (m_pos != m_end)
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LookAhead:
                case CompiledRegex::NegativeLookAhead:
                {
                    int count = *thread.inst++;
                    for (auto it = m_pos; count and it != m_end; ++it, --count)
                        if (*it != utf8::read(thread.inst))
                            break;
                    if ((op == CompiledRegex::LookAhead and count != 0) or
                        (op == CompiledRegex::NegativeLookAhead and count == 0))
                        return StepResult::Failed;
                    thread.inst = utf8::advance(thread.inst, prog_end, CharCount{count - 1});
                    break;
                }
                case CompiledRegex::LookBehind:
                case CompiledRegex::NegativeLookBehind:
                {
                    int count = *thread.inst++;
                    for (auto it = m_pos-1; count and it >= m_begin; --it, --count)
                        if (*it != utf8::read(thread.inst))
                            break;
                    if ((op == CompiledRegex::LookBehind and count != 0) or
                        (op == CompiledRegex::NegativeLookBehind and count == 0))
                        return StepResult::Failed;
                    thread.inst = utf8::advance(thread.inst, prog_end, CharCount{count - 1});
                    break;
                }
                case CompiledRegex::Match:
                    return StepResult::Matched;
            }
        }
        return StepResult::Failed;
    }

    bool exec(Iterator begin, Iterator end, RegexExecFlags flags)
    {
        m_begin = begin;
        m_end = end;
        m_flags = flags;

        bool found_match = false;
        m_current_threads.clear();
        m_next_threads.clear();

        Saves* initial_saves = nullptr;
        if (not (m_flags & RegexExecFlags::NoSaves))
        {
            m_saves.push_back(std::make_unique<Saves>(Saves{1, Vector<Iterator>(m_program.save_count, Iterator{})}));
            initial_saves = m_saves.back().get();
        }

        const auto start_offset = (flags & RegexExecFlags::Search) ? 0 : CompiledRegex::search_prefix_size;
        m_current_threads.push_back({m_program.bytecode.data() + start_offset, initial_saves});

        if (flags & RegexExecFlags::NotInitialNull and m_begin == m_end)
            return false;

        auto release_saves = [this](Saves* saves) {
            if (saves and --saves->refcount == 0)
                m_free_saves.push_back(saves);
        };

        for (m_pos = Utf8It{m_begin, m_begin, m_end}; m_pos != m_end; ++m_pos)
        {
            while (not m_current_threads.empty())
            {
                auto thread = m_current_threads.back();
                m_current_threads.pop_back();
                switch (step(thread))
                {
                case StepResult::Matched:
                    if (not (flags & RegexExecFlags::Search) or // We are not at end, this is not a full match
                        (flags & RegexExecFlags::NotInitialNull and m_pos == m_begin))
                    {
                        release_saves(thread.saves);
                        continue;
                    }

                    if (thread.saves)
                        m_captures = std::move(thread.saves->pos);

                    if (flags & RegexExecFlags::AnyMatch)
                        return true;

                    found_match = true;
                    m_current_threads.clear(); // remove this and lower priority threads
                    break;
                case StepResult::Failed:
                    release_saves(thread.saves);
                    break;
                case StepResult::Consumed:
                    if (contains_that(m_next_threads, [&](auto& t) { return t.inst == thread.inst; }))
                        release_saves(thread.saves);
                    else
                        m_next_threads.push_back(thread);
                    break;
                }
            }
            if (m_next_threads.empty())
                return found_match;

            std::swap(m_current_threads, m_next_threads);
            std::reverse(m_current_threads.begin(), m_current_threads.end());
        }
        if (found_match)
            return true;

        // Step remaining threads to see if they match without consuming anything else
        while (not m_current_threads.empty())
        {
            auto thread = m_current_threads.back();
            m_current_threads.pop_back();
            if (step(thread) == StepResult::Matched)
            {
                if (thread.saves)
                    m_captures = std::move(thread.saves->pos);
                return true;
            }
        }
        return false;
    }

    bool is_line_start() const
    {
        return (m_pos == m_begin and not (m_flags & RegexExecFlags::NotBeginOfLine)) or
               *(m_pos-1) == '\n';
    }

    bool is_line_end() const
    {
        return (m_pos == m_end and not (m_flags & RegexExecFlags::NotEndOfLine)) or
               *m_pos == '\n';
    }

    bool is_word_boundary() const
    {
        return (m_pos == m_begin and not (m_flags & RegexExecFlags::NotBeginOfWord)) or
               (m_pos == m_end and not (m_flags & RegexExecFlags::NotEndOfWord)) or
               is_word(*(m_pos-1)) != is_word(*m_pos);
    }

    const CompiledRegex& m_program;
    Vector<Thread> m_current_threads;
    Vector<Thread> m_next_threads;

    using Utf8It = utf8::iterator<Iterator>;

    Iterator m_begin;
    Iterator m_end;
    Utf8It m_pos;
    RegexExecFlags m_flags;

    Vector<std::unique_ptr<Saves>> m_saves;
    Vector<Saves*> m_free_saves;

    Vector<Iterator> m_captures;
};

template<typename It>
bool regex_match(It begin, It end, const CompiledRegex& re, RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    return vm.exec(begin, end, (RegexExecFlags)(flags & ~(RegexExecFlags::Search)) |
                               RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It>
bool regex_match(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                 RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    if (vm.exec(begin, end,  flags & ~(RegexExecFlags::Search)))
    {
        captures = std::move(vm.m_captures);
        return true;
    }
    return false;
}

template<typename It>
bool regex_search(It begin, It end, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    return vm.exec(begin, end, flags | RegexExecFlags::Search | RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It>
bool regex_search(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    if (vm.exec(begin, end, flags | RegexExecFlags::Search))
    {
        captures = std::move(vm.m_captures);
        return true;
    }
    return false;
}

}

#endif // regex_impl_hh_INCLUDED
<commit_msg>Regex: make m_current_threads and m_next_threads local variable of exec<commit_after>#ifndef regex_impl_hh_INCLUDED
#define regex_impl_hh_INCLUDED

#include "unicode.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"
#include "vector.hh"
#include "flags.hh"

namespace Kakoune
{

struct CompiledRegex
{
    enum Op : char
    {
        Match,
        Literal,
        LiteralIgnoreCase,
        AnyChar,
        Matcher,
        Jump,
        Split_PrioritizeParent,
        Split_PrioritizeChild,
        Save,
        LineStart,
        LineEnd,
        WordBoundary,
        NotWordBoundary,
        SubjectBegin,
        SubjectEnd,
        LookAhead,
        LookBehind,
        NegativeLookAhead,
        NegativeLookBehind,
    };

    using Offset = unsigned;
    static constexpr Offset search_prefix_size = 3 + 2 * sizeof(Offset);

    explicit operator bool() const { return not bytecode.empty(); }

    Vector<char> bytecode;
    Vector<std::function<bool (Codepoint)>> matchers;
    size_t save_count;
};

CompiledRegex compile_regex(StringView re);

enum class RegexExecFlags
{
    None              = 0,
    Search            = 1 << 0,
    NotBeginOfLine    = 1 << 1,
    NotEndOfLine      = 1 << 2,
    NotBeginOfWord    = 1 << 3,
    NotEndOfWord      = 1 << 4,
    NotBeginOfSubject = 1 << 5,
    NotInitialNull    = 1 << 6,
    AnyMatch          = 1 << 7,
    NoSaves           = 1 << 8,
};

constexpr bool with_bit_ops(Meta::Type<RegexExecFlags>) { return true; }

template<typename Iterator>
struct ThreadedRegexVM
{
    ThreadedRegexVM(const CompiledRegex& program)
      : m_program{program} { kak_assert(m_program); }

    struct Saves
    {
        int refcount;
        Vector<Iterator> pos;
    };

    Saves* clone_saves(Saves* saves)
    {
        if (not m_free_saves.empty())
        {
            Saves* res = m_free_saves.back();
            m_free_saves.pop_back();
            res->refcount = 1;
            res->pos = saves->pos;
            return res;
        }

        m_saves.push_back(std::make_unique<Saves>(Saves{1, saves->pos}));
        return m_saves.back().get();
    }

    void release_saves(Saves* saves)
    {
        if (saves and --saves->refcount == 0)
            m_free_saves.push_back(saves);
    };

    struct Thread
    {
        const char* inst;
        Saves* saves;
    };

    enum class StepResult { Consumed, Matched, Failed };
    StepResult step(Thread& thread, Vector<Thread>& threads)
    {
        const auto prog_start = m_program.bytecode.data();
        const auto prog_end = prog_start + m_program.bytecode.size();
        while (true)
        {
            const Codepoint cp = m_pos == m_end ? 0 : *m_pos;
            const CompiledRegex::Op op = (CompiledRegex::Op)*thread.inst++;
            switch (op)
            {
                case CompiledRegex::Literal:
                    if (utf8::read_codepoint(thread.inst, prog_end) == cp)
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::LiteralIgnoreCase:
                    if (utf8::read_codepoint(thread.inst, prog_end) == to_lower(cp))
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::AnyChar:
                    return StepResult::Consumed;
                case CompiledRegex::Jump:
                    thread.inst = prog_start + *reinterpret_cast<const CompiledRegex::Offset*>(thread.inst);
                    break;
                case CompiledRegex::Split_PrioritizeParent:
                {
                    auto parent = thread.inst + sizeof(CompiledRegex::Offset);
                    auto child = prog_start + *reinterpret_cast<const CompiledRegex::Offset*>(thread.inst);
                    thread.inst = parent;
                    if (thread.saves)
                        ++thread.saves->refcount;
                    threads.push_back({child, thread.saves});
                    break;
                }
                case CompiledRegex::Split_PrioritizeChild:
                {
                    auto parent = thread.inst + sizeof(CompiledRegex::Offset);
                    auto child = prog_start + *reinterpret_cast<const CompiledRegex::Offset*>(thread.inst);
                    thread.inst = child;
                    if (thread.saves)
                        ++thread.saves->refcount;
                    threads.push_back({parent, thread.saves});
                    break;
                }
                case CompiledRegex::Save:
                {
                    if (thread.saves == nullptr)
                        break;

                    const char index = *thread.inst++;
                    if (thread.saves->refcount > 1)
                    {
                        --thread.saves->refcount;
                        thread.saves = clone_saves(thread.saves);
                    }
                    thread.saves->pos[index] = m_pos.base();
                    break;
                }
                case CompiledRegex::Matcher:
                {
                    const int matcher_id = *thread.inst++;
                    return m_program.matchers[matcher_id](*m_pos) ?
                        StepResult::Consumed : StepResult::Failed;
                }
                case CompiledRegex::LineStart:
                    if (not is_line_start())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LineEnd:
                    if (not is_line_end())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::WordBoundary:
                    if (not is_word_boundary())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::NotWordBoundary:
                    if (is_word_boundary())
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectBegin:
                    if (m_pos != m_begin or m_flags & RegexExecFlags::NotBeginOfSubject)
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectEnd:
                    if (m_pos != m_end)
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LookAhead:
                case CompiledRegex::NegativeLookAhead:
                {
                    int count = *thread.inst++;
                    for (auto it = m_pos; count and it != m_end; ++it, --count)
                        if (*it != utf8::read(thread.inst))
                            break;
                    if ((op == CompiledRegex::LookAhead and count != 0) or
                        (op == CompiledRegex::NegativeLookAhead and count == 0))
                        return StepResult::Failed;
                    thread.inst = utf8::advance(thread.inst, prog_end, CharCount{count - 1});
                    break;
                }
                case CompiledRegex::LookBehind:
                case CompiledRegex::NegativeLookBehind:
                {
                    int count = *thread.inst++;
                    for (auto it = m_pos-1; count and it >= m_begin; --it, --count)
                        if (*it != utf8::read(thread.inst))
                            break;
                    if ((op == CompiledRegex::LookBehind and count != 0) or
                        (op == CompiledRegex::NegativeLookBehind and count == 0))
                        return StepResult::Failed;
                    thread.inst = utf8::advance(thread.inst, prog_end, CharCount{count - 1});
                    break;
                }
                case CompiledRegex::Match:
                    return StepResult::Matched;
            }
        }
        return StepResult::Failed;
    }

    bool exec(Iterator begin, Iterator end, RegexExecFlags flags)
    {
        m_begin = begin;
        m_end = end;
        m_flags = flags;

        bool found_match = false;

        if (flags & RegexExecFlags::NotInitialNull and m_begin == m_end)
            return false;

        Saves* initial_saves = nullptr;
        if (not (m_flags & RegexExecFlags::NoSaves))
        {
            m_saves.push_back(std::make_unique<Saves>(Saves{1, Vector<Iterator>(m_program.save_count, Iterator{})}));
            initial_saves = m_saves.back().get();
        }

        const bool search = (flags & RegexExecFlags::Search);

        const auto start_offset =  search ? 0 : CompiledRegex::search_prefix_size;
        Vector<Thread> current_threads{Thread{m_program.bytecode.data() + start_offset, initial_saves}};
        Vector<Thread> next_threads;
        for (m_pos = Utf8It{m_begin, m_begin, m_end}; m_pos != m_end; ++m_pos)
        {
            while (not current_threads.empty())
            {
                auto thread = current_threads.back();
                current_threads.pop_back();
                switch (step(thread, current_threads))
                {
                case StepResult::Matched:
                    if (not (flags & RegexExecFlags::Search) or // We are not at end, this is not a full match
                        (flags & RegexExecFlags::NotInitialNull and m_pos == m_begin))
                    {
                        release_saves(thread.saves);
                        continue;
                    }

                    if (thread.saves)
                        m_captures = std::move(thread.saves->pos);

                    if (flags & RegexExecFlags::AnyMatch)
                        return true;

                    found_match = true;
                    current_threads.clear(); // remove this and lower priority threads
                    break;
                case StepResult::Failed:
                    release_saves(thread.saves);
                    break;
                case StepResult::Consumed:
                    if (contains_that(next_threads, [&](auto& t) { return t.inst == thread.inst; }))
                        release_saves(thread.saves);
                    else
                        next_threads.push_back(thread);
                    break;
                }
            }
            if (next_threads.empty())
                return found_match;

            std::swap(current_threads, next_threads);
            std::reverse(current_threads.begin(), current_threads.end());
        }
        if (found_match)
            return true;

        // Step remaining threads to see if they match without consuming anything else
        while (not current_threads.empty())
        {
            auto thread = current_threads.back();
            current_threads.pop_back();
            if (step(thread, current_threads) == StepResult::Matched)
            {
                if (thread.saves)
                    m_captures = std::move(thread.saves->pos);
                return true;
            }
        }
        return false;
    }

    bool is_line_start() const
    {
        return (m_pos == m_begin and not (m_flags & RegexExecFlags::NotBeginOfLine)) or
               *(m_pos-1) == '\n';
    }

    bool is_line_end() const
    {
        return (m_pos == m_end and not (m_flags & RegexExecFlags::NotEndOfLine)) or
               *m_pos == '\n';
    }

    bool is_word_boundary() const
    {
        return (m_pos == m_begin and not (m_flags & RegexExecFlags::NotBeginOfWord)) or
               (m_pos == m_end and not (m_flags & RegexExecFlags::NotEndOfWord)) or
               is_word(*(m_pos-1)) != is_word(*m_pos);
    }

    const CompiledRegex& m_program;

    using Utf8It = utf8::iterator<Iterator>;

    Iterator m_begin;
    Iterator m_end;
    Utf8It m_pos;
    RegexExecFlags m_flags;

    Vector<std::unique_ptr<Saves>> m_saves;
    Vector<Saves*> m_free_saves;

    Vector<Iterator> m_captures;
};

template<typename It>
bool regex_match(It begin, It end, const CompiledRegex& re, RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    return vm.exec(begin, end, (RegexExecFlags)(flags & ~(RegexExecFlags::Search)) |
                               RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It>
bool regex_match(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                 RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    if (vm.exec(begin, end,  flags & ~(RegexExecFlags::Search)))
    {
        captures = std::move(vm.m_captures);
        return true;
    }
    return false;
}

template<typename It>
bool regex_search(It begin, It end, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    return vm.exec(begin, end, flags | RegexExecFlags::Search | RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It>
bool regex_search(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It> vm{re};
    if (vm.exec(begin, end, flags | RegexExecFlags::Search))
    {
        captures = std::move(vm.m_captures);
        return true;
    }
    return false;
}

}

#endif // regex_impl_hh_INCLUDED
<|endoftext|>


<commit_before>// wrap.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#pragma pack(push, 1)
struct Options {
	const _TCHAR magic[33];
	const _TCHAR appPath[128];
	const _TCHAR workingDir[128];
	BOOL WaitForCompletion;
};
#pragma pack(pop)

static const struct Options Opts = {
	_T("24cf2af931624d70b7972221e1fa1dfc"),
	_T("                                                                                "),
	_T("                                                                                "),
	true };

int _tmain(int argc, _TCHAR* argv[])
{

	std::wstring appPath(Opts.appPath);
	std::wstring workingDir(Opts.workingDir);
	_TCHAR* space = _T(" ");

	for (int i = 1; i < argc; i++)
	{
		appPath.append(space);
		appPath.append(argv[i]);
	}
	size_t appPathLength = appPath.length() * sizeof(_TCHAR);
	_TCHAR* appPathFinal = new _TCHAR[appPathLength];
	_tcscpy_s(appPathFinal, appPathLength, appPath.c_str());

	SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
	sa.nLength = sizeof(sa);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	STARTUPINFOW si = { sizeof(STARTUPINFOW) };
	si.cb = sizeof(si);
	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	si.dwFlags |= STARTF_USESTDHANDLES;

	_tprintf(_T("out is null: %d\n"), si.hStdOutput == NULL);
	_tprintf(_T("err is null: %d\n"), si.hStdError == NULL);
	_tprintf(_T("in is null: %d\n"), si.hStdInput == NULL);

	// TODO: error handling
	PROCESS_INFORMATION pi;
	CreateProcessW(NULL, appPathFinal, NULL, &sa, TRUE, 0, NULL, workingDir.c_str(), &si, &pi);
	if (Opts.WaitForCompletion)
	{
		WaitForSingleObject(pi.hProcess, INFINITE);
	}
	return 0;
}<commit_msg>Comments<commit_after>// wrap.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#pragma pack(push, 1)
struct Options {
	const _TCHAR magic[33];
	// Fixed lengths to keep things simple. 128 characters
	// should be more than enough given that the paths are relative.
	const _TCHAR appPath[128];
	const _TCHAR workingDir[128];
	BOOL WaitForCompletion;
};
#pragma pack(pop)

// This stuct gets filled by winston during the linking stage.
// This program serves as a template. Winston looks for the location
// of the magic number and then writes a new struct into the binary
// with the correct data prepopulated.
static const struct Options Opts = {
	_T("24cf2af931624d70b7972221e1fa1dfc"),
	_T("                                                                                "),
	_T("                                                                                "),
	true };

int _tmain(int argc, _TCHAR* argv[])
{
	std::wstring appPath(Opts.appPath);
	std::wstring workingDir(Opts.workingDir);
	_TCHAR* space = _T(" ");

	for (int i = 1; i < argc; i++)
	{
		appPath.append(space);
		appPath.append(argv[i]);
	}
	size_t appPathLength = appPath.length() * sizeof(_TCHAR);
	_TCHAR* appPathFinal = new _TCHAR[appPathLength];
	_tcscpy_s(appPathFinal, appPathLength, appPath.c_str());

	SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
	sa.nLength = sizeof(sa);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	STARTUPINFOW si = { sizeof(STARTUPINFOW) };
	si.cb = sizeof(si);
	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	si.dwFlags |= STARTF_USESTDHANDLES;

	_tprintf(_T("out is null: %d\n"), si.hStdOutput == NULL);
	_tprintf(_T("err is null: %d\n"), si.hStdError == NULL);
	_tprintf(_T("in is null: %d\n"), si.hStdInput == NULL);

	// TODO: error handling
	PROCESS_INFORMATION pi;
	CreateProcessW(NULL, appPathFinal, NULL, &sa, TRUE, 0, NULL, workingDir.c_str(), &si, &pi);
	if (Opts.WaitForCompletion)
	{
		WaitForSingleObject(pi.hProcess, INFINITE);
	}
	return 0;
}<|endoftext|>


<commit_before>#include <math.h>

#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeTorus.hxx>
#include <SMESH_Gen.hxx>
#include <StdMeshers_AutomaticLength.hxx>
#include <StdMeshers_TrianglePreference.hxx>
#include <StdMeshers_MEFISTO_2D.hxx>
#include <gtest/gtest.h>

TEST(MeshBasicGeometriesSuite, testMeshBox)
{
    // create a box, mixing integers and floats
    BRepPrimAPI_MakeBox my_box(10.,10.,10.);
    my_box.Build();
    ASSERT_TRUE(my_box.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_box.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // check bounding box. It should be 10.sqrt(3)==17.32050807568877
    double diagonal_size = mesh->GetShapeDiagonalSize(mesh->GetShapeToMesh());
    ASSERT_GT(diagonal_size, 17.320508);
    ASSERT_LT(diagonal_size, 17.320509);
    // create and add hypothesis
    StdMeshers_AutomaticLength* hyp1d = new StdMeshers_AutomaticLength(0,0,meshgen);
    StdMeshers_TrianglePreference* hyp2d = new StdMeshers_TrianglePreference(1,0,meshgen);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 0);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 1);
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

TEST(MeshBasicGeometriesSuite, testMeshBoxMEFISTO2)
{
    // create a box, mixing integers and floats
    BRepPrimAPI_MakeBox my_box(10.,10.,10.);
    my_box.Build();
    ASSERT_TRUE(my_box.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_box.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // check bounding box. It should be 10.sqrt(3)==17.32050807568877
    double diagonal_size = mesh->GetShapeDiagonalSize(mesh->GetShapeToMesh());
    ASSERT_GT(diagonal_size, 17.320508);
    ASSERT_LT(diagonal_size, 17.320509);
    // create and add hypothesis
    StdMeshers_AutomaticLength* hyp1d = new StdMeshers_AutomaticLength(0,0,meshgen);
    StdMeshers_TrianglePreference* hyp2d = new StdMeshers_TrianglePreference(1,0,meshgen);
    StdMeshers_MEFISTO_2D* mef2d = new StdMeshers_MEFISTO_2D(2,0,meshgen) ;
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 0);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 1);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 2);
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

TEST(MeshBasicGeometriesSuite, testMeshSphere)
{
    // the same as the previous test, but with a sphere
    BRepPrimAPI_MakeSphere my_sphere(10.);
    my_sphere.Build();
    ASSERT_TRUE(my_sphere.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_sphere.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

TEST(MeshBasicGeometriesSuite, testMeshTorus)
{
    // the same as the previous test, but with a sphere
    BRepPrimAPI_MakeTorus my_torus(10., 20.);
    my_torus.Build();
    ASSERT_TRUE(my_torus.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_torus.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

int main(int argc, char **argv){
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Extend mefisto2d test<commit_after>#include <math.h>

#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeTorus.hxx>
#include <SMESH_Gen.hxx>
#include <StdMeshers_AutomaticLength.hxx>
#include <StdMeshers_TrianglePreference.hxx>
#include <StdMeshers_NumberOfSegments.hxx>
#include <StdMeshers_Regular_1D.hxx>
#include <StdMeshers_MEFISTO_2D.hxx>
#include <gtest/gtest.h>

TEST(MeshBasicGeometriesSuite, testMeshBox)
{
    // create a box, mixing integers and floats
    BRepPrimAPI_MakeBox my_box(10.,10.,10.);
    my_box.Build();
    ASSERT_TRUE(my_box.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_box.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // check bounding box. It should be 10.sqrt(3)==17.32050807568877
    double diagonal_size = mesh->GetShapeDiagonalSize(mesh->GetShapeToMesh());
    ASSERT_GT(diagonal_size, 17.320508);
    ASSERT_LT(diagonal_size, 17.320509);
    // create and add hypothesis
    StdMeshers_AutomaticLength* hyp1d_0 = new StdMeshers_AutomaticLength(0,0,meshgen);
    StdMeshers_NumberOfSegments* hyp1d_1 = new StdMeshers_NumberOfSegments(1,0,meshgen);
    hyp1d_1->SetNumberOfSegments(1);
    StdMeshers_Regular_1D* hyp1d_2 = new StdMeshers_Regular_1D(2,0,meshgen);
    StdMeshers_TrianglePreference* hyp2d = new StdMeshers_TrianglePreference(3,0,meshgen);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 0);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 1);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 2);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 3);
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

TEST(MeshBasicGeometriesSuite, testMeshBoxMEFISTO2)
{
    // create a box, mixing integers and floats
    BRepPrimAPI_MakeBox my_box(10.,10.,10.);
    my_box.Build();
    ASSERT_TRUE(my_box.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_box.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // check bounding box. It should be 10.sqrt(3)==17.32050807568877
    double diagonal_size = mesh->GetShapeDiagonalSize(mesh->GetShapeToMesh());
    ASSERT_GT(diagonal_size, 17.320508);
    ASSERT_LT(diagonal_size, 17.320509);
    // create and add hypothesis
    StdMeshers_AutomaticLength* hyp1d = new StdMeshers_AutomaticLength(0,0,meshgen);
    StdMeshers_TrianglePreference* hyp2d = new StdMeshers_TrianglePreference(1,0,meshgen);
    StdMeshers_MEFISTO_2D* mef2d = new StdMeshers_MEFISTO_2D(2,0,meshgen) ;
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 0);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 1);
    mesh->AddHypothesis(mesh->GetShapeToMesh(), 2);
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

TEST(MeshBasicGeometriesSuite, testMeshSphere)
{
    // the same as the previous test, but with a sphere
    BRepPrimAPI_MakeSphere my_sphere(10.);
    my_sphere.Build();
    ASSERT_TRUE(my_sphere.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_sphere.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

TEST(MeshBasicGeometriesSuite, testMeshTorus)
{
    // the same as the previous test, but with a sphere
    BRepPrimAPI_MakeTorus my_torus(10., 20.);
    my_torus.Build();
    ASSERT_TRUE(my_torus.IsDone());
    // create the Mesh
    SMESH_Gen* meshgen = new SMESH_Gen();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    // set geometry to be meshed
    mesh->ShapeToMesh(my_torus.Shape());
    ASSERT_TRUE(mesh->HasShapeToMesh());
    // compute the mesh
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());
    // free memory
    delete meshgen;
    delete mesh;
}

int main(int argc, char **argv){
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#pragma once

#include <type_traits>

namespace agency
{

// XXX consider whether there should be derived-from relationships between these
struct sequential_execution_tag {};
struct concurrent_execution_tag {};
struct parallel_execution_tag {};
struct vector_execution_tag {};

template<class ExecutionCategory1, class ExecutionCategory2>
struct nested_execution_tag
{
  using outer_execution_category = ExecutionCategory1;
  using inner_execution_category = ExecutionCategory2;
};

// XXX need some way to compare the strength of these at compile time
// the following

//  "<" means "is weaker than"
//  "<" is transitive
// if category A is weaker than category B,
// then agents in category A can be executed with agents in category B
//
// these relationships should be true
//
// parallel_execution_tag < sequential_execution_tag
// parallel_execution_tag < concurrent_execution_tag
// vector_execution_tag   < parallel_execution_tag
//
// XXX figure out how sequential is related to concurrent
//
// XXX figure out how nested_execution_tag sorts

namespace detail
{

template<class ExecutionCategory>
struct is_nested_execution_category : std::false_type {};

template<class ExecutionCategory1, class ExecutionCategory2>
struct is_nested_execution_category<nested_execution_tag<ExecutionCategory1,ExecutionCategory2>> : std::true_type {};

} // end detail
} // end agency

<commit_msg>Add execution_depth helper<commit_after>#pragma once

#include <type_traits>

namespace agency
{

// XXX consider whether there should be derived-from relationships between these
struct sequential_execution_tag {};
struct concurrent_execution_tag {};
struct parallel_execution_tag {};
struct vector_execution_tag {};

template<class ExecutionCategory1, class ExecutionCategory2>
struct nested_execution_tag
{
  using outer_execution_category = ExecutionCategory1;
  using inner_execution_category = ExecutionCategory2;
};

// XXX need some way to compare the strength of these at compile time
// the following

//  "<" means "is weaker than"
//  "<" is transitive
// if category A is weaker than category B,
// then agents in category A can be executed with agents in category B
//
// these relationships should be true
//
// parallel_execution_tag < sequential_execution_tag
// parallel_execution_tag < concurrent_execution_tag
// vector_execution_tag   < parallel_execution_tag
//
// XXX figure out how sequential is related to concurrent
//
// XXX figure out how nested_execution_tag sorts

namespace detail
{

template<class ExecutionCategory>
struct is_nested_execution_category : std::false_type {};

template<class ExecutionCategory1, class ExecutionCategory2>
struct is_nested_execution_category<nested_execution_tag<ExecutionCategory1,ExecutionCategory2>> : std::true_type {};

template<class ExecutionCategory>
struct execution_depth : std::integral_constant<size_t, 1> {};

template<class ExecutionCategory1, class ExecutionCategory2>
struct execution_depth<nested_execution_tag<ExecutionCategory1,ExecutionCategory2>>
  : std::integral_constant<
      size_t,
      1 + execution_depth<ExecutionCategory2>::value
    >
{};

} // end detail
} // end agency

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
#include "config.h"
#include "memcached.h"
#include "runtime.h"
#include "statemachine_mcbp.h"

#include <exception>
#include <utilities/protocol2text.h>
#include <platform/strerror.h>

const char* to_string(const Connection::Priority& priority) {
    switch (priority) {
    case Connection::Priority::High:
        return "High";
    case Connection::Priority::Medium:
        return "Medium";
    case Connection::Priority::Low:
        return "Low";
    }
    throw std::invalid_argument("No such priority: " +
                                std::to_string(int(priority)));
}

Connection::Connection(SOCKET sfd, event_base* b)
    : socketDescriptor(sfd),
      base(b),
      sasl_conn(nullptr),
      admin(false),
      authenticated(false),
      username("unknown"),
      nodelay(false),
      refcount(0),
      engine_storage(nullptr),
      next(nullptr),
      thread(nullptr),
      parent_port(0),
      auth_context(nullptr),
      bucketIndex(0),
      bucketEngine(nullptr),
      peername("unknown"),
      sockname("unknown"),
      priority(Priority::Medium) {
    MEMCACHED_CONN_CREATE(this);
}

Connection::Connection(SOCKET sock,
                       event_base* b,
                       const struct listening_port& interface)
    : Connection(sock, b)
{
    parent_port = interface.port;
    resolveConnectionName(false);
    setAuthContext(auth_create(NULL, peername.c_str(), sockname.c_str()));
    setTcpNoDelay(interface.tcp_nodelay);
}

Connection::~Connection() {
    MEMCACHED_CONN_DESTROY(this);
    auth_destroy(auth_context);
    cbsasl_dispose(&sasl_conn);
}

/**
 * Convert a sockaddr_storage to a textual string (no name lookup).
 *
 * @param addr the sockaddr_storage received from getsockname or
 *             getpeername
 * @param addr_len the current length used by the sockaddr_storage
 * @return a textual string representing the connection. or NULL
 *         if an error occurs (caller takes ownership of the buffer and
 *         must call free)
 */
static std::string sockaddr_to_string(const struct sockaddr_storage* addr,
                                      socklen_t addr_len) {
    char host[50];
    char port[50];

    int err = getnameinfo(reinterpret_cast<const struct sockaddr*>(addr),
                          addr_len,
                          host, sizeof(host),
                          port, sizeof(port),
                          NI_NUMERICHOST | NI_NUMERICSERV);
    if (err != 0) {
        LOG_WARNING(NULL, "getnameinfo failed with error %d", err);
        return NULL;
    }

    if (addr->ss_family == AF_INET6) {
        return "[" + std::string(host) + "]:" + std::string(port);
    } else {
        return std::string(host) + ":" + std::string(port);
    }
}

void Connection::resolveConnectionName(bool listening) {
    int err;
    try {
        if (listening) {
            peername = "*";
        } else {
            struct sockaddr_storage peer;
            socklen_t peer_len = sizeof(peer);
            if ((err = getpeername(socketDescriptor,
                                   reinterpret_cast<struct sockaddr*>(&peer),
                                   &peer_len)) != 0) {
                LOG_WARNING(NULL, "getpeername for socket %d with error %d",
                            socketDescriptor, err);
            } else {
                peername = sockaddr_to_string(&peer, peer_len);
            }
        }

        struct sockaddr_storage sock;
        socklen_t sock_len = sizeof(sock);
        if ((err = getsockname(socketDescriptor,
                               reinterpret_cast<struct sockaddr*>(&sock),
                               &sock_len)) != 0) {
            LOG_WARNING(NULL, "getsockname for socket %d with error %d",
                        socketDescriptor, err);
        } else {
            sockname = sockaddr_to_string(&sock, sock_len);
        }
    } catch (std::bad_alloc& e) {
        LOG_WARNING(NULL,
                    "Connection::resolveConnectionName: failed to allocate memory: %s",
                    e.what());
    }
}

bool Connection::setTcpNoDelay(bool enable) {
    int flags = enable ? 1 : 0;

#if defined(WIN32)
    char* flags_ptr = reinterpret_cast<char*>(&flags);
#else
    void* flags_ptr = reinterpret_cast<void*>(&flags);
#endif
    int error = setsockopt(socketDescriptor, IPPROTO_TCP, TCP_NODELAY,
                           flags_ptr,
                           sizeof(flags));

    if (error != 0) {
        std::string errmsg = cb_strerror(GetLastNetworkError());
        LOG_WARNING(this, "setsockopt(TCP_NODELAY): %s",
                    errmsg.c_str());
        nodelay = false;
        return false;
    } else {
        nodelay = enable;
    }

    return true;
}

/* cJSON uses double for all numbers, so only has 53 bits of precision.
 * Therefore encode 64bit integers as string.
 */
static cJSON* json_create_uintptr(uintptr_t value) {
    char buffer[32];
    if (snprintf(buffer, sizeof(buffer),
                 "0x%" PRIxPTR, value) >= int(sizeof(buffer))) {
        return cJSON_CreateString("<too long>");
    } else {
        return cJSON_CreateString(buffer);
    }
}

static void json_add_uintptr_to_object(cJSON* obj, const char* name,
                                       uintptr_t value) {
    cJSON_AddItemToObject(obj, name, json_create_uintptr(value));
}

static void json_add_bool_to_object(cJSON* obj, const char* name, bool value) {
    if (value) {
        cJSON_AddTrueToObject(obj, name);
    } else {
        cJSON_AddFalseToObject(obj, name);
    }
}

const char* to_string(const Protocol& protocol) {
    if (protocol == Protocol::Memcached) {
        return "memcached";
    } else if (protocol == Protocol::Greenstack) {
        return "greenstack";
    } else {
        return "unknown";
    }
}

const char* to_string(const ConnectionState& connectionState) {
    switch (connectionState) {
    case ConnectionState::ESTABLISHED:
        return "established";
    case ConnectionState::OPEN:
        return "open";
    case ConnectionState::AUTHENTICATED:
        return "authenticated";
    }

    throw std::logic_error(
        "Unknown connection state: " + std::to_string(int(connectionState)));
}

cJSON* Connection::toJSON() const {
    cJSON* obj = cJSON_CreateObject();
    json_add_uintptr_to_object(obj, "connection", (uintptr_t)this);
    if (socketDescriptor == INVALID_SOCKET) {
        cJSON_AddStringToObject(obj, "socket", "disconnected");
    } else {
        cJSON_AddNumberToObject(obj, "socket", (double)socketDescriptor);
        cJSON_AddStringToObject(obj, "protocol", to_string(getProtocol()));
        cJSON_AddStringToObject(obj, "peername", getPeername().c_str());
        cJSON_AddStringToObject(obj, "sockname", getSockname().c_str());
        json_add_bool_to_object(obj, "admin", isAdmin());
        if (sasl_conn != NULL) {
            json_add_uintptr_to_object(obj, "sasl_conn",
                                       (uintptr_t)sasl_conn);
        }
        json_add_bool_to_object(obj, "nodelay", nodelay);
        cJSON_AddNumberToObject(obj, "refcount", refcount);
        {
            cJSON* features = cJSON_CreateObject();
            json_add_bool_to_object(features, "datatype",
                                    isSupportsDatatype());
            json_add_bool_to_object(features, "mutation_extras",
                                    isSupportsMutationExtras());

            cJSON_AddItemToObject(obj, "features", features);
        }
        json_add_uintptr_to_object(obj, "engine_storage",
                                   (uintptr_t)engine_storage);
        json_add_uintptr_to_object(obj, "next", (uintptr_t)next);
        json_add_uintptr_to_object(obj, "thread", (uintptr_t)thread.load(
            std::memory_order::memory_order_relaxed));
        cJSON_AddNumberToObject(obj, "parent_port", parent_port);
        cJSON_AddStringToObject(obj, "priority", to_string(priority));
    }
    return obj;
}
<commit_msg>Close open sockets in the destructor<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
#include "config.h"
#include "memcached.h"
#include "runtime.h"
#include "statemachine_mcbp.h"

#include <exception>
#include <utilities/protocol2text.h>
#include <platform/strerror.h>

const char* to_string(const Connection::Priority& priority) {
    switch (priority) {
    case Connection::Priority::High:
        return "High";
    case Connection::Priority::Medium:
        return "Medium";
    case Connection::Priority::Low:
        return "Low";
    }
    throw std::invalid_argument("No such priority: " +
                                std::to_string(int(priority)));
}

Connection::Connection(SOCKET sfd, event_base* b)
    : socketDescriptor(sfd),
      base(b),
      sasl_conn(nullptr),
      admin(false),
      authenticated(false),
      username("unknown"),
      nodelay(false),
      refcount(0),
      engine_storage(nullptr),
      next(nullptr),
      thread(nullptr),
      parent_port(0),
      auth_context(nullptr),
      bucketIndex(0),
      bucketEngine(nullptr),
      peername("unknown"),
      sockname("unknown"),
      priority(Priority::Medium) {
    MEMCACHED_CONN_CREATE(this);
}

Connection::Connection(SOCKET sock,
                       event_base* b,
                       const struct listening_port& interface)
    : Connection(sock, b)
{
    parent_port = interface.port;
    resolveConnectionName(false);
    setAuthContext(auth_create(NULL, peername.c_str(), sockname.c_str()));
    setTcpNoDelay(interface.tcp_nodelay);
}

Connection::~Connection() {
    MEMCACHED_CONN_DESTROY(this);
    auth_destroy(auth_context);
    cbsasl_dispose(&sasl_conn);
    if (socketDescriptor != INVALID_SOCKET) {
        LOG_INFO(this, "%u - Closing socket descriptor", getId());
        safe_close(socketDescriptor);
    }
}

/**
 * Convert a sockaddr_storage to a textual string (no name lookup).
 *
 * @param addr the sockaddr_storage received from getsockname or
 *             getpeername
 * @param addr_len the current length used by the sockaddr_storage
 * @return a textual string representing the connection. or NULL
 *         if an error occurs (caller takes ownership of the buffer and
 *         must call free)
 */
static std::string sockaddr_to_string(const struct sockaddr_storage* addr,
                                      socklen_t addr_len) {
    char host[50];
    char port[50];

    int err = getnameinfo(reinterpret_cast<const struct sockaddr*>(addr),
                          addr_len,
                          host, sizeof(host),
                          port, sizeof(port),
                          NI_NUMERICHOST | NI_NUMERICSERV);
    if (err != 0) {
        LOG_WARNING(NULL, "getnameinfo failed with error %d", err);
        return NULL;
    }

    if (addr->ss_family == AF_INET6) {
        return "[" + std::string(host) + "]:" + std::string(port);
    } else {
        return std::string(host) + ":" + std::string(port);
    }
}

void Connection::resolveConnectionName(bool listening) {
    int err;
    try {
        if (listening) {
            peername = "*";
        } else {
            struct sockaddr_storage peer;
            socklen_t peer_len = sizeof(peer);
            if ((err = getpeername(socketDescriptor,
                                   reinterpret_cast<struct sockaddr*>(&peer),
                                   &peer_len)) != 0) {
                LOG_WARNING(NULL, "getpeername for socket %d with error %d",
                            socketDescriptor, err);
            } else {
                peername = sockaddr_to_string(&peer, peer_len);
            }
        }

        struct sockaddr_storage sock;
        socklen_t sock_len = sizeof(sock);
        if ((err = getsockname(socketDescriptor,
                               reinterpret_cast<struct sockaddr*>(&sock),
                               &sock_len)) != 0) {
            LOG_WARNING(NULL, "getsockname for socket %d with error %d",
                        socketDescriptor, err);
        } else {
            sockname = sockaddr_to_string(&sock, sock_len);
        }
    } catch (std::bad_alloc& e) {
        LOG_WARNING(NULL,
                    "Connection::resolveConnectionName: failed to allocate memory: %s",
                    e.what());
    }
}

bool Connection::setTcpNoDelay(bool enable) {
    int flags = enable ? 1 : 0;

#if defined(WIN32)
    char* flags_ptr = reinterpret_cast<char*>(&flags);
#else
    void* flags_ptr = reinterpret_cast<void*>(&flags);
#endif
    int error = setsockopt(socketDescriptor, IPPROTO_TCP, TCP_NODELAY,
                           flags_ptr,
                           sizeof(flags));

    if (error != 0) {
        std::string errmsg = cb_strerror(GetLastNetworkError());
        LOG_WARNING(this, "setsockopt(TCP_NODELAY): %s",
                    errmsg.c_str());
        nodelay = false;
        return false;
    } else {
        nodelay = enable;
    }

    return true;
}

/* cJSON uses double for all numbers, so only has 53 bits of precision.
 * Therefore encode 64bit integers as string.
 */
static cJSON* json_create_uintptr(uintptr_t value) {
    char buffer[32];
    if (snprintf(buffer, sizeof(buffer),
                 "0x%" PRIxPTR, value) >= int(sizeof(buffer))) {
        return cJSON_CreateString("<too long>");
    } else {
        return cJSON_CreateString(buffer);
    }
}

static void json_add_uintptr_to_object(cJSON* obj, const char* name,
                                       uintptr_t value) {
    cJSON_AddItemToObject(obj, name, json_create_uintptr(value));
}

static void json_add_bool_to_object(cJSON* obj, const char* name, bool value) {
    if (value) {
        cJSON_AddTrueToObject(obj, name);
    } else {
        cJSON_AddFalseToObject(obj, name);
    }
}

const char* to_string(const Protocol& protocol) {
    if (protocol == Protocol::Memcached) {
        return "memcached";
    } else if (protocol == Protocol::Greenstack) {
        return "greenstack";
    } else {
        return "unknown";
    }
}

const char* to_string(const ConnectionState& connectionState) {
    switch (connectionState) {
    case ConnectionState::ESTABLISHED:
        return "established";
    case ConnectionState::OPEN:
        return "open";
    case ConnectionState::AUTHENTICATED:
        return "authenticated";
    }

    throw std::logic_error(
        "Unknown connection state: " + std::to_string(int(connectionState)));
}

cJSON* Connection::toJSON() const {
    cJSON* obj = cJSON_CreateObject();
    json_add_uintptr_to_object(obj, "connection", (uintptr_t)this);
    if (socketDescriptor == INVALID_SOCKET) {
        cJSON_AddStringToObject(obj, "socket", "disconnected");
    } else {
        cJSON_AddNumberToObject(obj, "socket", (double)socketDescriptor);
        cJSON_AddStringToObject(obj, "protocol", to_string(getProtocol()));
        cJSON_AddStringToObject(obj, "peername", getPeername().c_str());
        cJSON_AddStringToObject(obj, "sockname", getSockname().c_str());
        json_add_bool_to_object(obj, "admin", isAdmin());
        if (sasl_conn != NULL) {
            json_add_uintptr_to_object(obj, "sasl_conn",
                                       (uintptr_t)sasl_conn);
        }
        json_add_bool_to_object(obj, "nodelay", nodelay);
        cJSON_AddNumberToObject(obj, "refcount", refcount);
        {
            cJSON* features = cJSON_CreateObject();
            json_add_bool_to_object(features, "datatype",
                                    isSupportsDatatype());
            json_add_bool_to_object(features, "mutation_extras",
                                    isSupportsMutationExtras());

            cJSON_AddItemToObject(obj, "features", features);
        }
        json_add_uintptr_to_object(obj, "engine_storage",
                                   (uintptr_t)engine_storage);
        json_add_uintptr_to_object(obj, "next", (uintptr_t)next);
        json_add_uintptr_to_object(obj, "thread", (uintptr_t)thread.load(
            std::memory_order::memory_order_relaxed));
        cJSON_AddNumberToObject(obj, "parent_port", parent_port);
        cJSON_AddStringToObject(obj, "priority", to_string(priority));
    }
    return obj;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2004 by Stanislav Karchebny                             *
 *   Stanislav.Karchebny@kdemail.net                                       *
 *                                                                         *
 *   Licensed under GPL.                                                   *
 ***************************************************************************/

#include "archive.h"
#include "feed.h"
#include "addfeeddialog.h"

#include <qcheckbox.h>

#include <kapplication.h>
#include <kurl.h>
#include <klocale.h>
#include <klineedit.h>
#include <kiconloader.h>
#include <kicontheme.h>
#include <kdebug.h>
#include <ksqueezedtextlabel.h>

using namespace Akregator;

AddFeedWidget::AddFeedWidget(QWidget *parent, const char *name)
   : AddFeedWidgetBase(parent, name)
{
    pixmapLabel1->setPixmap(kapp->iconLoader()->loadIcon( "package_network",KIcon::Desktop,KIcon::SizeHuge, KIcon::DefaultState, 0, true));
    statusLabel->setText(QString::null);
}

AddFeedWidget::~AddFeedWidget()
{}

AddFeedDialog::AddFeedDialog(QWidget *parent, const char *name)
   : KDialogBase(KDialogBase::Swallow, Qt::WStyle_DialogBorder, parent, name, true, i18n("Add Feed"), KDialogBase::Ok|KDialogBase::Cancel)
{
    feedTitle = i18n("New Feed");

    widget = new AddFeedWidget(this);
    setMainWidget(widget);
}

AddFeedDialog::~AddFeedDialog()
{}

void AddFeedDialog::setURL(const QString& t)
{
    widget->urlEdit->setText(t);
}

void AddFeedDialog::slotOk( )
{
    enableButtonOK(false);
    feedURL = widget->urlEdit->text();

    Feed *f=new Feed(NULL, NULL);

    feed=f;
    if (feedURL.find(":/") == -1)
        feedURL.prepend("http://");
    f->setXmlUrl(feedURL);

    widget->statusLabel->setText( i18n("Downloading %1").arg(feedURL) );

    connect( feed, SIGNAL(fetched(Feed* )),
             this, SLOT(fetchCompleted(Feed *)) );
    connect( feed, SIGNAL(fetchError(Feed* )),
             this, SLOT(fetchError(Feed *)) );
    connect( feed, SIGNAL(fetchDiscovery(Feed* )),
             this, SLOT(fetchDiscovery(Feed *)) );

    f->fetch(true);
}

void AddFeedDialog::fetchCompleted(Feed *f)
{
   feedTitle=f->title();
   Archive::save(f);
   KDialogBase::slotOk();
}

void AddFeedDialog::fetchError(Feed *)
{
    KDialogBase::slotOk();
}

void AddFeedDialog::fetchDiscovery(Feed *f)
{
	widget->statusLabel->setText( i18n("Feed found, downloading...") );
    feedURL=f->xmlUrl();
}

#include "addfeeddialog.moc"
<commit_msg>yes, now the error is not just in the changelog :)<commit_after>/***************************************************************************
 *   Copyright (C) 2004 by Stanislav Karchebny                             *
 *   Stanislav.Karchebny@kdemail.net                                       *
 *                                                                         *
 *   Licensed under GPL.                                                   *
 ***************************************************************************/

#include "archive.h"
#include "feed.h"
#include "addfeeddialog.h"

#include <qcheckbox.h>

#include <kapplication.h>
#include <kurl.h>
#include <klocale.h>
#include <klineedit.h>
#include <kiconloader.h>
#include <kicontheme.h>
#include <kdebug.h>
#include <ksqueezedtextlabel.h>
#include <kmessagebox.h>

using namespace Akregator;

AddFeedWidget::AddFeedWidget(QWidget *parent, const char *name)
   : AddFeedWidgetBase(parent, name)
{
    pixmapLabel1->setPixmap(kapp->iconLoader()->loadIcon( "package_network",KIcon::Desktop,KIcon::SizeHuge, KIcon::DefaultState, 0, true));
    statusLabel->setText(QString::null);
}

AddFeedWidget::~AddFeedWidget()
{}

AddFeedDialog::AddFeedDialog(QWidget *parent, const char *name)
   : KDialogBase(KDialogBase::Swallow, Qt::WStyle_DialogBorder, parent, name, true, i18n("Add Feed"), KDialogBase::Ok|KDialogBase::Cancel)
{
    feedTitle = i18n("New Feed");

    widget = new AddFeedWidget(this);
    setMainWidget(widget);
}

AddFeedDialog::~AddFeedDialog()
{}

void AddFeedDialog::setURL(const QString& t)
{
    widget->urlEdit->setText(t);
}

void AddFeedDialog::slotOk( )
{
    enableButtonOK(false);
    feedURL = widget->urlEdit->text();

    Feed *f=new Feed(NULL, NULL);

    feed=f;
    if (feedURL.find(":/") == -1)
        feedURL.prepend("http://");
    f->setXmlUrl(feedURL);

    widget->statusLabel->setText( i18n("Downloading %1").arg(feedURL) );

    connect( feed, SIGNAL(fetched(Feed* )),
             this, SLOT(fetchCompleted(Feed *)) );
    connect( feed, SIGNAL(fetchError(Feed* )),
             this, SLOT(fetchError(Feed *)) );
    connect( feed, SIGNAL(fetchDiscovery(Feed* )),
             this, SLOT(fetchDiscovery(Feed *)) );

    f->fetch(true);
}

void AddFeedDialog::fetchCompleted(Feed *f)
{
   feedTitle=f->title();
   Archive::save(f);
   KDialogBase::slotOk();
}

void AddFeedDialog::fetchError(Feed *)
{
    KMessageBox::error(this, i18n("Feed not found from %1.").arg(feedURL));
    KDialogBase::slotCancel();
}

void AddFeedDialog::fetchDiscovery(Feed *f)
{
	widget->statusLabel->setText( i18n("Feed found, downloading...") );
    feedURL=f->xmlUrl();
}

#include "addfeeddialog.moc"
<|endoftext|>


<commit_before>#include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
#include <stan/math/rev/mat.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/rev/mat/util.hpp>
// For speed comparisons
#include <chrono>
#include <test/unit/math/rev/mat/prob/multi_normal_cholesky_old.hpp>
#include <stan/math/prim/mat/prob/lkj_corr_cholesky_rng.hpp>
#include <boost/random/mersenne_twister.hpp>

using Eigen::Dynamic;
using Eigen::Matrix;
using std::vector;

TEST(ProbDistributionsMultiNormalCholesky, MultiNormalVar) {
  using stan::math::var;
  Matrix<var, Dynamic, 1> y(3, 1);
  y << 2.0, -2.0, 11.0;
  Matrix<var, Dynamic, 1> mu(3, 1);
  mu << 1.0, -1.0, 3.0;
  Matrix<var, Dynamic, Dynamic> Sigma(3, 3);
  Sigma << 9.0, -3.0, 0.0, -3.0, 4.0, 0.0, 0.0, 0.0, 5.0;
  Matrix<var, Dynamic, Dynamic> L = Sigma.llt().matrixL();
  EXPECT_FLOAT_EQ(-11.73908,
                  stan::math::multi_normal_cholesky_log(y, mu, L).val());
}

TEST(AgradRev, check_varis_on_stack) {
  using stan::math::to_var;
  Matrix<double, Dynamic, 1> y(3, 1);
  y << 2.0, -2.0, 11.0;
  Matrix<double, Dynamic, 1> mu(3, 1);
  mu << 1.0, -1.0, 3.0;
  Matrix<double, Dynamic, Dynamic> Sigma(3, 3);
  Sigma << 9.0, -3.0, 0.0, -3.0, 4.0, 0.0, 0.0, 0.0, 5.0;
  Matrix<double, Dynamic, Dynamic> L = Sigma.llt().matrixL();
  test::check_varis_on_stack(stan::math::multi_normal_cholesky_log<true>(
      to_var(y), to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(to_var(y), to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(to_var(y), mu, to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(to_var(y), mu, L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(y, to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(y, to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(y, mu, to_var(L)));

  test::check_varis_on_stack(stan::math::multi_normal_cholesky_log<false>(
      to_var(y), to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(to_var(y), to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(to_var(y), mu, to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(to_var(y), mu, L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(y, to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(y, to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(y, mu, to_var(L)));
}

//  Here, we compare the speed of the new regression to that of one built from
//  existing primitives.

TEST(ProbDistributionsMultiNormalCholesky, mvn_speed) {
  using Eigen::Dynamic;
  using Eigen::Matrix;
  using stan::math::var;

  typedef std::chrono::high_resolution_clock::time_point TimeVar;
#define duration(a) \
  std::chrono::duration_cast<std::chrono::microseconds>(a).count()
#define timeNow() std::chrono::high_resolution_clock::now()

  const int R = 5000;
  const int C = 200;

  boost::random::mt19937 rng;

  int T1 = 0;
  int T2 = 0;
  for (size_t testnumber = 0; testnumber < 30; testnumber++) {
    std::vector<Matrix<double, Dynamic, 1>> Y_dbl;

    for (size_t i = 0; i < R; i++) {
      Matrix<double, Dynamic, 1> y_dbl = Eigen::VectorXd::Random(C);
      Y_dbl.push_back(y_dbl);
    }

    Matrix<double, Dynamic, 1> mu_dbl
        = Matrix<double, Dynamic, Dynamic>::Random(C, 1);

    Matrix<double, Dynamic, 1> sigma_dbl
        = Eigen::MatrixXd::Constant(C, 1, 0.01)
          + Matrix<double, Dynamic, 1>::Random(C, 1).array().abs().matrix();
    Matrix<double, Dynamic, Dynamic> L_Sigma_dbl
        = sigma_dbl.asDiagonal()
          * stan::math::lkj_corr_cholesky_rng(C, 1.0, rng);

    Matrix<var, Dynamic, 1> mu_v1 = mu_dbl;
    Matrix<var, Dynamic, Dynamic> L_Sigma_v1 = L_Sigma_dbl;
    std::vector<Matrix<var, Dynamic, 1>> Y_v1;
    for (size_t i = 0; i < R; i++) {
      Y_v1.push_back(Y_dbl[i]);
    }

    TimeVar t1 = timeNow();

    var lp1
        = stan::math::multi_normal_cholesky_old_lpdf(Y_v1, mu_v1, L_Sigma_v1);
    lp1.grad();

    TimeVar t2 = timeNow();
    stan::math::recover_memory();

    Matrix<var, Dynamic, 1> mu_v2 = mu_dbl;
    Matrix<var, Dynamic, Dynamic> L_Sigma_v2 = L_Sigma_dbl;
    std::vector<Matrix<var, Dynamic, 1>> Y_v2;
    for (size_t i = 0; i < R; i++) {
      Y_v2.push_back(Y_dbl[i]);
    }

    TimeVar t3 = timeNow();

    var lp2 = stan::math::multi_normal_cholesky_lpdf(Y_v2, mu_v2, L_Sigma_v2);
    lp2.grad();

    TimeVar t4 = timeNow();

    stan::math::recover_memory();

    T1 += duration(t2 - t1);
    T2 += duration(t4 - t3);
  }
  std::cout << "Existing Primitives:" << std::endl
            << T1 << std::endl
            << "New Primitives:" << std::endl
            << T2 << std::endl;
}
<commit_msg>change peformacne test<commit_after>#include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
#include <stan/math/rev/mat.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/rev/mat/util.hpp>
// For speed comparisons
#include <chrono>
#include <test/unit/math/rev/mat/prob/multi_normal_cholesky_old.hpp>
#include <stan/math/prim/mat/prob/lkj_corr_cholesky_rng.hpp>
#include <boost/random/mersenne_twister.hpp>

using Eigen::Dynamic;
using Eigen::Matrix;
using std::vector;

TEST(ProbDistributionsMultiNormalCholesky, MultiNormalVar) {
  using stan::math::var;
  Matrix<var, Dynamic, 1> y(3, 1);
  y << 2.0, -2.0, 11.0;
  Matrix<var, Dynamic, 1> mu(3, 1);
  mu << 1.0, -1.0, 3.0;
  Matrix<var, Dynamic, Dynamic> Sigma(3, 3);
  Sigma << 9.0, -3.0, 0.0, -3.0, 4.0, 0.0, 0.0, 0.0, 5.0;
  Matrix<var, Dynamic, Dynamic> L = Sigma.llt().matrixL();
  EXPECT_FLOAT_EQ(-11.73908,
                  stan::math::multi_normal_cholesky_log(y, mu, L).val());
}

TEST(AgradRev, check_varis_on_stack) {
  using stan::math::to_var;
  Matrix<double, Dynamic, 1> y(3, 1);
  y << 2.0, -2.0, 11.0;
  Matrix<double, Dynamic, 1> mu(3, 1);
  mu << 1.0, -1.0, 3.0;
  Matrix<double, Dynamic, Dynamic> Sigma(3, 3);
  Sigma << 9.0, -3.0, 0.0, -3.0, 4.0, 0.0, 0.0, 0.0, 5.0;
  Matrix<double, Dynamic, Dynamic> L = Sigma.llt().matrixL();
  test::check_varis_on_stack(stan::math::multi_normal_cholesky_log<true>(
      to_var(y), to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(to_var(y), to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(to_var(y), mu, to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(to_var(y), mu, L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(y, to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(y, to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<true>(y, mu, to_var(L)));

  test::check_varis_on_stack(stan::math::multi_normal_cholesky_log<false>(
      to_var(y), to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(to_var(y), to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(to_var(y), mu, to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(to_var(y), mu, L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(y, to_var(mu), to_var(L)));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(y, to_var(mu), L));
  test::check_varis_on_stack(
      stan::math::multi_normal_cholesky_log<false>(y, mu, to_var(L)));
}

//  Here, we compare the speed of the new regression to that of one built from
//  existing primitives.

TEST(ProbDistributionsMultiNormalCholesky, mvn_speed) {
  using Eigen::Dynamic;
  using Eigen::Matrix;
  using stan::math::var;

  typedef std::chrono::high_resolution_clock::time_point TimeVar;
#define duration(a) \
  std::chrono::duration_cast<std::chrono::microseconds>(a).count()
#define timeNow() std::chrono::high_resolution_clock::now()

  const int R = 1000;
  const int C = 600;

  boost::random::mt19937 rng;

  int T1 = 0;
  int T2 = 0;
  for (size_t testnumber = 0; testnumber < 30; testnumber++) {
    std::vector<Matrix<double, Dynamic, 1>> Y_dbl;

    for (size_t i = 0; i < R; i++) {
      Matrix<double, Dynamic, 1> y_dbl = Eigen::VectorXd::Random(C);
      Y_dbl.push_back(y_dbl);
    }

    Matrix<double, Dynamic, 1> mu_dbl
        = Matrix<double, Dynamic, Dynamic>::Random(C, 1);

    Matrix<double, Dynamic, 1> sigma_dbl
        = Eigen::MatrixXd::Constant(C, 1, 0.01)
          + Matrix<double, Dynamic, 1>::Random(C, 1).array().abs().matrix();
    Matrix<double, Dynamic, Dynamic> L_Sigma_dbl
        = sigma_dbl.asDiagonal()
          * stan::math::lkj_corr_cholesky_rng(C, 1.0, rng);

    Matrix<var, Dynamic, 1> mu_v1 = mu_dbl;
    Matrix<var, Dynamic, Dynamic> L_Sigma_v1 = L_Sigma_dbl;
    std::vector<Matrix<var, Dynamic, 1>> Y_v1;
    for (size_t i = 0; i < R; i++) {
      Y_v1.push_back(Y_dbl[i]);
    }

    TimeVar t1 = timeNow();

    var lp1
        = stan::math::multi_normal_cholesky_old_lpdf(Y_v1, mu_v1, L_Sigma_v1);
    lp1.grad();

    TimeVar t2 = timeNow();
    stan::math::recover_memory();

    Matrix<var, Dynamic, 1> mu_v2 = mu_dbl;
    Matrix<var, Dynamic, Dynamic> L_Sigma_v2 = L_Sigma_dbl;
    std::vector<Matrix<var, Dynamic, 1>> Y_v2;
    for (size_t i = 0; i < R; i++) {
      Y_v2.push_back(Y_dbl[i]);
    }

    TimeVar t3 = timeNow();

    var lp2 = stan::math::multi_normal_cholesky_lpdf(Y_v2, mu_v2, L_Sigma_v2);
    lp2.grad();

    TimeVar t4 = timeNow();

    stan::math::recover_memory();

    T1 += duration(t2 - t1);
    T2 += duration(t4 - t3);
  }
  std::cout << "Existing Primitives:" << std::endl
            << T1 << std::endl
            << "New Primitives:" << std::endl
            << T2 << std::endl;
}
<|endoftext|>


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

#include "repository.h"
#include "commit.h"
#include "tree.h"
#include "index.h"
#include "tag.h"
#include "rev_walker.h"
#include "rawobj.h"
#include "ref.h"

namespace gitteh {

Persistent<FunctionTemplate> Repository::constructor_template;

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

	Local<FunctionTemplate> t = FunctionTemplate::New(New);
	constructor_template = Persistent<FunctionTemplate>::New(t);
	constructor_template->SetClassName(String::New("Repository"));
	t->InstanceTemplate()->SetInternalFieldCount(1);

	NODE_SET_PROTOTYPE_METHOD(t, "getCommit", GetCommit);
	NODE_SET_PROTOTYPE_METHOD(t, "getTree", GetTree);
	NODE_SET_PROTOTYPE_METHOD(t, "getTag", GetTag);
	NODE_SET_PROTOTYPE_METHOD(t, "getRawObject", GetRawObject);
	NODE_SET_PROTOTYPE_METHOD(t, "getReference", GetReference);

	NODE_SET_PROTOTYPE_METHOD(t, "createWalker", CreateWalker);
	NODE_SET_PROTOTYPE_METHOD(t, "createRawObject", CreateRawObject);
	NODE_SET_PROTOTYPE_METHOD(t, "createTag", CreateTag);
	NODE_SET_PROTOTYPE_METHOD(t, "createTree", CreateTree);
	NODE_SET_PROTOTYPE_METHOD(t, "createCommit", CreateCommit);
	NODE_SET_PROTOTYPE_METHOD(t, "createOidReference", CreateOidRef);
	NODE_SET_PROTOTYPE_METHOD(t, "createSymbolicReference", CreateSymbolicRef);

	NODE_SET_PROTOTYPE_METHOD(t, "exists", Exists);

	t->InstanceTemplate()->SetAccessor(String::New("index"), IndexGetter);

	target->Set(String::New("Repository"), t->GetFunction());
}

Handle<Value> Repository::New(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_STR_ARG(0, path);

	Repository *repo = new Repository();

	if(int result = git_repository_open(&repo->repo_, *path) != GIT_SUCCESS) {
		Handle<Value> ex = Exception::Error(String::New("Git error."));
		return ThrowException(ex);
	}

	repo->path_ = *path;

	args.This()->Set(String::New("path"), String::New(repo->path_), ReadOnly);

	repo->odb_ = git_repository_database(repo->repo_);

	repo->Wrap(args.This());
	return args.This();
}

Handle<Value> Repository::GetCommit(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_OID_ARG(0, commitOid);

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_commit* commit;
	if(git_commit_lookup(&commit, repo->repo_, &commitOid) != GIT_SUCCESS) {
		// TODO: error code handling.
		return scope.Close(Null());
	}

	Commit *commitObject = repo->wrapCommit(commit);
	return scope.Close(commitObject->handle_);
}

Handle<Value> Repository::GetTree(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_OID_ARG(0, treeOid);

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tree *tree;
	if(git_tree_lookup(&tree, repo->repo_, &treeOid) != GIT_SUCCESS) {
		return scope.Close(Null());
	}

	Tree *treeObject = repo->wrapTree(tree);
	return scope.Close(treeObject->handle_);
}

Handle<Value> Repository::GetTag(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_OID_ARG(0, tagOid);

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tag *tag;
	int res = git_tag_lookup(&tag, repo->repo_, &tagOid);
	if(res != GIT_SUCCESS)
		THROW_GIT_ERROR("Couldn't get tag.", res);

	Tag *tagObj = repo->wrapTag(tag);
	return scope.Close(tagObj->handle_);
}

Handle<Value> Repository::GetRawObject(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_OID_ARG(0, oid);

	git_rawobj *obj = new git_rawobj;
	int res = git_odb_read(obj, repo->odb_, &oid);
	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't load raw object.", res);
	}

	Local<Value> arg = External::New(obj);
	Persistent<Object> result(RawObject::constructor_template->GetFunction()->NewInstance(1, &arg));
	return scope.Close(result);
}

Handle<Value> Repository::CreateRawObject(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	// Initialize a new rawobj.
	git_rawobj *rawObj = new git_rawobj;
	rawObj->len = 0;
	rawObj->type = GIT_OBJ_BAD;

	Handle<Value> constructorArgs[1] = { External::New(rawObj) };
	Handle<Object> jsObject = RawObject::constructor_template->GetFunction()->NewInstance(1, constructorArgs);

	RawObject *rawObjObj = ObjectWrap::Unwrap<RawObject>(jsObject);
	rawObjObj->repository_ = repo;
	return scope.Close(jsObject);
}

Handle<Value> Repository::CreateWalker(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_revwalk *walker;
	int res = git_revwalk_new(&walker, repo->repo_);
	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't create revision walker", res);
	}

	Handle<Value> constructorArgs[2] = { External::New(walker), External::New(repo) };
	Handle<Object> instance = RevWalker::constructor_template->GetFunction()->NewInstance(2, constructorArgs);

	RevWalker *walkerObject = ObjectWrap::Unwrap<RevWalker>(instance);
	return scope.Close(walkerObject->handle_);
}

Handle<Value> Repository::IndexGetter(Local<String>, const AccessorInfo& info) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(info.This());
	if(repo->index_ == NULL) {
		git_index *index;
		int result = git_repository_index(&index, repo->repo_);
		if(result == GIT_EBAREINDEX) {
			git_index_open_bare(&index, repo->path_);
		}

		Handle<Value> arg = External::New(index);
		Handle<Object> instance = Index::constructor_template->GetFunction()->NewInstance(1, &arg);
		repo->index_ = ObjectWrap::Unwrap<Index>(instance);
	}

	return repo->index_->handle_;
}

Handle<Value> Repository::CreateTag(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tag *tag;
	int res = git_tag_new(&tag, repo->repo_);
	if(res != GIT_SUCCESS)
		THROW_GIT_ERROR("Couldn't create new tag.", res);

	Tag *tagObject = repo->wrapTag(tag);
	return scope.Close(tagObject->handle_);
}

Handle<Value> Repository::CreateTree(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tree *tree;
	int res = git_tree_new(&tree, repo->repo_);
	if(res != GIT_SUCCESS)
		THROW_GIT_ERROR("Couldn't create tree.", res);

	Tree *treeObject = repo->wrapTree(tree);
	return treeObject->handle_;
}

Handle<Value> Repository::CreateCommit(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_commit *commit;
	int result = git_commit_new(&commit, repo->repo_);

	if(result != GIT_SUCCESS) {
		// TODO: error handling.
		return Null();
	}

	Commit *commitObject = repo->wrapCommit(commit);
	return scope.Close(commitObject->handle_);
}

Handle<Value> Repository::GetReference(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_STR_ARG(0, referenceName);

	git_reference *reference;
	int result = git_reference_lookup(&reference, repo->repo_, *referenceName);
	if(result != GIT_SUCCESS)
		THROW_GIT_ERROR("Failed to load ref.", result);

	Reference *refObj = repo->wrapReference(reference);
	return scope.Close(refObj->handle_);
}

Handle<Value> Repository::CreateSymbolicRef(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_STR_ARG(0, nameArg);
	REQ_STR_ARG(1, targetArg);

	if(!nameArg.length()) {
		THROW_ERROR("Please provide a name.");
	}

	if(!targetArg.length()) {
		THROW_ERROR("Please provide a target for the symbolic ref.");
	}

	git_reference *ref;
	int res = git_reference_create_symbolic(&ref, repo->repo_, *nameArg, *targetArg);

	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't create reference.", res);
	}

	Reference *refObj = repo->wrapReference(ref);
	return scope.Close(refObj->handle_);
}

Handle<Value> Repository::CreateOidRef(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(2);
	REQ_STR_ARG(0, nameArg);
	REQ_OID_ARG(1, oidArg);

	if(!nameArg.length()) {
		THROW_ERROR("Please provide a name.");
	}

	git_reference *ref;
	int res = git_reference_create_oid(&ref, repo->repo_, *nameArg, &oidArg);
	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't create reference.", res);
	}

	Reference *refObj = repo->wrapReference(ref);
	return scope.Close(refObj->handle_);
}

Handle<Value> Repository::Exists(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_OID_ARG(0, objOid);

	return Boolean::New(git_odb_exists(repo->odb_, &objOid));
}

Repository::~Repository() {
	close();
}

void Repository::close() {
	if(repo_) {
		git_repository_free(repo_);
		repo_ = NULL;
	}
}

Commit *Repository::wrapCommit(git_commit *commit) {
	Commit *commitObject;
	if(commitStore_.getObjectFor(commit, &commitObject)) {
		// Commit needs to know who it's daddy is.
		commitObject->repository_ = this;
	}

	return commitObject;
}

Tree *Repository::wrapTree(git_tree *tree) {
	Tree *treeObject;
	if(treeStore_.getObjectFor(tree, &treeObject)) {
		treeObject->repository_ = this;
	}

	return treeObject;
}

Tag *Repository::wrapTag(git_tag *tag) {
	Tag *tagObject;
	if(tagStore_.getObjectFor(tag, &tagObject)) {
		tagObject->repository_ = this;
	}

	return tagObject;
}

Reference *Repository::wrapReference(git_reference *ref) {
	Reference *refObj;
	if(refStore_.getObjectFor(ref, &refObj)) {
		refObj->repository_ = this;
	}

	return refObj;
}

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

#include "repository.h"
#include "commit.h"
#include "tree.h"
#include "index.h"
#include "tag.h"
#include "rev_walker.h"
#include "rawobj.h"
#include "ref.h"

namespace gitteh {

Persistent<FunctionTemplate> Repository::constructor_template;

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

	Local<FunctionTemplate> t = FunctionTemplate::New(New);
	constructor_template = Persistent<FunctionTemplate>::New(t);
	constructor_template->SetClassName(String::New("Repository"));
	t->InstanceTemplate()->SetInternalFieldCount(1);

	NODE_SET_PROTOTYPE_METHOD(t, "getCommit", GetCommit);
	NODE_SET_PROTOTYPE_METHOD(t, "getTree", GetTree);
	NODE_SET_PROTOTYPE_METHOD(t, "getTag", GetTag);
	NODE_SET_PROTOTYPE_METHOD(t, "getRawObject", GetRawObject);
	NODE_SET_PROTOTYPE_METHOD(t, "getReference", GetReference);

	NODE_SET_PROTOTYPE_METHOD(t, "createWalker", CreateWalker);
	NODE_SET_PROTOTYPE_METHOD(t, "createRawObject", CreateRawObject);
	NODE_SET_PROTOTYPE_METHOD(t, "createTag", CreateTag);
	NODE_SET_PROTOTYPE_METHOD(t, "createTree", CreateTree);
	NODE_SET_PROTOTYPE_METHOD(t, "createCommit", CreateCommit);
	NODE_SET_PROTOTYPE_METHOD(t, "createOidReference", CreateOidRef);
	NODE_SET_PROTOTYPE_METHOD(t, "createSymbolicReference", CreateSymbolicRef);

	NODE_SET_PROTOTYPE_METHOD(t, "exists", Exists);

	t->InstanceTemplate()->SetAccessor(String::New("index"), IndexGetter);

	target->Set(String::New("Repository"), t->GetFunction());
}

Handle<Value> Repository::New(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_STR_ARG(0, path);

	Repository *repo = new Repository();

	if(int result = git_repository_open(&repo->repo_, *path) != GIT_SUCCESS) {
		Handle<Value> ex = Exception::Error(String::New("Git error."));
		return ThrowException(ex);
	}

	repo->path_ = *path;

	args.This()->Set(String::New("path"), String::New(repo->path_), ReadOnly);

	repo->odb_ = git_repository_database(repo->repo_);

	repo->Wrap(args.This());
	return args.This();
}

Handle<Value> Repository::GetCommit(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_OID_ARG(0, commitOid);

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_commit* commit;
	if(git_commit_lookup(&commit, repo->repo_, &commitOid) != GIT_SUCCESS) {
		// TODO: error code handling.
		return scope.Close(Null());
	}

	Commit *commitObject = repo->wrapCommit(commit);
	return scope.Close(commitObject->handle_);
}

Handle<Value> Repository::GetTree(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_OID_ARG(0, treeOid);

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tree *tree;
	if(git_tree_lookup(&tree, repo->repo_, &treeOid) != GIT_SUCCESS) {
		return scope.Close(Null());
	}

	Tree *treeObject = repo->wrapTree(tree);
	return scope.Close(treeObject->handle_);
}

Handle<Value> Repository::GetTag(const Arguments& args) {
	HandleScope scope;

	REQ_ARGS(1);
	REQ_OID_ARG(0, tagOid);

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tag *tag;
	int res = git_tag_lookup(&tag, repo->repo_, &tagOid);
	if(res != GIT_SUCCESS)
		THROW_GIT_ERROR("Couldn't get tag.", res);

	Tag *tagObj = repo->wrapTag(tag);
	return scope.Close(tagObj->handle_);
}

Handle<Value> Repository::GetRawObject(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_OID_ARG(0, oid);

	git_rawobj *obj = new git_rawobj;
	int res = git_odb_read(obj, repo->odb_, &oid);
	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't load raw object.", res);
	}

	Local<Value> arg = External::New(obj);
	Persistent<Object> result(RawObject::constructor_template->GetFunction()->NewInstance(1, &arg));
	return scope.Close(result);
}

Handle<Value> Repository::CreateRawObject(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	// Initialize a new rawobj.
	git_rawobj *rawObj = new git_rawobj;
	rawObj->len = 0;
	rawObj->type = GIT_OBJ_BAD;

	Handle<Value> constructorArgs[1] = { External::New(rawObj) };
	Handle<Object> jsObject = RawObject::constructor_template->GetFunction()->NewInstance(1, constructorArgs);

	RawObject *rawObjObj = ObjectWrap::Unwrap<RawObject>(jsObject);
	rawObjObj->repository_ = repo;
	return scope.Close(jsObject);
}

Handle<Value> Repository::CreateWalker(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_revwalk *walker;
	int res = git_revwalk_new(&walker, repo->repo_);
	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't create revision walker", res);
	}

	Handle<Value> constructorArgs[2] = { External::New(walker), External::New(repo) };
	Handle<Object> instance = RevWalker::constructor_template->GetFunction()->NewInstance(2, constructorArgs);

	RevWalker *walkerObject = ObjectWrap::Unwrap<RevWalker>(instance);
	return scope.Close(walkerObject->handle_);
}

Handle<Value> Repository::IndexGetter(Local<String>, const AccessorInfo& info) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(info.This());
	if(repo->index_ == NULL) {
		git_index *index;
		int result = git_repository_index(&index, repo->repo_);
		if(result == GIT_EBAREINDEX) {
			git_index_open_bare(&index, repo->path_);
		}

		Handle<Value> arg = External::New(index);
		Handle<Object> instance = Index::constructor_template->GetFunction()->NewInstance(1, &arg);
		repo->index_ = ObjectWrap::Unwrap<Index>(instance);
	}

	return repo->index_->handle_;
}

Handle<Value> Repository::CreateTag(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tag *tag;
	int res = git_tag_new(&tag, repo->repo_);
	if(res != GIT_SUCCESS)
		THROW_GIT_ERROR("Couldn't create new tag.", res);

	Tag *tagObject = repo->wrapTag(tag);
	return scope.Close(tagObject->handle_);
}

Handle<Value> Repository::CreateTree(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_tree *tree;
	int res = git_tree_new(&tree, repo->repo_);
	if(res != GIT_SUCCESS)
		THROW_GIT_ERROR("Couldn't create tree.", res);

	Tree *treeObject = repo->wrapTree(tree);
	return treeObject->handle_;
}

Handle<Value> Repository::CreateCommit(const Arguments& args) {
	HandleScope scope;

	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	git_commit *commit;
	int result = git_commit_new(&commit, repo->repo_);

	if(result != GIT_SUCCESS) {
		// TODO: error handling.
		return Null();
	}

	Commit *commitObject = repo->wrapCommit(commit);
	return scope.Close(commitObject->handle_);
}

Handle<Value> Repository::GetReference(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_STR_ARG(0, referenceName);

	git_reference *reference;
	int result = git_reference_lookup(&reference, repo->repo_, *referenceName);
	if(result != GIT_SUCCESS)
		THROW_GIT_ERROR("Failed to load ref.", result);

	Reference *refObj = repo->wrapReference(reference);
	return scope.Close(refObj->handle_);
}

Handle<Value> Repository::CreateSymbolicRef(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(2);
	REQ_STR_ARG(0, nameArg);
	REQ_STR_ARG(1, targetArg);

	if(!nameArg.length()) {
		THROW_ERROR("Please provide a name.");
	}

	if(!targetArg.length()) {
		THROW_ERROR("Please provide a target for the symbolic ref.");
	}

	git_reference *ref;
	int res = git_reference_create_symbolic(&ref, repo->repo_, *nameArg, *targetArg);

	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't create reference.", res);
	}

	Reference *refObj = repo->wrapReference(ref);
	return scope.Close(refObj->handle_);
}

Handle<Value> Repository::CreateOidRef(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(2);
	REQ_STR_ARG(0, nameArg);
	REQ_OID_ARG(1, oidArg);

	if(!nameArg.length()) {
		THROW_ERROR("Please provide a name.");
	}

	git_reference *ref;
	int res = git_reference_create_oid(&ref, repo->repo_, *nameArg, &oidArg);
	if(res != GIT_SUCCESS) {
		THROW_GIT_ERROR("Couldn't create reference.", res);
	}

	Reference *refObj = repo->wrapReference(ref);
	return scope.Close(refObj->handle_);
}

Handle<Value> Repository::Exists(const Arguments& args) {
	HandleScope scope;
	Repository *repo = ObjectWrap::Unwrap<Repository>(args.This());

	REQ_ARGS(1);
	REQ_OID_ARG(0, objOid);

	return Boolean::New(git_odb_exists(repo->odb_, &objOid));
}

Repository::~Repository() {
	close();
}

void Repository::close() {
	if(repo_) {
		git_repository_free(repo_);
		repo_ = NULL;
	}
}

Commit *Repository::wrapCommit(git_commit *commit) {
	Commit *commitObject;
	if(commitStore_.getObjectFor(commit, &commitObject)) {
		// Commit needs to know who it's daddy is.
		commitObject->repository_ = this;
	}

	return commitObject;
}

Tree *Repository::wrapTree(git_tree *tree) {
	Tree *treeObject;
	if(treeStore_.getObjectFor(tree, &treeObject)) {
		treeObject->repository_ = this;
	}

	return treeObject;
}

Tag *Repository::wrapTag(git_tag *tag) {
	Tag *tagObject;
	if(tagStore_.getObjectFor(tag, &tagObject)) {
		tagObject->repository_ = this;
	}

	return tagObject;
}

Reference *Repository::wrapReference(git_reference *ref) {
	Reference *refObj;
	if(refStore_.getObjectFor(ref, &refObj)) {
		refObj->repository_ = this;
	}

	return refObj;
}

} // namespace gitteh
<|endoftext|>