<commit_before>#include "string.hh"

#include "exception.hh"
#include "containers.hh"
#include "utf8_iterator.hh"
#include "unit_tests.hh"

#include <cstdio>

namespace Kakoune
{

Vector<String> split(StringView str, char separator, char escape)
{
    Vector<String> res;
    auto it = str.begin();
    while (it != str.end())
    {
        res.emplace_back();
        String& element = res.back();
        while (it != str.end())
        {
            auto c = *it;
            if (c == escape and it + 1 != str.end() and *(it+1) == separator)
            {
                element += separator;
                it += 2;
            }
            else if (c == separator)
            {
                ++it;
                break;
            }
            else
            {
                element += c;
                ++it;
            }
        }
    }
    return res;
}

Vector<StringView> split(StringView str, char separator)
{
    Vector<StringView> res;
    auto beg = str.begin();
    for (auto it = beg; it != str.end(); ++it)
    {
        if (*it == separator)
        {
            res.emplace_back(beg, it);
            beg = it + 1;
        }
    }
    res.emplace_back(beg, str.end());
    return res;
}

String escape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto it = str.begin(), end = str.end(); it != end; )
    {
        auto next = std::find_if(it, end, [&characters](char c) { return contains(characters, c); });
        if (next != end)
        {
            res += StringView{it, next+1};
            res.back() = escape;
            res += *next;
            it = next+1;
        }
        else
        {
            res += StringView{it, next};
            break;
        }
    }
    return res;
}

String unescape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto it = str.begin(), end = str.end(); it != end; )
    {
        auto next = std::find(it, end, escape);
        if (next != end and next+1 != end and contains(characters, *(next+1)))
        {
            res += StringView{it, next+1};
            res.back() = *(next+1);
            it = next + 2;
        }
        else
        {
            res += StringView{it, next == end ? next : next + 1};
            it = next == end ? next : next + 1;
        }
    }
    return res;
}

String indent(StringView str, StringView indent)
{
    String res;
    res.reserve(str.length());
    bool was_eol = true;
    for (ByteCount i = 0; i < str.length(); ++i)
    {
        if (was_eol)
            res += indent;
        res += str[i];
        was_eol = is_eol(str[i]);
    }
    return res;
}

Optional<int> str_to_int_ifp(StringView str)
{
    unsigned int res = 0;
    bool negative = false;
    for (auto it = str.begin(), end = str.end(); it != end; ++it)
    {
        const char c = *it;
        if (it == str.begin() and c == '-')
            negative = true;
        else if (c >= '0' and c <= '9')
            res = res * 10 + c - '0';
        else
            return {};
    }
    return negative ? -(int)res : (int)res;
}

int str_to_int(StringView str)
{
    if (auto val = str_to_int_ifp(str))
        return *val;
    throw runtime_error{str + " is not a number"};
}

InplaceString<15> to_string(int val)
{
    InplaceString<15> res;
    res.m_length = sprintf(res.m_data, "%i", val);
    return res;
}

InplaceString<23> to_string(long int val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%li", val);
    return res;
}

InplaceString<23> to_string(size_t val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%zu", val);
    return res;
}

InplaceString<23> to_string(Hex val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%zx", val.val);
    return res;
}

InplaceString<23> to_string(float val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%f", val);
    return res;
}

InplaceString<7> to_string(Codepoint c)
{
    InplaceString<7> res;
    char* ptr = res.m_data;
    utf8::dump(ptr, c);
    res.m_length = (int)(ptr - res.m_data);
    return res;
}

bool subsequence_match(StringView str, StringView subseq)
{
    auto it = str.begin();
    for (auto& c : subseq)
    {
        if (it == str.end())
            return false;
        while (*it != c)
        {
            if (++it == str.end())
                return false;
        }
        ++it;
    }
    return true;
}

String expand_tabs(StringView line, CharCount tabstop, CharCount col)
{
    String res;
    res.reserve(line.length());
    for (auto it = line.begin(), end = line.end(); it != end; )
    {
        if (*it == '\t')
        {
            CharCount end_col = (col / tabstop + 1) * tabstop;
            res += String{' ', end_col - col};
            col = end_col;
            ++it;
        }
        else
        {
            auto char_end = utf8::next(it, end);
            res += {it, char_end};
            ++col;
            it = char_end;
        }
    }
    return res;
}

Vector<StringView> wrap_lines(StringView text, CharCount max_width)
{
    if (max_width <= 0)
        throw runtime_error("Invalid max width");

    using Utf8It = utf8::iterator<const char*>;
    Utf8It word_begin{text.begin(), text};
    Utf8It word_end{word_begin};
    Utf8It end{text.end(), text};
    CharCount col = 0;
    Vector<StringView> lines;
    Utf8It line_begin{text.begin(), text};
    Utf8It line_end = line_begin;
    while (word_begin != end)
    {
        const CharCategories cat = categorize(*word_begin);
        do
        {
            ++word_end;
        } while (word_end != end and categorize(*word_end) == cat);

        col += word_end - word_begin;
        if ((word_begin != line_begin and col > max_width) or
            cat == CharCategories::EndOfLine)
        {
            lines.emplace_back(line_begin.base(), line_end.base());
            line_begin = (cat == CharCategories::EndOfLine or
                          cat == CharCategories::Blank) ? word_end : word_begin;
            col = word_end - line_begin;
        }
        if (cat == CharCategories::Word or cat == CharCategories::Punctuation)
            line_end = word_end;

        word_begin = word_end;
    }
    if (line_begin != word_begin)
        lines.emplace_back(line_begin.base(), word_begin.base());
    return lines;
}

template<typename AppendFunc>
void format_impl(StringView fmt, ArrayView<const StringView> params, AppendFunc append)
{
    int implicitIndex = 0;
    for (auto it = fmt.begin(), end = fmt.end(); it != end;)
    {
        auto opening = std::find(it, end, '{');
        if (opening == end)
        {
            append(StringView{it, opening});
            break;
        }
        else if (opening != it and *(opening-1) == '\\')
        {
            append(StringView{it, opening-1});
            append('{');
            it = opening + 1;
        }
        else
        {
            append(StringView{it, opening});
            auto closing = std::find(opening, end, '}');
            if (closing == end)
                throw runtime_error("Format string error, unclosed '{'");
            int index;
            if (closing == opening + 1)
                index = implicitIndex;
            else
                index = str_to_int({opening+1, closing});

            if (index >= params.size())
                throw runtime_error("Format string parameter index too big");

            append(params[index]);
            implicitIndex = index+1;
            it = closing+1;
        }
    }
}

StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params)
{
    char* ptr = buffer.begin();
    const char* end = buffer.end();
    format_impl(fmt, params, [&](StringView s) mutable {
        for (auto c : s)
        {
            if (ptr == end)
                throw runtime_error("buffer is too small");
            *ptr++ = c;
        }
    });
    if (ptr == end)
        throw runtime_error("buffer is too small");
    *ptr = 0;

    return { buffer.begin(), ptr };
}

String format(StringView fmt, ArrayView<const StringView> params)
{
    ByteCount size = fmt.length();
    for (auto& s : params) size += s.length();
    String res;
    res.reserve(size);

    format_impl(fmt, params, [&](StringView s) { res += s; });
    return res;
}

UnitTest test_string{[]()
{
    kak_assert(String("youpi ") + "matin" == "youpi matin");

    Vector<String> splited = split("youpi:matin::tchou\\:kanaky:hihi\\:", ':', '\\');
    kak_assert(splited[0] == "youpi");
    kak_assert(splited[1] == "matin");
    kak_assert(splited[2] == "");
    kak_assert(splited[3] == "tchou:kanaky");
    kak_assert(splited[4] == "hihi:");

    Vector<StringView> splitedview = split("youpi:matin::tchou\\:kanaky:hihi\\:", ':');
    kak_assert(splitedview[0] == "youpi");
    kak_assert(splitedview[1] == "matin");
    kak_assert(splitedview[2] == "");
    kak_assert(splitedview[3] == "tchou\\");
    kak_assert(splitedview[4] == "kanaky");
    kak_assert(splitedview[5] == "hihi\\");
    kak_assert(splitedview[6] == "");

    kak_assert(escape("youpi:matin:tchou:", ':', '\\') == "youpi\\:matin\\:tchou\\:");
    kak_assert(unescape("youpi\\:matin\\:tchou\\:", ':', '\\') == "youpi:matin:tchou:");

    kak_assert(prefix_match("tchou kanaky", "tchou"));
    kak_assert(prefix_match("tchou kanaky", "tchou kanaky"));
    kak_assert(prefix_match("tchou kanaky", "t"));
    kak_assert(not prefix_match("tchou kanaky", "c"));

    kak_assert(subsequence_match("tchou kanaky", "tknky"));
    kak_assert(subsequence_match("tchou kanaky", "knk"));
    kak_assert(subsequence_match("tchou kanaky", "tchou kanaky"));
    kak_assert(not subsequence_match("tchou kanaky", "tchou  kanaky"));

    kak_assert(format("Youhou {1} {} {0} \\{}", 10, "hehe", 5) == "Youhou hehe 5 10 {}");

    char buffer[20];
    kak_assert(format_to(buffer, "Hey {}", 15) == "Hey 15");

    kak_assert(str_to_int("5") == 5);
    kak_assert(str_to_int(to_string(INT_MAX)) == INT_MAX);
    kak_assert(str_to_int(to_string(INT_MIN)) == INT_MIN);
    kak_assert(str_to_int("00") == 0);
    kak_assert(str_to_int("-0") == 0);
}};

}
<commit_msg>Splitting an empty string now returns an empty vector<commit_after>#include "string.hh"

#include "exception.hh"
#include "containers.hh"
#include "utf8_iterator.hh"
#include "unit_tests.hh"

#include <cstdio>

namespace Kakoune
{

Vector<String> split(StringView str, char separator, char escape)
{
    Vector<String> res;
    auto it = str.begin();
    while (it != str.end())
    {
        res.emplace_back();
        String& element = res.back();
        while (it != str.end())
        {
            auto c = *it;
            if (c == escape and it + 1 != str.end() and *(it+1) == separator)
            {
                element += separator;
                it += 2;
            }
            else if (c == separator)
            {
                ++it;
                break;
            }
            else
            {
                element += c;
                ++it;
            }
        }
    }
    return res;
}

Vector<StringView> split(StringView str, char separator)
{
    Vector<StringView> res;
    if (str.empty())
        return res;

    auto beg = str.begin();
    for (auto it = beg; it != str.end(); ++it)
    {
        if (*it == separator)
        {
            res.emplace_back(beg, it);
            beg = it + 1;
        }
    }
    res.emplace_back(beg, str.end());
    return res;
}

String escape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto it = str.begin(), end = str.end(); it != end; )
    {
        auto next = std::find_if(it, end, [&characters](char c) { return contains(characters, c); });
        if (next != end)
        {
            res += StringView{it, next+1};
            res.back() = escape;
            res += *next;
            it = next+1;
        }
        else
        {
            res += StringView{it, next};
            break;
        }
    }
    return res;
}

String unescape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto it = str.begin(), end = str.end(); it != end; )
    {
        auto next = std::find(it, end, escape);
        if (next != end and next+1 != end and contains(characters, *(next+1)))
        {
            res += StringView{it, next+1};
            res.back() = *(next+1);
            it = next + 2;
        }
        else
        {
            res += StringView{it, next == end ? next : next + 1};
            it = next == end ? next : next + 1;
        }
    }
    return res;
}

String indent(StringView str, StringView indent)
{
    String res;
    res.reserve(str.length());
    bool was_eol = true;
    for (ByteCount i = 0; i < str.length(); ++i)
    {
        if (was_eol)
            res += indent;
        res += str[i];
        was_eol = is_eol(str[i]);
    }
    return res;
}

