aboutsummaryrefslogblamecommitdiffstatshomepage
path: root/src/string.hpp
blob: 3621ca62bdf53fb3d7a74bf93684a924c479d6c7 (plain) (tree)

























































































































































                                                                                                                                                                      
#pragma once

#include <cctype>
#include <cstddef>

#include <algorithm>
#include <locale>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>

namespace string
{
    template <typename Char>
    inline void ltrim(std::basic_string<Char>& s)
    {
        s.erase(s.begin(), std::find_if(s.begin(), s.end(), [] (const Char& c)
        {
            return !std::isspace(c);
        }));
    }

    template <typename Char>
    inline void rtrim(std::basic_string<Char>& s)
    {
        s.erase(std::find_if(s.rbegin(), s.rend(), [] (const Char& c)
        {
            return !std::isspace(c);
        }).base(), s.end());
    }

    template <typename Char>
    inline void trim(std::basic_string<Char>& s)
    {
        ltrim(s);
        rtrim(s);
    }

    template <typename Char, typename Sep, typename InputIterator>
    inline std::basic_string<Char> join(
        const Sep& sep,
        InputIterator beg,
        InputIterator end)
    {
        std::basic_ostringstream<Char> oss;

        if (beg != end)
        {
            oss << *beg;
            ++beg;
        }

        for (; beg != end; ++beg)
            oss << sep << *beg;

        return oss.str();
    }

    template <typename Char, typename Sep>
    inline std::basic_string<Char> join(
        const Sep& sep,
        const std::vector<std::basic_string<Char>>& args)
    {
        return join<Char>(sep, args.cbegin(), args.cend());
    }

    template <typename Char, typename String, typename = void>
    struct StringHelper
    { };

    template <typename Char, typename String>
    struct StringHelper<Char, String, typename std::enable_if<std::is_same<typename std::decay<typename std::remove_pointer<String>::type>::type, Char>::value>::type>
    {
        inline StringHelper(const Char& c)
            : buf{&c}
            , len{1}
        { }

        inline StringHelper(const Char* s)
            : buf{s}
            , len{std::char_traits<Char>::length(s)}
        { }

        inline const Char* buffer() const { return buf; }

        inline std::size_t length() const { return len; }

    private:
        const Char* const buf;
        const std::size_t len;
    };

    template <typename Char, typename String>
    struct StringHelper<Char, String, typename std::enable_if<std::is_same<String, std::basic_string<Char>>::value>::type>
    {
        inline StringHelper(const std::basic_string<Char>& s)
            : s{s}
        { }

        inline const Char* buffer() const { return s.c_str(); }

        inline std::size_t length() const { return s.length(); }

    private:
        const std::basic_string<Char>& s;
    };

    template <typename Char, typename What, typename By>
    inline void replace(
        std::basic_string<Char>& s,
        const What& what,
        const By& by)
    {
        std::size_t pos = 0;

        const StringHelper<Char, typename std::decay<What>::type> what_helper{what};
        const StringHelper<Char, typename std::decay<By>::type> by_helper{by};

        const auto what_buf = what_helper.buffer();
        const auto what_len = what_helper.length();

        const auto by_buf = by_helper.buffer();
        const auto by_len = by_helper.length();

        while ((pos = s.find(what_buf, pos, what_len)) != std::basic_string<Char>::npos)
        {
            s.replace(pos, what_len, by_buf, by_len);
            pos += by_len;
        }
    }

    template <typename Char, typename What>
    inline void prefix_with(
        std::basic_string<Char>& s,
        const What& what,
        const Char& by)
    {
        const StringHelper<Char, typename std::decay<What>::type> what_helper{what};

        const auto what_buf = what_helper.buffer();
        const auto what_len = what_helper.length();

        std::size_t numof_by = 0;

        for (std::size_t i = 0; i < what_len; ++i)
            numof_by += std::count(s.cbegin(), s.cend(), what_buf[i]);

        s.reserve(s.capacity() + numof_by);

        for (std::size_t i = 0; i < what_len; ++i)
            replace(s, what_buf[i], by);
    }
}