summaryrefslogtreecommitdiffstats
path: root/source/core/slang-string-util.h
blob: 03f503ed210ba5f5b4d611602d73c1b0e23bee07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#ifndef SLANG_CORE_STRING_UTIL_H
#define SLANG_CORE_STRING_UTIL_H

#include "slang-string.h"
#include "slang-list.h"

#include <stdarg.h>

#include "../../slang-com-helper.h"
#include "../../slang-com-ptr.h"

namespace Slang {

struct StringUtil
{
    typedef bool (*EqualFn)(const UnownedStringSlice& a, const UnownedStringSlice& b);

        /// True if the splits of a and b (via splitChar) are all equal as compared with the equalFn function
    static bool areAllEqualWithSplit(const UnownedStringSlice& a, const UnownedStringSlice& b, char splitChar, EqualFn equalFn);

        /// True if all slices in match are all equal as compared with the equalFn function
    static bool areAllEqual(const List<UnownedStringSlice>& a, const List<UnownedStringSlice>& b, EqualFn equalFn);

        /// Split in, by specified splitChar into slices out
        /// Slices contents will directly address into in, so contents will only stay valid as long as in does.
    static void split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut);
        /// Split in by the specified splitSlice
        /// Slices contents will directly address into in, so contents will only stay valid as long as in does.
    static void split(const UnownedStringSlice& in, const UnownedStringSlice& splitSlice, List<UnownedStringSlice>& slicesOut);

        /// Splits in into outSlices, up to maxSlices. May not consume all of in (for example if it runs out of space).
    static Index split(const UnownedStringSlice& in, char splitChar, Index maxSlices, UnownedStringSlice* outSlices);
        /// Splits into outSlices up to maxSlices. Returns SLANG_OK if of 'in' consumed.
    static SlangResult split(const UnownedStringSlice& in, char splitChar, Index maxSlices, UnownedStringSlice* outSlices, Index& outSlicesCount);

        /// Append the joining of in items, separated by 'separator' onto out
    static void join(const List<String>& in, char separator, StringBuilder& out);
    static void join(const List<String>& in, const UnownedStringSlice& separator, StringBuilder& out);

    static void join(const UnownedStringSlice* values, Index valueCount, char separator, StringBuilder& out);
    static void join(const UnownedStringSlice* values, Index valueCount, const UnownedStringSlice& separator, StringBuilder& out);

        /// Equivalent to doing a split and then finding the index of 'find' on the array
        /// Returns -1 if not found
    static Index indexOfInSplit(const UnownedStringSlice& in, char splitChar, const UnownedStringSlice& find);

        /// Given the entry at the split index specified.
        /// Will return slice with begin() == nullptr if not found or input has begin() == nullptr)
    static UnownedStringSlice getAtInSplit(const UnownedStringSlice& in, char splitChar, Index index);

        /// Returns the size in bytes needed to hold the formatted string using the specified args, NOT including a terminating 0
        /// NOTE! The caller *should* assume this will consume the va_list (use va_copy to make a copy to be consumed)
    static size_t calcFormattedSize(const char* format, va_list args);

        /// Calculate the formatted string using the specified args.
        /// NOTE! The caller *should* assume this will consume the va_list
        /// The buffer should be at least calcFormattedSize + 1 bytes. The +1 is needed because a terminating 0 is written. 
    static void calcFormatted(const char* format, va_list args, size_t numChars, char* dst);

        /// Appends formatted string with args into buf
    static void append(const char* format, va_list args, StringBuilder& buf);

        /// Appends the formatted string with specified trailing args
    static void appendFormat(StringBuilder& buf, const char* format, ...);

        /// Create a string from the format string applying args (like sprintf)
    static String makeStringWithFormat(const char* format, ...);

        /// Given a string held in a blob, returns as a String
        /// Returns an empty string if blob is nullptr 
    static String getString(ISlangBlob* blob);
    static UnownedStringSlice getSlice(ISlangBlob* blob);