Optional<int> str_to_int_ifp(StringView str)
{
    unsigned int res = 0;
    bool negative = false;
    for (auto it = str.begin(), end = str.end(); it != end; ++it)
    {
        const char c = *it;
        if (it == str.begin() and c == '-')
            negative = true;
        else if (c >= '0' and c <= '9')
            res = res * 10 + c - '0';
        else
            return {};
    }
    return negative ? -(int)res : (int)res;
}

int str_to_int(StringView str)
{
    if (auto val = str_to_int_ifp(str))
        return *val;
    throw runtime_error{str + " is not a number"};
}

InplaceString<15> to_string(int val)
{
    InplaceString<15> res;
    res.m_length = sprintf(res.m_data, "%i", val);
    return res;
}

InplaceString<23> to_string(long int val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%li", val);
    return res;
}

InplaceString<23> to_string(size_t val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%zu", val);
    return res;
}

InplaceString<23> to_string(Hex val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%zx", val.val);
    return res;
}

InplaceString<23> to_string(float val)
{
    InplaceString<23> res;
    res.m_length = sprintf(res.m_data, "%f", val);
    return res;
}

InplaceString<7> to_string(Codepoint c)
{
    InplaceString<7> res;
    char* ptr = res.m_data;
    utf8::dump(ptr, c);
    res.m_length = (int)(ptr - res.m_data);
    return res;
}

bool subsequence_match(StringView str, StringView subseq)
{
    auto it = str.begin();
    for (auto& c : subseq)
    {
        if (it == str.end())
            return false;
        while (*it != c)
        {
            if (++it == str.end())
                return false;
        }
        ++it;
    }
    return true;
}

String expand_tabs(StringView line, CharCount tabstop, CharCount col)
{
    String res;
    res.reserve(line.length());
    for (auto it = line.begin(), end = line.end(); it != end; )
    {
        if (*it == '\t')
        {
            CharCount end_col = (col / tabstop + 1) * tabstop;
            res += String{' ', end_col - col};
            col = end_col;
            ++it;
        }
        else
        {
            auto char_end = utf8::next(it, end);
            res += {it, char_end};
            ++col;
            it = char_end;
        }
    }
    return res;
}

Vector<StringView> wrap_lines(StringView text, CharCount max_width)
{
    if (max_width <= 0)
        throw runtime_error("Invalid max width");

    using Utf8It = utf8::iterator<const char*>;
    Utf8It word_begin{text.begin(), text};
    Utf8It word_end{word_begin};
    Utf8It end{text.end(), text};
    CharCount col = 0;
    Vector<StringView> lines;
    Utf8It line_begin{text.begin(), text};
    Utf8It line_end = line_begin;
    while (word_begin != end)
    {
        const CharCategories cat = categorize(*word_begin);
        do
        {
            ++word_end;
        } while (word_end != end and categorize(*word_end) == cat);

        col += word_end - word_begin;
        if ((word_begin != line_begin and col > max_width) or
            cat == CharCategories::EndOfLine)
        {
            lines.emplace_back(line_begin.base(), line_end.base());
            line_begin = (cat == CharCategories::EndOfLine or
                          cat == CharCategories::Blank) ? word_end : word_begin;
            col = word_end - line_begin;
        }
        if (cat == CharCategories::Word or cat == CharCategories::Punctuation)
            line_end = word_end;

        word_begin = word_end;
    }
    if (line_begin != word_begin)
        lines.emplace_back(line_begin.base(), word_begin.base());
    return lines;
}

template<typename AppendFunc>
void format_impl(StringView fmt, ArrayView<const StringView> params, AppendFunc append)
{
    int implicitIndex = 0;
    for (auto it = fmt.begin(), end = fmt.end(); it != end;)
    {
        auto opening = std::find(it, end, '{');
        if (opening == end)
        {
            append(StringView{it, opening});
            break;
        }
        else if (opening != it and *(opening-1) == '\\')
        {
            append(StringView{it, opening-1});
            append('{');
            it = opening + 1;
        }
        else
        {
            append(StringView{it, opening});
            auto closing = std::find(opening, end, '}');
            if (closing == end)
                throw runtime_error("Format string error, unclosed '{'");
            int index;
            if (closing == opening + 1)
                index = implicitIndex;
            else
                index = str_to_int({opening+1, closing});

            if (index >= params.size())
                throw runtime_error("Format string parameter index too big");

            append(params[index]);
            implicitIndex = index+1;
            it = closing+1;
        }
    }
}

StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params)
{
    char* ptr = buffer.begin();
    const char* end = buffer.end();
    format_impl(fmt, params, [&](StringView s) mutable {
        for (auto c : s)
        {
            if (ptr == end)
                throw runtime_error("buffer is too small");
            *ptr++ = c;
        }
    });
    if (ptr == end)
        throw runtime_error("buffer is too small");
    *ptr = 0;

    return { buffer.begin(), ptr };
}

String format(StringView fmt, ArrayView<const StringView> params)
{
    ByteCount size = fmt.length();
    for (auto& s : params) size += s.length();
    String res;
    res.reserve(size);

    format_impl(fmt, params, [&](StringView s) { res += s; });
    return res;
}

UnitTest test_string{[]()
{
    kak_assert(String("youpi ") + "matin" == "youpi matin");

    Vector<String> splited = split("youpi:matin::tchou\\:kanaky:hihi\\:", ':', '\\');
    kak_assert(splited[0] == "youpi");
    kak_assert(splited[1] == "matin");
    kak_assert(splited[2] == "");
    kak_assert(splited[3] == "tchou:kanaky");
    kak_assert(splited[4] == "hihi:");

    Vector<StringView> splitedview = split("youpi:matin::tchou\\:kanaky:hihi\\:", ':');
    kak_assert(splitedview[0] == "youpi");
    kak_assert(splitedview[1] == "matin");
    kak_assert(splitedview[2] == "");
    kak_assert(splitedview[3] == "tchou\\");
    kak_assert(splitedview[4] == "kanaky");
    kak_assert(splitedview[5] == "hihi\\");
    kak_assert(splitedview[6] == "");

    kak_assert(escape("youpi:matin:tchou:", ':', '\\') == "youpi\\:matin\\:tchou\\:");
    kak_assert(unescape("youpi\\:matin\\:tchou\\:", ':', '\\') == "youpi:matin:tchou:");

    kak_assert(prefix_match("tchou kanaky", "tchou"));
    kak_assert(prefix_match("tchou kanaky", "tchou kanaky"));
    kak_assert(prefix_match("tchou kanaky", "t"));
    kak_assert(not prefix_match("tchou kanaky", "c"));

    kak_assert(subsequence_match("tchou kanaky", "tknky"));
    kak_assert(subsequence_match("tchou kanaky", "knk"));
    kak_assert(subsequence_match("tchou kanaky", "tchou kanaky"));
    kak_assert(not subsequence_match("tchou kanaky", "tchou  kanaky"));

    kak_assert(format("Youhou {1} {} {0} \\{}", 10, "hehe", 5) == "Youhou hehe 5 10 {}");

    char buffer[20];
    kak_assert(format_to(buffer, "Hey {}", 15) == "Hey 15");

    kak_assert(str_to_int("5") == 5);
    kak_assert(str_to_int(to_string(INT_MAX)) == INT_MAX);
    kak_assert(str_to_int(to_string(INT_MIN)) == INT_MIN);
    kak_assert(str_to_int("00") == 0);
    kak_assert(str_to_int("-0") == 0);
}};

}
<|endoftext|>


<commit_before>#ifndef string_hh_INCLUDED
#define string_hh_INCLUDED

#include "units.hh"
#include "utf8.hh"
#include "hash.hh"
#include "vector.hh"
#include "array_view.hh"

#include <string>
#include <climits>

namespace Kakoune
{

class StringView;

template<typename Type, typename CharType>
class StringOps
{
public:
    using value_type = CharType;

    friend inline size_t hash_value(const Type& str)
    {
        return hash_data(str.data(), (int)str.length());
    }

    using iterator = CharType*;
    using const_iterator = const CharType*;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    [[gnu::always_inline]]
    iterator begin() { return type().data(); }

    [[gnu::always_inline]]
    const_iterator begin() const { return type().data(); }

    [[gnu::always_inline]]
    iterator end() { return type().data() + (int)type().length(); }

    [[gnu::always_inline]]
    const_iterator end() const { return type().data() + (int)type().length(); }

    reverse_iterator rbegin() { return reverse_iterator{end()}; }
    const_reverse_iterator rbegin() const { return const_reverse_iterator{end()}; }

    reverse_iterator rend() { return reverse_iterator{begin()}; }
    const_reverse_iterator rend() const { return const_reverse_iterator{begin()}; }

    CharType& front() { return *type().data(); }
    const CharType& front() const { return *type().data(); }
    CharType& back() { return type().data()[(int)type().length() - 1]; }
    const CharType& back() const { return type().data()[(int)type().length() - 1]; }

    [[gnu::always_inline]]
    CharType& operator[](ByteCount pos) { return type().data()[(int)pos]; }

    [[gnu::always_inline]]
    const CharType& operator[](ByteCount pos) const { return type().data()[(int)pos]; }

    Codepoint operator[](CharCount pos) const
    { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); }

    CharCount char_length() const { return utf8::distance(begin(), end()); }

    [[gnu::always_inline]]
    bool empty() const { return type().length() == 0_byte; }

    ByteCount byte_count_to(CharCount count) const
    { return utf8::advance(begin(), end(), (int)count) - begin(); }

    CharCount char_count_to(ByteCount count) const
    { return utf8::distance(begin(), begin() + (int)count); }

    StringView substr(ByteCount from, ByteCount length = INT_MAX) const;
    StringView substr(CharCount from, CharCount length = INT_MAX) const;

private:
    [[gnu::always_inline]]
    Type& type() { return *static_cast<Type*>(this); }
    [[gnu::always_inline]]
    const Type& type() const { return *static_cast<const Type*>(this); }
};

class String : public StringOps<String, char>
{
public:
    using Content = std::basic_string<char, std::char_traits<char>,
                                      Allocator<char, MemoryDomain::String>>;

    String() {}
    String(const char* content) : m_data(content) {}
    String(const char* content, ByteCount len) : m_data(content, (size_t)(int)len) {}
    explicit String(char content, CharCount count = 1) : m_data((size_t)(int)count, content) {}
    explicit String(Codepoint cp, CharCount count = 1)
    {
        while (count-- > 0)
            utf8::dump(std::back_inserter(*this), cp);
    }
    template<typename Iterator>
    String(Iterator begin, Iterator end) : m_data(begin, end) {}

    [[gnu::always_inline]]
    char* data() { return &m_data[0]; }

    [[gnu::always_inline]]
    const char* data() const { return m_data.data(); }

    [[gnu::always_inline]]
    ByteCount length() const { return (int)m_data.length(); }

    [[gnu::always_inline]]
    const char* c_str() const { return m_data.c_str(); }

    [[gnu::always_inline]]
    void append(const char* data, ByteCount count) { m_data.append(data, (size_t)(int)count); }

    void push_back(char c) { m_data.push_back(c); }
    void resize(ByteCount size) { m_data.resize((size_t)(int)size); }
    void reserve(ByteCount size) { m_data.reserve((size_t)(int)size); }

private:
    Content m_data;
};

class StringView : public StringOps<StringView, const char>
{
public:
    constexpr StringView() = default;
    constexpr StringView(const char* data, ByteCount length)
        : m_data{data}, m_length{length} {}
    constexpr StringView(const char* data) : m_data{data}, m_length{strlen(data)} {}
    constexpr StringView(const char* begin, const char* end) : m_data{begin}, m_length{(int)(end - begin)} {}
    StringView(const String& str) : m_data{str.data()}, m_length{(int)str.length()} {}
    StringView(const char& c) : m_data(&c), m_length(1) {}
    StringView(int c) = delete;

    [[gnu::always_inline]]
    constexpr const char* data() const { return m_data; }

    [[gnu::always_inline]]
    constexpr ByteCount length() const { return m_length; }

    String str() const { return {begin(), end()}; }

    struct ZeroTerminatedString
    {
        ZeroTerminatedString(const char* begin, const char* end)
        {
            if (*end == '\0')
                unowned = begin;
            else
                owned = String::Content(begin, end);
        }
        operator const char*() const { return unowned ? unowned : owned.c_str(); }

    private:
        String::Content owned;
        const char* unowned = nullptr;

    };
    ZeroTerminatedString zstr() const { return {begin(), end()}; }

private:
    static constexpr ByteCount strlen(const char* s)
    {
        return *s == 0 ? 0 : strlen(s+1) + 1;
    }

    const char* m_data = nullptr;
    ByteCount m_length = 0;
};

template<typename Type, typename CharType>
inline StringView StringOps<Type, CharType>::substr(ByteCount from, ByteCount length) const
{
    if (length < 0)
        length = INT_MAX;
    return StringView{ type().data() + (int)from, std::min(type().length() - from, length) };
}

template<typename Type, typename CharType>
inline StringView StringOps<Type, CharType>::substr(CharCount from, CharCount length) const
{
    if (length < 0)
        length = INT_MAX;
    auto beg = utf8::advance(begin(), end(), (int)from);
    return StringView{ beg, utf8::advance(beg, end(), length) };
}

inline String& operator+=(String& lhs, StringView rhs)
{
    lhs.append(rhs.data(), rhs.length());
    return lhs;
}

inline String operator+(StringView lhs, StringView rhs)
{
    String res;
    res.reserve((int)(lhs.length() + rhs.length()));
    res.append(lhs.data(), lhs.length());
    res.append(rhs.data(), rhs.length());
    return res;
}

[[gnu::always_inline]]
inline bool operator==(const StringView& lhs, const StringView& rhs)
{
    return lhs.length() == rhs.length() and
       std::equal(lhs.begin(), lhs.end(), rhs.begin());
}

[[gnu::always_inline]]
inline bool operator!=(const StringView& lhs, const StringView& rhs)
{ return not (lhs == rhs); }

inline bool operator<(const StringView& lhs, const StringView& rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(),
                                        rhs.begin(), rhs.end());
}

Vector<String> split(StringView str, char separator, char escape);
Vector<StringView> split(StringView str, char separator);

String escape(StringView str, StringView characters, char escape);
String unescape(StringView str, StringView characters, char escape);

String indent(StringView str, StringView indent = "    ");

template<typename Container>
String join(const Container& container, char joiner, bool esc_joiner = true)
{
    String res;
    for (const auto& str : container)
    {
        if (not res.empty())
            res += joiner;
        res += esc_joiner ? escape(str, joiner, '\\') : str;
    }
    return res;
}

inline String operator"" _str(const char* str, size_t)
{
    return String(str);
}

inline String codepoint_to_str(Codepoint cp)
{
    String str;
    utf8::dump(std::back_inserter(str), cp);
    return str;
}

int str_to_int(StringView str);

template<size_t N>
struct InplaceString
{
    constexpr operator StringView() const { return {m_data, m_length}; }
    operator String() const { return {m_data, m_length}; }

    ByteCount m_length;
    char m_data[N];
};

InplaceString<16> to_string(int val);
InplaceString<24> to_string(size_t val);
InplaceString<24> to_string(float val);

template<typename RealType, typename ValueType>
decltype(to_string(std::declval<ValueType>()))
to_string(const StronglyTypedNumber<RealType, ValueType>& val)
{
    return to_string((ValueType)val);
}

inline bool prefix_match(StringView str, StringView prefix)
{
    return str.substr(0_byte, prefix.length()) == prefix;
}

bool subsequence_match(StringView str, StringView subseq);

String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0);

Vector<StringView> wrap_lines(StringView text, CharCount max_width);

namespace detail
{

template<typename T> using IsString = std::is_convertible<T, StringView>;

template<typename T, class = typename std::enable_if<!IsString<T>::value>::type>
auto format_param(const T& val) -> decltype(to_string(val)) { return to_string(val); }

template<typename T, class = typename std::enable_if<IsString<T>::value>::type>
StringView format_param(const T& val) { return val; }

}

String format(StringView fmt, ArrayView<const StringView> params);

template<typename... Types>
String format(StringView fmt, Types... params)
{
    return format(fmt, ArrayView<const StringView>{detail::format_param(params)...});
}

}

#endif // string_hh_INCLUDED
<commit_msg>Always optimize StringView::strlen (recursive due to constexpr)<commit_after>#ifndef string_hh_INCLUDED
#define string_hh_INCLUDED

#include "units.hh"
#include "utf8.hh"
#include "hash.hh"
#include "vector.hh"
#include "array_view.hh"

#include <string>
#include <climits>

namespace Kakoune
{

class StringView;

template<typename Type, typename CharType>
class StringOps
{
public:
    using value_type = CharType;

    friend inline size_t hash_value(const Type& str)
    {
        return hash_data(str.data(), (int)str.length());
    }

    using iterator = CharType*;
    using const_iterator = const CharType*;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    [[gnu::always_inline]]
    iterator begin() { return type().data(); }

    [[gnu::always_inline]]
    const_iterator begin() const { return type().data(); }

    [[gnu::always_inline]]
    iterator end() { return type().data() + (int)type().length(); }

    [[gnu::always_inline]]
    const_iterator end() const { return type().data() + (int)type().length(); }

    reverse_iterator rbegin() { return reverse_iterator{end()}; }
    const_reverse_iterator rbegin() const { return const_reverse_iterator{end()}; }

    reverse_iterator rend() { return reverse_iterator{begin()}; }
    const_reverse_iterator rend() const { return const_reverse_iterator{begin()}; }

    CharType& front() { return *type().data(); }
    const CharType& front() const { return *type().data(); }
    CharType& back() { return type().data()[(int)type().length() - 1]; }
    const CharType& back() const { return type().data()[(int)type().length() - 1]; }

    [[gnu::always_inline]]
    CharType& operator[](ByteCount pos) { return type().data()[(int)pos]; }

    [[gnu::always_inline]]
    const CharType& operator[](ByteCount pos) const { return type().data()[(int)pos]; }

    Codepoint operator[](CharCount pos) const
    { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); }

    CharCount char_length() const { return utf8::distance(begin(), end()); }

    [[gnu::always_inline]]
    bool empty() const { return type().length() == 0_byte; }

    ByteCount byte_count_to(CharCount count) const
    { return utf8::advance(begin(), end(), (int)count) - begin(); }

    CharCount char_count_to(ByteCount count) const
    { return utf8::distance(begin(), begin() + (int)count); }

    StringView substr(ByteCount from, ByteCount length = INT_MAX) const;
    StringView substr(CharCount from, CharCount length = INT_MAX) const;

private:
    [[gnu::always_inline]]
    Type& type() { return *static_cast<Type*>(this); }
    [[gnu::always_inline]]
    const Type& type() const { return *static_cast<const Type*>(this); }
};

class String : public StringOps<String, char>
{
public:
    using Content = std::basic_string<char, std::char_traits<char>,
                                      Allocator<char, MemoryDomain::String>>;

    String() {}
    String(const char* content) : m_data(content) {}
    String(const char* content, ByteCount len) : m_data(content, (size_t)(int)len) {}
    explicit String(char content, CharCount count = 1) : m_data((size_t)(int)count, content) {}
    explicit String(Codepoint cp, CharCount count = 1)
    {
        while (count-- > 0)
            utf8::dump(std::back_inserter(*this), cp);
    }
    template<typename Iterator>
    String(Iterator begin, Iterator end) : m_data(begin, end) {}

    [[gnu::always_inline]]
    char* data() { return &m_data[0]; }

    [[gnu::always_inline]]
    const char* data() const { return m_data.data(); }

    [[gnu::always_inline]]
    ByteCount length() const { return (int)m_data.length(); }

    [[gnu::always_inline]]
    const char* c_str() const { return m_data.c_str(); }

    [[gnu::always_inline]]
    void append(const char* data, ByteCount count) { m_data.append(data, (size_t)(int)count); }

    void push_back(char c) { m_data.push_back(c); }
    void resize(ByteCount size) { m_data.resize((size_t)(int)size); }
    void reserve(ByteCount size) { m_data.reserve((size_t)(int)size); }

private:
    Content m_data;
};

class StringView : public StringOps<StringView, const char>
{
public:
    constexpr StringView() = default;
    constexpr StringView(const char* data, ByteCount length)
        : m_data{data}, m_length{length} {}
    constexpr StringView(const char* data) : m_data{data}, m_length{strlen(data)} {}
    constexpr StringView(const char* begin, const char* end) : m_data{begin}, m_length{(int)(end - begin)} {}
    StringView(const String& str) : m_data{str.data()}, m_length{(int)str.length()} {}
    StringView(const char& c) : m_data(&c), m_length(1) {}
    StringView(int c) = delete;

    [[gnu::always_inline]]
    constexpr const char* data() const { return m_data; }

    [[gnu::always_inline]]
    constexpr ByteCount length() const { return m_length; }

    String str() const { return {begin(), end()}; }

    struct ZeroTerminatedString
    {
        ZeroTerminatedString(const char* begin, const char* end)
        {
            if (*end == '\0')
                unowned = begin;
            else
                owned = String::Content(begin, end);
        }
        operator const char*() const { return unowned ? unowned : owned.c_str(); }

    private:
        String::Content owned;
        const char* unowned = nullptr;

    };
    ZeroTerminatedString zstr() const { return {begin(), end()}; }

private:
    [[gnu::optimize(3)]] // this is recursive for constexpr reason
    static constexpr ByteCount strlen(const char* s)
    {
        return *s == 0 ? 0 : strlen(s+1) + 1;
    }

    const char* m_data = nullptr;
    ByteCount m_length = 0;
};

template<typename Type, typename CharType>
inline StringView StringOps<Type, CharType>::substr(ByteCount from, ByteCount length) const
{
    if (length < 0)
        length = INT_MAX;
    return StringView{ type().data() + (int)from, std::min(type().length() - from, length) };
}

template<typename Type, typename CharType>
inline StringView StringOps<Type, CharType>::substr(CharCount from, CharCount length) const
{
    if (length < 0)
        length = INT_MAX;
    auto beg = utf8::advance(begin(), end(), (int)from);
    return StringView{ beg, utf8::advance(beg, end(), length) };
}

inline String& operator+=(String& lhs, StringView rhs)
{
    lhs.append(rhs.data(), rhs.length());
    return lhs;
}

inline String operator+(StringView lhs, StringView rhs)
{
    String res;
    res.reserve((int)(lhs.length() + rhs.length()));
    res.append(lhs.data(), lhs.length());
    res.append(rhs.data(), rhs.length());
    return res;
}

[[gnu::always_inline]]
inline bool operator==(const StringView& lhs, const StringView& rhs)
{
    return lhs.length() == rhs.length() and
       std::equal(lhs.begin(), lhs.end(), rhs.begin());
}

[[gnu::always_inline]]
inline bool operator!=(const StringView& lhs, const StringView& rhs)
{ return not (lhs == rhs); }

inline bool operator<(const StringView& lhs, const StringView& rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(),
                                        rhs.begin(), rhs.end());
}

Vector<String> split(StringView str, char separator, char escape);
Vector<StringView> split(StringView str, char separator);

String escape(StringView str, StringView characters, char escape);
String unescape(StringView str, StringView characters, char escape);