        /// Given a string or slice, replaces all instances of fromChar with toChar
    static String calcCharReplaced(const UnownedStringSlice& slice, char fromChar, char toChar);
    static String calcCharReplaced(const String& string, char fromChar, char toChar);
    
        /// Create a blob from a string
    static ComPtr<ISlangBlob> createStringBlob(const String& string);

        /// Given input text outputs with standardized line endings. Ie \n\r -> \n
    static void appendStandardLines(const UnownedStringSlice& text, StringBuilder& out);

        /// Extracts a line and stores the remaining text in ioText, and the line in outLine. Returns true if has a line. 
        /// 
        /// As well as indicating end of text with the return value, at the end of all the text a 'special' null UnownedStringSlice with a null 'begin'
        /// pointer is also returned as the outLine.
        /// ioText will be modified to contain the remaining text, starting at the beginning of the next line.
        /// As an empty final line is still a line, the special null UnownedStringSlice is the last value ioText after the last valid line is returned.
        /// 
        /// NOTE! That behavior is as if line terminators (like \n) act as separators. Thus input of "\n" will return *two* lines - an empty line
        /// before and then after the \n. 
    static bool extractLine(UnownedStringSlice& ioText, UnownedStringSlice& outLine);
    
        /// Given text, splits into lines stored in outLines. NOTE! That lines is only valid as long as textIn remains valid
    static void calcLines(const UnownedStringSlice& textIn, List<UnownedStringSlice>& lines);

        /// Given a line that may contain cr/lf, returns the the a slice that doesn't have trailing cr/lf
    static UnownedStringSlice trimEndOfLine(const UnownedStringSlice& slice);

        /// Equal if the lines are equal (in effect a way to ignore differences in line breaks)
    static bool areLinesEqual(const UnownedStringSlice& a, const UnownedStringSlice& b);

        /// Convert in to int. Returns SLANG_FAIL on error
    static SlangResult parseInt(const UnownedStringSlice& in, Int& outValue);

        /// Convert ioText into double. Returns SLANG_OK on success.
    static SlangResult parseDouble(const UnownedStringSlice& text, double& out);

        /// Convert into int64_t. Returns SLANG_OK on success. 
    static SlangResult parseInt64(const UnownedStringSlice& text, int64_t& out);
};

/* A helper class that allows parsing of lines from text with iteration. Uses StringUtil::extractLine for the actual underlying implementation. */
class LineParser
{
public:
    struct Iterator
    {
        const UnownedStringSlice& operator*() const { return m_line; }
        const UnownedStringSlice* operator->() const { return &m_line; }
        Iterator& operator++()
        {
            StringUtil::extractLine(m_remaining, m_line);
            return *this;
        }
        Iterator operator++(int) { Iterator rs = *this; operator++(); return rs; }

            /// Equal if both are at the same m_line address exactly. Handles termination case correctly where line.begin() == nullptr.
        bool operator==(const Iterator& rhs) const { return m_line.begin() == rhs.m_line.begin();  }
        bool operator !=(const Iterator& rhs) const { return !(*this == rhs); }

            /// Ctor
        Iterator(const UnownedStringSlice& line, const UnownedStringSlice& remaining) : m_line(line), m_remaining(remaining) {}

    protected:
        UnownedStringSlice m_line;
        UnownedStringSlice m_remaining;
    };

    Iterator begin() const { UnownedStringSlice remaining(m_text), line;  StringUtil::extractLine(remaining, line); return Iterator(line, remaining);  }
    Iterator end() const { UnownedStringSlice term(nullptr, nullptr); return Iterator(term, term); }

        /// Ctor
    LineParser(const UnownedStringSlice& text) : m_text(text) {}

protected:
    UnownedStringSlice m_text;
};

} // namespace Slang

#endif // SLANG_STRING_UTIL_H