String indent(StringView str, StringView indent = "    ");

template<typename Container>
String join(const Container& container, char joiner, bool esc_joiner = true)
{
    String res;
    for (const auto& str : container)
    {
        if (not res.empty())
            res += joiner;
        res += esc_joiner ? escape(str, joiner, '\\') : str;
    }
    return res;
}

inline String operator"" _str(const char* str, size_t)
{
    return String(str);
}

inline String codepoint_to_str(Codepoint cp)
{
    String str;
    utf8::dump(std::back_inserter(str), cp);
    return str;
}

int str_to_int(StringView str);

template<size_t N>
struct InplaceString
{
    constexpr operator StringView() const { return {m_data, m_length}; }
    operator String() const { return {m_data, m_length}; }

    ByteCount m_length;
    char m_data[N];
};

InplaceString<16> to_string(int val);
InplaceString<24> to_string(size_t val);
InplaceString<24> to_string(float val);

template<typename RealType, typename ValueType>
decltype(to_string(std::declval<ValueType>()))
to_string(const StronglyTypedNumber<RealType, ValueType>& val)
{
    return to_string((ValueType)val);
}

inline bool prefix_match(StringView str, StringView prefix)
{
    return str.substr(0_byte, prefix.length()) == prefix;
}

bool subsequence_match(StringView str, StringView subseq);

String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0);

Vector<StringView> wrap_lines(StringView text, CharCount max_width);

namespace detail
{

template<typename T> using IsString = std::is_convertible<T, StringView>;

template<typename T, class = typename std::enable_if<!IsString<T>::value>::type>
auto format_param(const T& val) -> decltype(to_string(val)) { return to_string(val); }

template<typename T, class = typename std::enable_if<IsString<T>::value>::type>
StringView format_param(const T& val) { return val; }

}

String format(StringView fmt, ArrayView<const StringView> params);

template<typename... Types>
String format(StringView fmt, Types... params)
{
    return format(fmt, ArrayView<const StringView>{detail::format_param(params)...});
}

}

#endif // string_hh_INCLUDED
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "ActionWarehouse.h"
#include "ActionFactory.h"
#include "Parser.h"
#include "MooseObjectAction.h"
#include "InputFileFormatter.h"
#include "InputParameters.h"
#include "MooseMesh.h"

ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory & factory) :
    _app(app),
    _syntax(syntax),
    _action_factory(factory),
    _generator_valid(false),
    _show_actions(false),
    _mesh(NULL),
    _displaced_mesh(NULL),
    _problem(NULL),
    _executioner(NULL)
{
}

ActionWarehouse::~ActionWarehouse()
{
}

void
ActionWarehouse::build()
{
  _ordered_names = _syntax.getSortedActionName();
  for (std::vector<std::string>::iterator it = _ordered_names.begin(); it != _ordered_names.end(); ++it)
    buildBuildableActions(*it);
}

void
ActionWarehouse::clear()
{
  for (std::map<std::string, std::vector<Action *> >::iterator it = _action_blocks.begin(); it != _action_blocks.end(); ++it)
  {
    for (std::vector<Action *>::iterator jt = (*it).second.begin(); jt != (*it).second.end(); ++jt)
      delete *jt;
  }
  _action_blocks.clear();
  _generator_valid = false;
}

void
ActionWarehouse::addActionBlock(Action * blk)
{
  std::string action_name = blk->getAction();

  // Some error checking
  if (!_syntax.hasActionName(action_name))
    mooseError("A(n) " << action_name << " is not a registered action name");

  // Make sure that the ObjectAction action_name and Action action_name are consistent
  // otherwise that means that is action was built by the wrong type
  MooseObjectAction * moa = dynamic_cast<MooseObjectAction *>(blk);
  if (moa)
  {
    InputParameters mparams = moa->getObjectParams();
    if (mparams.have_parameter<std::string>("built_by_action"))
    {
      std::string moose_action_name = moa->getObjectParams().get<std::string>("built_by_action");
      if ((moose_action_name != action_name) &&  // if there is a mismatch, that means there is an object in the wrong section, unless...
          ! // NOT in the exception list...
          ((action_name == "add_aux_bc" && moose_action_name == "add_aux_kernel") ||
           (action_name == "add_postprocessor" && moose_action_name == "add_user_object") ||
           (action_name == "add_user_object" && moose_action_name == "add_postprocessor")))
        mooseError("Inconsistent Action Name detected (" + blk->name() + ")! Action that satisfies " + action_name + " is building a MOOSE Object that normally satisfies " + moose_action_name);
    }
  }

  _action_blocks[action_name].push_back(blk);
}

ActionIterator
ActionWarehouse::actionBlocksWithActionBegin(const std::string & action_name)
{
  return _action_blocks[action_name].begin();
}

ActionIterator
ActionWarehouse::actionBlocksWithActionEnd(const std::string & action_name)
{
  return _action_blocks[action_name].end();
}

const std::vector<Action *> &
ActionWarehouse::getActionsByName(const std::string & action_name) const
{
  return _action_blocks.at(action_name);
}

void
ActionWarehouse::buildBuildableActions(const std::string &action_name)
{
  if (_syntax.isActionRequired(action_name) && _action_blocks[action_name].empty())
  {
    bool ret_value = false;
    std::pair<std::multimap<std::string, std::string>::iterator,
              std::multimap<std::string, std::string>::iterator> range = _action_factory.getA(action_name);
    for (std::multimap<std::string, std::string>::iterator it = range.first; it != range.second; ++it)
    {
      InputParameters params = _action_factory.getValidParams(it->second);
      params.set<ActionWarehouse *>("awh") = this;

      if (params.areAllRequiredParamsValid())
      {
        addActionBlock(_action_factory.create(it->second, "", params));
        ret_value = true;
      }
    }

    if (!ret_value)
      _unsatisfied_dependencies.insert(action_name);
  }
}

void
ActionWarehouse::checkUnsatisfiedActions() const
{
  std::stringstream oss;
  bool empty = true;

  for (std::set<std::string>::const_iterator i = _unsatisfied_dependencies.begin(); i != _unsatisfied_dependencies.end(); ++i)
  {
    if (_action_blocks.find(*i) == _action_blocks.end())
    {
      if (empty)
        empty = false;
      else
        oss << " ";
      oss << *i;
    }
  }

  if (!empty)
    mooseError(std::string("The following unsatisfied actions where found while setting up the MOOSE problem:\n")
               + oss.str() + "\n");
}

void
ActionWarehouse::printActionDependencySets()
{
  std::cerr << "[DBG][ACT] Ordered Actions:\n";

  const std::vector<std::set<std::string> > & ordered_names = _syntax.getSortedActionNameSet();
  for (std::vector<std::set<std::string> >::const_iterator i = ordered_names.begin(); i != ordered_names.end(); ++i)
  {
    std::cerr << "[DBG][ACT] (";
    unsigned int jj = 0;
    for (std::set<std::string>::const_iterator j = i->begin(); j != i->end(); ++j)
    {
      if (jj++) std::cerr << ", ";
      std::cout << *j;
    }
    std::cout << ")\n";

    for (std::set<std::string>::const_iterator j = i->begin(); j != i->end(); ++j)
    {
      for (std::vector<Action *>::const_iterator k = _action_blocks[*j].begin(); k != _action_blocks[*j].end(); ++k)
        std::cerr << "[DBG][ACT]" << "\t" << (*k)->getAction() << "\n";
    }
  }
}

void
ActionWarehouse::executeAllActions()
{
  if (_show_actions)
  {
    std::cerr << "[DBG][ACT] Action Dependency Sets:\n";
    printActionDependencySets();
    std::cerr << "[DBG][ACT] Executing actions:" << std::endl;
  }

  for (std::vector<std::string>::iterator it = _ordered_names.begin(); it != _ordered_names.end(); ++it)
  {
    std::string action_name = *it;
    executeActionsWithAction(action_name);
  }
}

void
ActionWarehouse::executeActionsWithAction(const std::string & name)
{
  for (ActionIterator act_iter = actionBlocksWithActionBegin(name);
       act_iter != actionBlocksWithActionEnd(name);
       ++act_iter)
  {
    if (_show_actions)
      std::cerr << "[DBG][ACT] - " << (*act_iter)->name() << std::endl;
    (*act_iter)->act();
  }
}

void
ActionWarehouse::printInputFile(std::ostream & out)
{
  InputFileFormatter tree(false);

  std::map<std::string, std::vector<Action *> >::iterator iter;

  std::vector<Action *> ordered_actions;
  ordered_actions.clear();
  for (iter = _action_blocks.begin(); iter != _action_blocks.end(); ++iter)
    for (std::vector<Action *>::iterator j = iter->second.begin(); j != iter->second.end(); ++j)
      ordered_actions.push_back(*j);

  for (std::vector<Action* >::iterator i = ordered_actions.begin();
       i != ordered_actions.end();
       ++i)
   {
    std::string name ((*i)->name());
    std::string action ((*i)->getAction());

    bool is_parent;
    if (_syntax.isAssociated(name, &is_parent) != "")
     {
      InputParameters params = (*i)->getParams();
      tree.insertNode(name, action, true, &params);

      MooseObjectAction *moose_object_action = dynamic_cast<MooseObjectAction *>(*i);
      if (moose_object_action)
       {
        InputParameters obj_params = moose_object_action->getObjectParams();
        tree.insertNode(name, action, false, &obj_params);
       }
     }
  }

  out << tree.print("");
}

<commit_msg>Print out more detailed info when show_actions is on (closes #963)<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "ActionWarehouse.h"
#include "ActionFactory.h"
#include "Parser.h"
#include "MooseObjectAction.h"
#include "InputFileFormatter.h"
#include "InputParameters.h"
#include "MooseMesh.h"
#include "AddVariableAction.h"
#include "AddAuxVariableAction.h"

ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory & factory) :
    _app(app),
    _syntax(syntax),
    _action_factory(factory),
    _generator_valid(false),
    _show_actions(false),
    _mesh(NULL),
    _displaced_mesh(NULL),
    _problem(NULL),
    _executioner(NULL)
{
}

ActionWarehouse::~ActionWarehouse()
{
}

void
ActionWarehouse::build()
{
  _ordered_names = _syntax.getSortedActionName();
  for (std::vector<std::string>::iterator it = _ordered_names.begin(); it != _ordered_names.end(); ++it)
    buildBuildableActions(*it);
}

void
ActionWarehouse::clear()
{
  for (std::map<std::string, std::vector<Action *> >::iterator it = _action_blocks.begin(); it != _action_blocks.end(); ++it)
  {
    for (std::vector<Action *>::iterator jt = (*it).second.begin(); jt != (*it).second.end(); ++jt)
      delete *jt;
  }
  _action_blocks.clear();
  _generator_valid = false;
}

void
ActionWarehouse::addActionBlock(Action * blk)
{
  std::string action_name = blk->getAction();

  // Some error checking
  if (!_syntax.hasActionName(action_name))
    mooseError("A(n) " << action_name << " is not a registered action name");

  // Make sure that the ObjectAction action_name and Action action_name are consistent
  // otherwise that means that is action was built by the wrong type
  MooseObjectAction * moa = dynamic_cast<MooseObjectAction *>(blk);
  if (moa)
  {
    InputParameters mparams = moa->getObjectParams();
    if (mparams.have_parameter<std::string>("built_by_action"))
    {
      std::string moose_action_name = moa->getObjectParams().get<std::string>("built_by_action");
      if ((moose_action_name != action_name) &&  // if there is a mismatch, that means there is an object in the wrong section, unless...
          ! // NOT in the exception list...
          ((action_name == "add_aux_bc" && moose_action_name == "add_aux_kernel") ||
           (action_name == "add_postprocessor" && moose_action_name == "add_user_object") ||
           (action_name == "add_user_object" && moose_action_name == "add_postprocessor")))
        mooseError("Inconsistent Action Name detected (" + blk->name() + ")! Action that satisfies " + action_name + " is building a MOOSE Object that normally satisfies " + moose_action_name);
    }
  }

  _action_blocks[action_name].push_back(blk);
}

ActionIterator
ActionWarehouse::actionBlocksWithActionBegin(const std::string & action_name)
{
  return _action_blocks[action_name].begin();
}

ActionIterator
ActionWarehouse::actionBlocksWithActionEnd(const std::string & action_name)
{
  return _action_blocks[action_name].end();
}

const std::vector<Action *> &
ActionWarehouse::getActionsByName(const std::string & action_name) const
{
  return _action_blocks.at(action_name);
}

void
ActionWarehouse::buildBuildableActions(const std::string &action_name)
{
  if (_syntax.isActionRequired(action_name) && _action_blocks[action_name].empty())
  {
    bool ret_value = false;
    std::pair<std::multimap<std::string, std::string>::iterator,
              std::multimap<std::string, std::string>::iterator> range = _action_factory.getA(action_name);
    for (std::multimap<std::string, std::string>::iterator it = range.first; it != range.second; ++it)
    {
      InputParameters params = _action_factory.getValidParams(it->second);
      params.set<ActionWarehouse *>("awh") = this;

      if (params.areAllRequiredParamsValid())
      {
        addActionBlock(_action_factory.create(it->second, "", params));
        ret_value = true;
      }
    }

    if (!ret_value)
      _unsatisfied_dependencies.insert(action_name);
  }
}

void
ActionWarehouse::checkUnsatisfiedActions() const
{
  std::stringstream oss;
  bool empty = true;

  for (std::set<std::string>::const_iterator i = _unsatisfied_dependencies.begin(); i != _unsatisfied_dependencies.end(); ++i)
  {
    if (_action_blocks.find(*i) == _action_blocks.end())
    {
      if (empty)
        empty = false;
      else
        oss << " ";
      oss << *i;
    }
  }

  if (!empty)
    mooseError(std::string("The following unsatisfied actions where found while setting up the MOOSE problem:\n")
               + oss.str() + "\n");
}

void
ActionWarehouse::printActionDependencySets()
{
  std::cerr << "[DBG][ACT] Ordered Actions:\n";

  const std::vector<std::set<std::string> > & ordered_names = _syntax.getSortedActionNameSet();
  for (std::vector<std::set<std::string> >::const_iterator i = ordered_names.begin(); i != ordered_names.end(); ++i)
  {
    std::cerr << "[DBG][ACT] (";
    unsigned int jj = 0;
    for (std::set<std::string>::const_iterator j = i->begin(); j != i->end(); ++j)
    {
      if (jj++) std::cerr << ", ";
      std::cout << *j;
    }
    std::cout << ")\n";

    for (std::set<std::string>::const_iterator j = i->begin(); j != i->end(); ++j)
    {
      for (std::vector<Action *>::const_iterator k = _action_blocks[*j].begin(); k != _action_blocks[*j].end(); ++k)
      {
        Action * act = *k;
        std::cerr << "[DBG][ACT]" << "\t" << act->getAction();
        if (dynamic_cast<MooseObjectAction *>(act) != NULL ||
            dynamic_cast<AddVariableAction *>(act) != NULL ||
            dynamic_cast<AddAuxVariableAction *>(act) != NULL)
        {
          // print out short name only for MooseObjectActions
          std::stringstream ss;
          ss << ": " << (*k)->getShortName();
          if (ss.str().size() > 2)
            std::cerr << ss.str();
        }
        std::cerr << "\n";
      }
    }
  }
}

void
ActionWarehouse::executeAllActions()
{
  if (_show_actions)
  {
    std::cerr << "[DBG][ACT] Action Dependency Sets:\n";
    printActionDependencySets();
    std::cerr << "[DBG][ACT] Executing actions:" << std::endl;
  }

  for (std::vector<std::string>::iterator it = _ordered_names.begin(); it != _ordered_names.end(); ++it)
  {
    std::string action_name = *it;
    executeActionsWithAction(action_name);
  }
}

void
ActionWarehouse::executeActionsWithAction(const std::string & name)
{
  for (ActionIterator act_iter = actionBlocksWithActionBegin(name);
       act_iter != actionBlocksWithActionEnd(name);
       ++act_iter)
  {
    if (_show_actions)
      std::cerr << "[DBG][ACT] - " << (*act_iter)->name() << std::endl;
    (*act_iter)->act();
  }
}

void
ActionWarehouse::printInputFile(std::ostream & out)
{
  InputFileFormatter tree(false);

  std::map<std::string, std::vector<Action *> >::iterator iter;

  std::vector<Action *> ordered_actions;
  ordered_actions.clear();
  for (iter = _action_blocks.begin(); iter != _action_blocks.end(); ++iter)
    for (std::vector<Action *>::iterator j = iter->second.begin(); j != iter->second.end(); ++j)
      ordered_actions.push_back(*j);

  for (std::vector<Action* >::iterator i = ordered_actions.begin();
       i != ordered_actions.end();
       ++i)
   {
    std::string name ((*i)->name());
    std::string action ((*i)->getAction());

    bool is_parent;
    if (_syntax.isAssociated(name, &is_parent) != "")
     {
      InputParameters params = (*i)->getParams();
      tree.insertNode(name, action, true, &params);

      MooseObjectAction *moose_object_action = dynamic_cast<MooseObjectAction *>(*i);
      if (moose_object_action)
       {
        InputParameters obj_params = moose_object_action->getObjectParams();
        tree.insertNode(name, action, false, &obj_params);
       }
     }
  }

  out << tree.print("");
}

<|endoftext|>


<commit_before>/**
 * @file armadillo_usage.cpp
 * @brief Usage test for Armadillolibrary
 * @author Paolo D'Apice
 */

#define BOOST_TEST_MODULE armadillo
#include <boost/test/unit_test.hpp>

#include "utils/matrix.hpp"

#include <armadillo>

using namespace arma;

BOOST_AUTO_TEST_CASE(arma_mat) {
    mat a = randu<mat>(4,4);
    a.print("randu");

    mat b = a.cols(1,3);
    b.print("cols");

    uvec i{1,3};
    mat c = a.cols(i);
    c.print("cols");
}

BOOST_AUTO_TEST_CASE(arma_vec) {
    vec c{1,2,3};
    rowvec r{1,2,3};

    c.print("colvec");
    r.print("rowvec");
}

BOOST_AUTO_TEST_CASE(arma_cube) {
    int data[] = {1,2,3,4,5,6,7,8,9,10,11,12};
    icube c(data, 3, 2, 2);
    c.print("cube:");

    c.reshape(1, 3*2*2, 1);
    c.print("reshaped:");

    irowvec v = c;
    v.print("vector:");

    imat m = v;
    m.print("matrix:");

    join_cols(m,v).print("join cols");
    join_rows(m,v).print("join rows");
}

BOOST_AUTO_TEST_CASE(arma_reshape) {
    mat a = { 1,2,3,4,5,6 };
    a.reshape(2,3);
    a.print("2x3:");

    a.reshape(3,2);
    a.print("3x2:");

    cube b(a.memptr(), 1, 2, 3);
    b.print("1x2x3:");

    b.reshape(3,2,1);
    b.print("3,2,1:");

    mat c = b;
    c.print("cube to mat:");
}

BOOST_AUTO_TEST_CASE(arma_hist) {
    ivec a = conv_to<ivec>::from(randu<vec>(1000) * 100.);

    ivec b = linspace<ivec>(1,10,10);
    b.print("bins");

    uvec h = hist(a, b);
    h.print("hist");
}

<commit_msg>Fix compilation error in armadillo_usage test<commit_after>/**
 * @file armadillo_usage.cpp
 * @brief Usage test for Armadillolibrary
 * @author Paolo D'Apice
 */

#define BOOST_TEST_MODULE armadillo
#include <boost/test/unit_test.hpp>

#include "utils/matrix.hpp"

#include <armadillo>

using namespace arma;

BOOST_AUTO_TEST_CASE(arma_mat) {
    mat a = randu<mat>(4,4);
    a.print("randu");

    mat b = a.cols(1,3);
    b.print("cols");

    uvec i{1,3};
    mat c = a.cols(i);
    c.print("cols");
}

BOOST_AUTO_TEST_CASE(arma_vec) {
    vec c{1,2,3};
    rowvec r{1,2,3};

    c.print("colvec");
    r.print("rowvec");
}

BOOST_AUTO_TEST_CASE(arma_cube) {
    sword data[] = {1,2,3,4,5,6,7,8,9,10,11,12};
    icube c(data, 3, 2, 2);
    c.print("cube:");

    c.reshape(1, 3*2*2, 1);
    c.print("reshaped:");

    irowvec v = c;
    v.print("vector:");

    imat m = v;
    m.print("matrix:");

    join_cols(m,v).print("join cols");
    join_rows(m,v).print("join rows");
}

BOOST_AUTO_TEST_CASE(arma_reshape) {
    mat a = { 1,2,3,4,5,6 };
    a.reshape(2,3);
    a.print("2x3:");

    a.reshape(3,2);
    a.print("3x2:");

    cube b(a.memptr(), 1, 2, 3);
    b.print("1x2x3:");

    b.reshape(3,2,1);
    b.print("3,2,1:");

    mat c = b;
    c.print("cube to mat:");
}

BOOST_AUTO_TEST_CASE(arma_hist) {
    ivec a = conv_to<ivec>::from(randu<vec>(1000) * 100.);

    ivec b = linspace<ivec>(1,10,10);
    b.print("bins");

    uvec h = hist(a, b);
    h.print("hist");
}

<|endoftext|>


<commit_before>#include "pacman.hh"

#include <fnmatch.h>
#include <glob.h>

#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

namespace {

struct GlobbufFree {
  void operator()(glob_t* globbuf) { globfree(globbuf); }
};

std::string& ltrim(std::string& s) {
  s.erase(s.begin(),
          std::find_if(s.begin(), s.end(),
                       std::not1(std::ptr_fun<int, int>(std::isspace))));
  return s;
}

std::string& rtrim(std::string& s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
                       std::not1(std::ptr_fun<int, int>(std::isspace)))
              .base(),
          s.end());
  return s;
}

std::string& trim(std::string& s) { return ltrim(rtrim(s)); }

}  // namespace

namespace dlr {

Pacman::Pacman(alpm_handle_t* alpm, std::vector<std::string> ignored_packages)
    : alpm_(alpm),
      local_db_(alpm_get_localdb(alpm_)),
      ignored_packages_(std::move(ignored_packages)) {}

Pacman::~Pacman() { alpm_release(alpm_); }

struct ParseState {
  alpm_handle_t* alpm;

  std::string section;
  std::vector<std::string> ignorepkgs;
};

bool IsSection(const std::string& s) {
  return s.size() > 2 && s[0] == '[' && s[s.size() - 1] == ']';
}

bool ParseOneFile(const std::string& path, ParseState* state) {
  std::ifstream file(path);

  std::string line;
  while (std::getline(file, line)) {
    line = trim(line);

    if (line.size() == 0 || line[0] == '#') {
      continue;
    }

    if (IsSection(line)) {
      state->section = line.substr(1, line.size() - 2);
      continue;
    }

    auto equals = line.find_first_of('=');
    if (equals == std::string::npos) {
      // There aren't any directives we care about which are valueless.
      continue;
    }

    auto key = line.substr(0, equals);
    key = trim(key);

    auto value = line.substr(equals + 1);

    if (state->section == "options") {
      if (key == "IgnorePkg") {
        std::istringstream iss(value);
        std::copy(std::istream_iterator<std::string>(iss),
                  std::istream_iterator<std::string>(),
                  std::back_inserter(state->ignorepkgs));
      }
    } else {
      alpm_register_syncdb(state->alpm, state->section.c_str(), 0);
    }

    if (key == "Include") {
      std::unique_ptr<glob_t, GlobbufFree> globbuf(new glob_t);

      if (glob(value.c_str(), GLOB_NOCHECK, nullptr, globbuf.get()) != 0) {
        return false;
      }

      for (size_t i = 0; i < globbuf->gl_pathc; ++i) {
        if (ParseOneFile(globbuf->gl_pathv[i], state) == false) {
          return false;
        }
      }
    }
  }

  file.close();

  return true;
}

// static
std::unique_ptr<Pacman> Pacman::NewFromConfig(const std::string& config_file) {
  ParseState state;

  alpm_errno_t err;
  state.alpm = alpm_initialize("/", "/var/lib/pacman", &err);
  if (state.alpm == nullptr) {
    return nullptr;
  }

  if (!ParseOneFile(config_file, &state)) {
    return nullptr;
  }

  return std::unique_ptr<Pacman>(
      new Pacman(state.alpm, std::move(state.ignorepkgs)));
}

bool Pacman::ShouldIgnorePackage(const std::string& package) const {
  return std::find_if(ignored_packages_.cbegin(), ignored_packages_.cend(),
                      [&package](const std::string& p) {
                        return fnmatch(p.c_str(), package.c_str(), 0) == 0;
                      }) != ignored_packages_.cend();
}

std::string Pacman::RepoForPackage(const std::string& package) const {
  for (auto i = alpm_get_syncdbs(alpm_); i != nullptr; i = i->next) {
    auto db = static_cast<alpm_db_t*>(i->data);

    if (alpm_find_satisfier(alpm_db_get_pkgcache(db), package.c_str())) {
      return alpm_db_get_name(db);
    }
  }

  return std::string();
}

bool Pacman::PackageIsInstalled(const std::string& package) const {
  auto* cache = alpm_db_get_pkgcache(local_db_);
  return alpm_find_satisfier(cache, package.c_str()) != nullptr;
}

std::vector<Pacman::Package> Pacman::ForeignPackages() const {
  std::vector<Package> packages;

  for (auto i = alpm_db_get_pkgcache(local_db_); i; i = i->next) {
    const auto pkg = static_cast<alpm_pkg_t*>(i->data);
    const std::string pkgname(alpm_pkg_get_name(pkg));

    if (RepoForPackage(pkgname).empty()) {
      packages.emplace_back(pkgname, alpm_pkg_get_version(pkg));
    }
  }

  return packages;
}

// static
int Pacman::Vercmp(const std::string& a, const std::string& b) {
  return alpm_pkg_vercmp(a.c_str(), b.c_str());
}

}  // namespace dlr
<commit_msg>Fix build against latest release of pacman<commit_after>#include "pacman.hh"

#include <fnmatch.h>
#include <glob.h>

#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

namespace {

struct GlobbufFree {
  void operator()(glob_t* globbuf) { globfree(globbuf); }
};

std::string& ltrim(std::string& s) {
  s.erase(s.begin(),
          std::find_if(s.begin(), s.end(),
                       std::not1(std::ptr_fun<int, int>(std::isspace))));
  return s;
}

std::string& rtrim(std::string& s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
                       std::not1(std::ptr_fun<int, int>(std::isspace)))
              .base(),
          s.end());
  return s;
}

std::string& trim(std::string& s) { return ltrim(rtrim(s)); }

}  // namespace

namespace dlr {

Pacman::Pacman(alpm_handle_t* alpm, std::vector<std::string> ignored_packages)
    : alpm_(alpm),
      local_db_(alpm_get_localdb(alpm_)),
      ignored_packages_(std::move(ignored_packages)) {}

Pacman::~Pacman() { alpm_release(alpm_); }

struct ParseState {
  alpm_handle_t* alpm;

  std::string section;
  std::vector<std::string> ignorepkgs;
};

bool IsSection(const std::string& s) {
  return s.size() > 2 && s[0] == '[' && s[s.size() - 1] == ']';
}

bool ParseOneFile(const std::string& path, ParseState* state) {
  std::ifstream file(path);

  std::string line;
  while (std::getline(file, line)) {
    line = trim(line);

    if (line.size() == 0 || line[0] == '#') {
      continue;
    }

    if (IsSection(line)) {
      state->section = line.substr(1, line.size() - 2);
      continue;
    }

    auto equals = line.find_first_of('=');
    if (equals == std::string::npos) {
      // There aren't any directives we care about which are valueless.
      continue;
    }

    auto key = line.substr(0, equals);
    key = trim(key);

    auto value = line.substr(equals + 1);

    if (state->section == "options") {
      if (key == "IgnorePkg") {
        std::istringstream iss(value);
        std::copy(std::istream_iterator<std::string>(iss),
                  std::istream_iterator<std::string>(),
                  std::back_inserter(state->ignorepkgs));
      }
    } else {
      alpm_register_syncdb(state->alpm, state->section.c_str(),
                           static_cast<alpm_siglevel_t>(0));
    }

    if (key == "Include") {
      std::unique_ptr<glob_t, GlobbufFree> globbuf(new glob_t);

      if (glob(value.c_str(), GLOB_NOCHECK, nullptr, globbuf.get()) != 0) {
        return false;
      }

      for (size_t i = 0; i < globbuf->gl_pathc; ++i) {
        if (ParseOneFile(globbuf->gl_pathv[i], state) == false) {
          return false;
        }
      }
    }
  }

  file.close();

  return true;
}

// static
std::unique_ptr<Pacman> Pacman::NewFromConfig(const std::string& config_file) {
  ParseState state;

  alpm_errno_t err;
  state.alpm = alpm_initialize("/", "/var/lib/pacman", &err);
  if (state.alpm == nullptr) {
    return nullptr;
  }

  if (!ParseOneFile(config_file, &state)) {
    return nullptr;
  }

  return std::unique_ptr<Pacman>(
      new Pacman(state.alpm, std::move(state.ignorepkgs)));
}

bool Pacman::ShouldIgnorePackage(const std::string& package) const {
  return std::find_if(ignored_packages_.cbegin(), ignored_packages_.cend(),
                      [&package](const std::string& p) {
                        return fnmatch(p.c_str(), package.c_str(), 0) == 0;
                      }) != ignored_packages_.cend();
}

std::string Pacman::RepoForPackage(const std::string& package) const {
  for (auto i = alpm_get_syncdbs(alpm_); i != nullptr; i = i->next) {
    auto db = static_cast<alpm_db_t*>(i->data);

    if (alpm_find_satisfier(alpm_db_get_pkgcache(db), package.c_str())) {
      return alpm_db_get_name(db);
    }
  }

  return std::string();
}

bool Pacman::PackageIsInstalled(const std::string& package) const {
  auto* cache = alpm_db_get_pkgcache(local_db_);
  return alpm_find_satisfier(cache, package.c_str()) != nullptr;
}

std::vector<Pacman::Package> Pacman::ForeignPackages() const {
  std::vector<Package> packages;

  for (auto i = alpm_db_get_pkgcache(local_db_); i; i = i->next) {
    const auto pkg = static_cast<alpm_pkg_t*>(i->data);
    const std::string pkgname(alpm_pkg_get_name(pkg));

    if (RepoForPackage(pkgname).empty()) {
      packages.emplace_back(pkgname, alpm_pkg_get_version(pkg));
    }
  }

  return packages;
}

// static
int Pacman::Vercmp(const std::string& a, const std::string& b) {
  return alpm_pkg_vercmp(a.c_str(), b.c_str());
}

}  // namespace dlr
<|endoftext|>


<commit_before>/*
 */
#include "types.hpp"
#include "ast/ast.hpp"

const char* coretype_name(const eCoreType ct ) {
    switch(ct)
    {
    case CORETYPE_INVAL:return "-";
    case CORETYPE_ANY:  return "_";
    case CORETYPE_CHAR: return "char";
    case CORETYPE_UINT: return "usize";
    case CORETYPE_INT:  return "isize";
    case CORETYPE_U8:   return "u8";
    case CORETYPE_I8:   return "i8";
    case CORETYPE_U16:  return "u16";
    case CORETYPE_I16:  return "i16";
    case CORETYPE_U32:  return "u32";
    case CORETYPE_I32:  return "i32";
    case CORETYPE_U64:  return "u64";
    case CORETYPE_I64:  return "i64";
    case CORETYPE_F32:  return "f32";
    case CORETYPE_F64:  return "f64";
    }
    DEBUG("Unknown core type?! " << ct);
    return "NFI";
}

void TypeRef::merge_with(const TypeRef& other)
{
    // Ignore if other is wildcard
    if( other.m_class == TypeRef::ANY )
        return;

    if( m_class == TypeRef::ANY ) {
        *this = other;
        return;
    }

    if( m_class != other.m_class )
        throw ::std::runtime_error("TypeRef::merge_with - Types not compatible");

    if( is_concrete() && other.is_concrete() )
    {
        if( *this != other )
            throw ::std::runtime_error("TypeRef::merge_with - Types not compatible");
        return;
    }

    switch(m_class)
    {
    case TypeRef::ANY:
    case TypeRef::UNIT:
    case TypeRef::PRIMITIVE:
        throw ::std::runtime_error("TypeRef::merge_with - Reached concrete/wildcard");
    case TypeRef::TUPLE:
        // Other is known not to be wildcard, and is also a tuple, so it must be the same size
        if( m_inner_types.size() != other.m_inner_types.size() )
            throw ::std::runtime_error("TypeRef::merge_with - Types not compatible [tuple sz]");
        for(unsigned int i = 0; i < m_inner_types.size(); i ++)
        {
            m_inner_types[i].merge_with( other.m_inner_types[i] );
        }
        break;
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
        if( m_is_inner_mutable != other.m_is_inner_mutable )
            throw ::std::runtime_error("TypeRef::merge_with - Types not compatible [inner mut]");
        assert( m_inner_types.size() == 1 );
        assert( other.m_inner_types.size() == 1 );
        m_inner_types[0].merge_with( other.m_inner_types[0] );
        break;
    case TypeRef::ARRAY:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on ARRAY");
    case TypeRef::GENERIC:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on GENERIC");
    case TypeRef::PATH:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on PATH");
    case TypeRef::ASSOCIATED:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on ASSOCIATED");
    }
}

/// Resolve all Generic/Argument types to the value returned by the passed closure
void TypeRef::resolve_args(::std::function<TypeRef(const char*)> fcn)
{
    DEBUG("" << *this);
    switch(m_class)
    {
    case TypeRef::ANY:
        // TODO: Is resolving args on an ANY an erorr?
        break;
    case TypeRef::UNIT:
    case TypeRef::PRIMITIVE:
        break;
    case TypeRef::TUPLE:
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
    case TypeRef::ARRAY:
        for( auto& t : m_inner_types )
            t.resolve_args(fcn);
        break;
    case TypeRef::GENERIC:
        *this = fcn(m_path[0].name().c_str());
        break;
    case TypeRef::PATH:
        for(auto& n : m_path.nodes())
        {
            for(auto& p : n.args())
                p.resolve_args(fcn);
        }
        break;
    case TypeRef::ASSOCIATED:
        for(auto& t : m_inner_types )
            t.resolve_args(fcn);
        break;
    }
}

void TypeRef::match_args(const TypeRef& other, ::std::function<void(const char*,const TypeRef&)> fcn) const
{
    // If the other type is a wildcard, early return
    // - TODO - Might want to restrict the other type to be of the same form as this type
    if( other.m_class == TypeRef::ANY )
        return;
    // If this type is a generic, then call the closure with the other type
    if( m_class == TypeRef::GENERIC ) {
        fcn( m_path[0].name().c_str(), other );
        return ;
    }

    // Any other case, it's a "pattern" match
    if( m_class != other.m_class )
        throw ::std::runtime_error("Type mismatch (class)");
    switch(m_class)
    {
    case TypeRef::ANY:
        // Wait, isn't this an error?
        throw ::std::runtime_error("Encountered '_' in match_args");
    case TypeRef::UNIT:
        break;
    case TypeRef::PRIMITIVE:
        // TODO: Should check if the type matches
        if( m_core_type != other.m_core_type )
            throw ::std::runtime_error("Type mismatch (core)");
        break;
    case TypeRef::TUPLE:
        if( m_inner_types.size() != other.m_inner_types.size() )
            throw ::std::runtime_error("Type mismatch (tuple size)");
        for(unsigned int i = 0; i < m_inner_types.size(); i ++ )
            m_inner_types[i].match_args( other.m_inner_types[i], fcn );
        break;
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
        if( m_is_inner_mutable != other.m_is_inner_mutable )
            throw ::std::runtime_error("Type mismatch (inner mutable)");
        m_inner_types[0].match_args( other.m_inner_types[0], fcn );
        break;
    case TypeRef::ARRAY:
        throw ::std::runtime_error("TODO: TypeRef::match_args on ARRAY");
    case TypeRef::GENERIC:
        throw ::std::runtime_error("Encountered GENERIC in match_args");
    case TypeRef::PATH:
        throw ::std::runtime_error("TODO: TypeRef::match_args on PATH");
    case TypeRef::ASSOCIATED:
        throw ::std::runtime_error("TODO: TypeRef::match_args on ASSOCIATED");
    }
}

bool TypeRef::is_concrete() const
{
    switch(m_class)
    {
    case TypeRef::ANY:
        return false;
    case TypeRef::UNIT:
    case TypeRef::PRIMITIVE:
        return true;
    case TypeRef::TUPLE:
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
    case TypeRef::ARRAY:
        for(const auto& t : m_inner_types )
            if( not t.is_concrete() )
                return false;
        return true;
    case TypeRef::GENERIC:
        // Well, I guess a generic param is "concrete"
        return true;
    case TypeRef::PATH:
        for(const auto& n : m_path.nodes())
        {
            for(const auto& p : n.args())
                if( not p.is_concrete() )
                    return false;
        }
        return true;
    case TypeRef::ASSOCIATED:
        for(const auto& t : m_inner_types )
            if( not t.is_concrete() )
                return false;
        for(const auto& n : m_path.nodes())
        {
            for(const auto& p : n.args())
                if( not p.is_concrete() )
                    return false;
        }
        return true;
    }
    throw ::std::runtime_error( FMT("BUGCHECK - Invalid type class on " << *this) );
}

bool TypeRef::operator==(const TypeRef& x) const
{
    if(m_class != x.m_class)
        return false;
    switch(m_class)
    {
    case TypeRef::ANY:
    case TypeRef::UNIT:
        return true;
    case TypeRef::PRIMITIVE:
        return m_core_type == x.m_core_type;
    case TypeRef::TUPLE:
        return m_inner_types == x.m_inner_types;
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
        return m_is_inner_mutable == x.m_is_inner_mutable && m_inner_types == x.m_inner_types;
    case TypeRef::ARRAY:
        if(m_inner_types[0] != x.m_inner_types[0])
            return false;
        if(m_size_expr.get())
        {
            throw ::std::runtime_error("TODO: Sized array comparisons");
        }
        return true;
    case TypeRef::GENERIC:
        DEBUG(*this << " == " << x);
        throw ::std::runtime_error("BUGCHECK - Can't compare generic type");
    case TypeRef::PATH:
        return m_path == x.m_path;
    case TypeRef::ASSOCIATED:
        return m_path == x.m_path && m_inner_types == x.m_inner_types;
    }
    throw ::std::runtime_error(FMT("BUGCHECK - Unhandled TypeRef class '" << m_class << "'"));
}

::std::ostream& operator<<(::std::ostream& os, const eCoreType ct) {
    return os << coretype_name(ct);
}

::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr) {
    os << "TypeRef(";
    switch(tr.m_class)
    {
    case TypeRef::ANY:
        //os << "TagAny";
        os << "_";
        if( tr.m_inner_types.size() ) {
            os << ": {" << tr.m_inner_types << "}";
        }
        break;
    case TypeRef::UNIT:
        //os << "TagUnit";
        os << "()";
        break;
    case TypeRef::PRIMITIVE:
        //os << "TagPrimitive, " << tr.m_core_type;
        os << tr.m_core_type;
        break;
    case TypeRef::TUPLE:
        //os << "TagTuple, {" << tr.m_inner_types << "}";
        os << "(" << tr.m_inner_types << ",)";
        break;
    case TypeRef::REFERENCE:
        //os << "TagReference, " << (tr.m_is_inner_mutable ? "mut" : "const") << ", " << tr.m_inner_types[0];
        os << "&" << (tr.m_is_inner_mutable ? "mut " : "") << tr.m_inner_types[0];
        break;
    case TypeRef::POINTER:
        //os << "TagPointer, " << (tr.m_is_inner_mutable ? "mut" : "const") << ", " << tr.m_inner_types[0];
        os << "*" << (tr.m_is_inner_mutable ? "mut" : "const") << " " << tr.m_inner_types[0];
        break;
    case TypeRef::ARRAY:
        os << "TagSizedArray, " << tr.m_inner_types[0] << ", " << tr.m_size_expr;
        break;
    case TypeRef::GENERIC:
        os << "TagArg, " << tr.m_path[0].name();
        break;
    case TypeRef::PATH:
        //os << "TagPath, " << tr.m_path;
        os << tr.m_path;
        break;
    case TypeRef::ASSOCIATED:
        //os << "TagAssoc, <" << tr.m_inner_types[0] << " as " << tr.m_inner_types[1] << ">::" << tr.m_path[0].name();
        os << "<" << tr.m_inner_types[0] << " as " << tr.m_inner_types[1] << ">::" << tr.m_path[0].name();
        break;
    }
    os << ")";
    return os;
}

void operator% (::Serialiser& s, eCoreType ct) {
    s << coretype_name(ct);
}
void operator% (::Deserialiser& d, eCoreType& ct) {
    ::std::string n;
    d.item(n);
    /* */if(n == "-")   ct = CORETYPE_INVAL;
    else if(n == "_")   ct = CORETYPE_ANY;
    else if(n == "char")  ct = CORETYPE_CHAR;
    else if(n == "usize") ct = CORETYPE_UINT;
    else if(n == "isize") ct = CORETYPE_INT;
    else if(n == "u8")    ct = CORETYPE_U8;
    else if(n == "i8")    ct = CORETYPE_I8;
    else if(n == "u16")   ct = CORETYPE_U16;
    else if(n == "i16")   ct = CORETYPE_I16;
    else if(n == "u32")   ct = CORETYPE_U32;
    else if(n == "i32")   ct = CORETYPE_I32;
    else if(n == "u64")   ct = CORETYPE_U64;
    else if(n == "i64")   ct = CORETYPE_I64;
    else if(n == "f32")   ct = CORETYPE_F32;
    else if(n == "f64")   ct = CORETYPE_F64;
    else
        throw ::std::runtime_error("Deserialise failure - coretype " + n);
}
const char* TypeRef::class_name(TypeRef::Class c) {
    switch(c)
    {
    #define _(x)    case TypeRef::x: return #x;
    _(ANY)
    _(UNIT)
    _(PRIMITIVE)
    _(TUPLE)
    _(REFERENCE)
    _(POINTER)
    _(ARRAY)
    _(GENERIC)
    _(PATH)
    _(ASSOCIATED)
    #undef _
    }
    return "NFI";
}
void operator>>(::Deserialiser& d, TypeRef::Class& c) {
    ::std::string n;
    d.item(n);
    #define _(x) if(n == #x) c = TypeRef::x;
    /**/ _(ANY)
    else _(UNIT)
    else _(PRIMITIVE)
    else _(TUPLE)
    else _(REFERENCE)
    else _(POINTER)
    else _(ARRAY)
    else _(GENERIC)
    else _(PATH)
    else _(ASSOCIATED)
    else
        throw ::std::runtime_error("Deserialise failure - " + n);
    #undef _
}
SERIALISE_TYPE(TypeRef::, "TypeRef", {
    s << class_name(m_class);
    if(m_class == PRIMITIVE)
        s << coretype_name(m_core_type);
    s << m_inner_types;
    if(m_class == REFERENCE || m_class == POINTER)
        s << m_is_inner_mutable;
    s << m_size_expr;
    s << m_path;
},{
    s >> m_class;
    if(m_class == PRIMITIVE)
        s % m_core_type;
    s.item( m_inner_types );
    if(m_class == REFERENCE || m_class == POINTER)
        s.item( m_is_inner_mutable );
    bool size_expr_present;
    s.item(size_expr_present);
    if( size_expr_present )
        m_size_expr = AST::ExprNode::from_deserialiser(s);
    else
        m_size_expr.reset();
    s.item( m_path );
})
<commit_msg>(minor) Types - Added some documenting comments<commit_after>/*
 * MRustC - Mutabah's Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * types.cpp
 * - Backing code for the TypeRef class
 *
 * Handles a chunk of type resolution (merging) and matching/comparing types
 */
#include "types.hpp"
#include "ast/ast.hpp"

const char* coretype_name(const eCoreType ct ) {
    switch(ct)
    {
    case CORETYPE_INVAL:return "-";
    case CORETYPE_ANY:  return "_";
    case CORETYPE_CHAR: return "char";
    case CORETYPE_UINT: return "usize";
    case CORETYPE_INT:  return "isize";
    case CORETYPE_U8:   return "u8";
    case CORETYPE_I8:   return "i8";
    case CORETYPE_U16:  return "u16";
    case CORETYPE_I16:  return "i16";
    case CORETYPE_U32:  return "u32";
    case CORETYPE_I32:  return "i32";
    case CORETYPE_U64:  return "u64";
    case CORETYPE_I64:  return "i64";
    case CORETYPE_F32:  return "f32";
    case CORETYPE_F64:  return "f64";
    }
    DEBUG("Unknown core type?! " << ct);
    return "NFI";
}

/// Merge the contents of the passed type with this type
///
/// \note Both types must be of the same form (i.e. both be tuples)
void TypeRef::merge_with(const TypeRef& other)
{
    // Ignore if other is wildcard
    if( other.m_class == TypeRef::ANY ) {
        assert(other.m_inner_types.size() == 0 && !"TODO: merge_with on bounded _");
        return;
    }

    // If this is a wildcard, then replace with the othet type
    if( m_class == TypeRef::ANY ) {
        assert(m_inner_types.size() == 0 && !"TODO: merge_with on bounded _");
        *this = other;
        return;
    }

    // If classes don't match, then merge is impossible
    if( m_class != other.m_class )
        throw ::std::runtime_error("TypeRef::merge_with - Types not compatible");

    // If both types are concrete, then they must be the same
    if( is_concrete() && other.is_concrete() )
    {
        if( *this != other )
            throw ::std::runtime_error("TypeRef::merge_with - Types not compatible");
        return;
    }

    switch(m_class)
    {
    case TypeRef::ANY:
    case TypeRef::UNIT:
    case TypeRef::PRIMITIVE:
        throw ::std::runtime_error("TypeRef::merge_with - Reached concrete/wildcard");
    case TypeRef::TUPLE:
        // Other is known not to be wildcard, and is also a tuple, so it must be the same size
        if( m_inner_types.size() != other.m_inner_types.size() )
            throw ::std::runtime_error("TypeRef::merge_with - Types not compatible [tuple sz]");
        for(unsigned int i = 0; i < m_inner_types.size(); i ++)
        {
            m_inner_types[i].merge_with( other.m_inner_types[i] );
        }
        break;
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
        if( m_is_inner_mutable != other.m_is_inner_mutable )
            throw ::std::runtime_error("TypeRef::merge_with - Types not compatible [inner mut]");
        assert( m_inner_types.size() == 1 );
        assert( other.m_inner_types.size() == 1 );
        m_inner_types[0].merge_with( other.m_inner_types[0] );
        break;
    case TypeRef::ARRAY:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on ARRAY");
    case TypeRef::GENERIC:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on GENERIC");
    case TypeRef::PATH:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on PATH");
    case TypeRef::ASSOCIATED:
        throw ::std::runtime_error("TODO: TypeRef::merge_with on ASSOCIATED");
    }
}

/// Resolve all Generic/Argument types to the value returned by the passed closure
///
/// Replaces every instance of a TypeRef::GENERIC with the value returned from the passed
/// closure.
void TypeRef::resolve_args(::std::function<TypeRef(const char*)> fcn)
{
    DEBUG("" << *this);
    switch(m_class)
    {
    case TypeRef::ANY:
        // TODO: Is resolving args on an ANY an erorr?
        break;
    case TypeRef::UNIT:
    case TypeRef::PRIMITIVE:
        break;
    case TypeRef::TUPLE:
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
    case TypeRef::ARRAY:
        for( auto& t : m_inner_types )
            t.resolve_args(fcn);
        break;
    case TypeRef::GENERIC:
        *this = fcn(m_path[0].name().c_str());
        break;
    case TypeRef::PATH:
        for(auto& n : m_path.nodes())
        {
            for(auto& p : n.args())
                p.resolve_args(fcn);
        }
        break;
    case TypeRef::ASSOCIATED:
        for(auto& t : m_inner_types )
            t.resolve_args(fcn);
        break;
    }
}

/// Match this type against another type, calling the provided function for all generics found in this
///
/// \param other    Type containing (possibly) concrete types
/// \param fcn  Function to call for all generics (called with matching type from \a other)
/// This is used to handle extracting types passsed to methods/enum variants
void TypeRef::match_args(const TypeRef& other, ::std::function<void(const char*,const TypeRef&)> fcn) const
{
    // If the other type is a wildcard, early return
    // - TODO - Might want to restrict the other type to be of the same form as this type
    if( other.m_class == TypeRef::ANY )
        return;
    // If this type is a generic, then call the closure with the other type
    if( m_class == TypeRef::GENERIC ) {
        fcn( m_path[0].name().c_str(), other );
        return ;
    }

    // Any other case, it's a "pattern" match
    if( m_class != other.m_class )
        throw ::std::runtime_error("Type mismatch (class)");
    switch(m_class)
    {
    case TypeRef::ANY:
        // Wait, isn't this an error?
        throw ::std::runtime_error("Encountered '_' in match_args");
    case TypeRef::UNIT:
        break;
    case TypeRef::PRIMITIVE:
        // TODO: Should check if the type matches
        if( m_core_type != other.m_core_type )
            throw ::std::runtime_error("Type mismatch (core)");
        break;
    case TypeRef::TUPLE:
        if( m_inner_types.size() != other.m_inner_types.size() )
            throw ::std::runtime_error("Type mismatch (tuple size)");
        for(unsigned int i = 0; i < m_inner_types.size(); i ++ )
            m_inner_types[i].match_args( other.m_inner_types[i], fcn );
        break;
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
        if( m_is_inner_mutable != other.m_is_inner_mutable )
            throw ::std::runtime_error("Type mismatch (inner mutable)");
        m_inner_types[0].match_args( other.m_inner_types[0], fcn );
        break;
    case TypeRef::ARRAY:
        throw ::std::runtime_error("TODO: TypeRef::match_args on ARRAY");
    case TypeRef::GENERIC:
        throw ::std::runtime_error("Encountered GENERIC in match_args");
    case TypeRef::PATH:
        throw ::std::runtime_error("TODO: TypeRef::match_args on PATH");
    case TypeRef::ASSOCIATED:
        throw ::std::runtime_error("TODO: TypeRef::match_args on ASSOCIATED");
    }
}

/// Checks if the type is fully bounded
bool TypeRef::is_concrete() const
{
    switch(m_class)
    {
    case TypeRef::ANY:
        return false;
    case TypeRef::UNIT:
    case TypeRef::PRIMITIVE:
        return true;
    case TypeRef::TUPLE:
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
    case TypeRef::ARRAY:
        for(const auto& t : m_inner_types )
            if( not t.is_concrete() )
                return false;
        return true;
    case TypeRef::GENERIC:
        // Well, I guess a generic param is "concrete"
        return true;
    case TypeRef::PATH:
        for(const auto& n : m_path.nodes())
        {
            for(const auto& p : n.args())
                if( not p.is_concrete() )
                    return false;
        }
        return true;
    case TypeRef::ASSOCIATED:
        for(const auto& t : m_inner_types )
            if( not t.is_concrete() )
                return false;
        for(const auto& n : m_path.nodes())
        {
            for(const auto& p : n.args())
                if( not p.is_concrete() )
                    return false;
        }
        return true;
    }
    throw ::std::runtime_error( FMT("BUGCHECK - Invalid type class on " << *this) );
}

bool TypeRef::operator==(const TypeRef& x) const
{
    if(m_class != x.m_class)
        return false;
    switch(m_class)
    {
    case TypeRef::ANY:
    case TypeRef::UNIT:
        return true;
    case TypeRef::PRIMITIVE:
        return m_core_type == x.m_core_type;
    case TypeRef::TUPLE:
        return m_inner_types == x.m_inner_types;
    case TypeRef::REFERENCE:
    case TypeRef::POINTER:
        return m_is_inner_mutable == x.m_is_inner_mutable && m_inner_types == x.m_inner_types;
    case TypeRef::ARRAY:
        if(m_inner_types[0] != x.m_inner_types[0])
            return false;
        if(m_size_expr.get())
        {
            throw ::std::runtime_error("TODO: Sized array comparisons");
        }
        return true;
    case TypeRef::GENERIC:
        DEBUG(*this << " == " << x);
        throw ::std::runtime_error("BUGCHECK - Can't compare generic type");
    case TypeRef::PATH:
        return m_path == x.m_path;
    case TypeRef::ASSOCIATED:
        return m_path == x.m_path && m_inner_types == x.m_inner_types;
    }
    throw ::std::runtime_error(FMT("BUGCHECK - Unhandled TypeRef class '" << m_class << "'"));
}

::std::ostream& operator<<(::std::ostream& os, const eCoreType ct) {
    return os << coretype_name(ct);
}

::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr) {
    os << "TypeRef(";
    switch(tr.m_class)
    {
    case TypeRef::ANY:
        //os << "TagAny";
        os << "_";
        if( tr.m_inner_types.size() ) {
            os << ": {" << tr.m_inner_types << "}";
        }
        break;
    case TypeRef::UNIT:
        //os << "TagUnit";
        os << "()";
        break;
    case TypeRef::PRIMITIVE:
        //os << "TagPrimitive, " << tr.m_core_type;
        os << tr.m_core_type;
        break;
    case TypeRef::TUPLE:
        //os << "TagTuple, {" << tr.m_inner_types << "}";
        os << "(" << tr.m_inner_types << ",)";
        break;
    case TypeRef::REFERENCE:
        //os << "TagReference, " << (tr.m_is_inner_mutable ? "mut" : "const") << ", " << tr.m_inner_types[0];
        os << "&" << (tr.m_is_inner_mutable ? "mut " : "") << tr.m_inner_types[0];
        break;
    case TypeRef::POINTER:
        //os << "TagPointer, " << (tr.m_is_inner_mutable ? "mut" : "const") << ", " << tr.m_inner_types[0];
        os << "*" << (tr.m_is_inner_mutable ? "mut" : "const") << " " << tr.m_inner_types[0];
        break;
    case TypeRef::ARRAY:
        os << "TagSizedArray, " << tr.m_inner_types[0] << ", " << tr.m_size_expr;
        break;
    case TypeRef::GENERIC:
        os << "TagArg, " << tr.m_path[0].name();
        break;
    case TypeRef::PATH:
        //os << "TagPath, " << tr.m_path;
        os << tr.m_path;
        break;
    case TypeRef::ASSOCIATED:
        //os << "TagAssoc, <" << tr.m_inner_types[0] << " as " << tr.m_inner_types[1] << ">::" << tr.m_path[0].name();
        os << "<" << tr.m_inner_types[0] << " as " << tr.m_inner_types[1] << ">::" << tr.m_path[0].name();
        break;
    }
    os << ")";
    return os;
}

void operator% (::Serialiser& s, eCoreType ct) {
    s << coretype_name(ct);
}
void operator% (::Deserialiser& d, eCoreType& ct) {
    ::std::string n;
    d.item(n);
    /* */if(n == "-")   ct = CORETYPE_INVAL;
    else if(n == "_")   ct = CORETYPE_ANY;
    else if(n == "char")  ct = CORETYPE_CHAR;
    else if(n == "usize") ct = CORETYPE_UINT;
    else if(n == "isize") ct = CORETYPE_INT;
    else if(n == "u8")    ct = CORETYPE_U8;
    else if(n == "i8")    ct = CORETYPE_I8;
    else if(n == "u16")   ct = CORETYPE_U16;
    else if(n == "i16")   ct = CORETYPE_I16;
    else if(n == "u32")   ct = CORETYPE_U32;
    else if(n == "i32")   ct = CORETYPE_I32;
    else if(n == "u64")   ct = CORETYPE_U64;
    else if(n == "i64")   ct = CORETYPE_I64;
    else if(n == "f32")   ct = CORETYPE_F32;
    else if(n == "f64")   ct = CORETYPE_F64;
    else
        throw ::std::runtime_error("Deserialise failure - coretype " + n);
}
const char* TypeRef::class_name(TypeRef::Class c) {
    switch(c)
    {
    #define _(x)    case TypeRef::x: return #x;
    _(ANY)
    _(UNIT)
    _(PRIMITIVE)
    _(TUPLE)
    _(REFERENCE)
    _(POINTER)
    _(ARRAY)
    _(GENERIC)
    _(PATH)
    _(ASSOCIATED)
    #undef _
    }
    return "NFI";
}
void operator>>(::Deserialiser& d, TypeRef::Class& c) {
    ::std::string n;
    d.item(n);
    #define _(x) if(n == #x) c = TypeRef::x;
    /**/ _(ANY)
    else _(UNIT)
    else _(PRIMITIVE)
    else _(TUPLE)
    else _(REFERENCE)
    else _(POINTER)
    else _(ARRAY)
    else _(GENERIC)
    else _(PATH)
    else _(ASSOCIATED)
    else
        throw ::std::runtime_error("Deserialise failure - " + n);
    #undef _
}
SERIALISE_TYPE(TypeRef::, "TypeRef", {
    s << class_name(m_class);
    if(m_class == PRIMITIVE)
        s << coretype_name(m_core_type);
    s << m_inner_types;
    if(m_class == REFERENCE || m_class == POINTER)
        s << m_is_inner_mutable;
    s << m_size_expr;
    s << m_path;
},{
    s >> m_class;
    if(m_class == PRIMITIVE)
        s % m_core_type;
    s.item( m_inner_types );
    if(m_class == REFERENCE || m_class == POINTER)
        s.item( m_is_inner_mutable );
    bool size_expr_present;
    s.item(size_expr_present);
    if( size_expr_present )
        m_size_expr = AST::ExprNode::from_deserialiser(s);
    else
        m_size_expr.reset();
    s.item( m_path );
})
<|endoftext|>