2022-08-05 01:01:41 +01:00
|
|
|
#pragma once
|
|
|
|
|
2022-08-07 00:15:47 +01:00
|
|
|
#include "Orange/Core/Vector.h"
|
2022-08-05 01:01:41 +01:00
|
|
|
#include <Orange/Core/Result.h>
|
|
|
|
#include <Orange/Core/Span.h>
|
|
|
|
|
|
|
|
#include <charconv>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
namespace orange::stream
|
|
|
|
{
|
|
|
|
template <typename T>
|
|
|
|
Result<T> Parse(const char*& first, const char* end)
|
|
|
|
{
|
|
|
|
T obj;
|
|
|
|
auto result = std::from_chars(first, end, obj);
|
|
|
|
if (result.ec == std::errc{})
|
|
|
|
{
|
|
|
|
first = result.ptr;
|
2022-08-05 03:26:36 +01:00
|
|
|
return Result<T>::Success(obj);
|
2022-08-05 01:01:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return Result<T>::Error(BasicErrorCode::NotFound);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Result<T> Parse(const char*& first, size_t length)
|
|
|
|
{
|
|
|
|
return Parse<T>(first, first + length);
|
|
|
|
}
|
|
|
|
|
2023-01-18 21:28:26 +00:00
|
|
|
template <typename T>
|
|
|
|
Result<T> Parse(StringView view)
|
|
|
|
{
|
|
|
|
return Parse<T>(view.data, view.size);
|
|
|
|
}
|
|
|
|
|
2022-08-05 01:01:41 +01:00
|
|
|
template <typename T>
|
|
|
|
Result<T> Parse(const char*& first)
|
|
|
|
{
|
|
|
|
return Parse<T>(first, first + strlen(first));
|
|
|
|
}
|
|
|
|
|
2022-08-05 03:26:36 +01:00
|
|
|
inline bool EndOfStream(const char* first, const char* end)
|
|
|
|
{
|
|
|
|
return first == end || *first == '\0';
|
|
|
|
}
|
|
|
|
|
2022-08-05 01:01:41 +01:00
|
|
|
inline bool CharMatches(char character, StringView delims)
|
|
|
|
{
|
|
|
|
for (auto delim : delims)
|
|
|
|
{
|
|
|
|
if (character == delim)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-05 03:26:36 +01:00
|
|
|
inline size_t Consume(const char*& first, const char* end, StringView delims)
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
|
|
|
size_t count = 0;
|
2022-08-05 03:26:36 +01:00
|
|
|
while (!EndOfStream(first, end) && CharMatches(*first, delims))
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
|
|
|
first++;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2023-01-18 21:28:26 +00:00
|
|
|
static constexpr const char* WhitespaceDelimiters = " \t";
|
|
|
|
static constexpr const char* NewlineDelimiters = "\r\n";
|
|
|
|
static constexpr const char* WhitespaceOrNewlineDelimiters = " \t\r\n";
|
|
|
|
|
2022-08-05 03:26:36 +01:00
|
|
|
inline size_t ConsumeSpace(const char*& first, const char* end)
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
2023-01-18 21:28:26 +00:00
|
|
|
return Consume(first, end, WhitespaceDelimiters);
|
2022-08-05 01:01:41 +01:00
|
|
|
}
|
|
|
|
|
2023-01-18 10:16:34 +00:00
|
|
|
inline size_t ConsumeSpaceAndNewLine(const char*& first, const char* end)
|
|
|
|
{
|
2023-01-18 21:28:26 +00:00
|
|
|
return Consume(first, end, WhitespaceOrNewlineDelimiters);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool IsWhitespace(char val)
|
|
|
|
{
|
|
|
|
return val == ' ' || val == '\t';
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool IsNewLine(char val)
|
|
|
|
{
|
|
|
|
return val == '\r' || val == '\n';
|
2023-01-18 10:16:34 +00:00
|
|
|
}
|
|
|
|
|
2022-08-07 00:15:47 +01:00
|
|
|
template <typename OutArray = SmallVector<char, 1>>
|
2022-08-05 03:26:36 +01:00
|
|
|
size_t ReadOrAdvance(const char*& first, const char* end, StringView delims, size_t advancement = 0, OutArray* array = nullptr)
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
|
|
|
size_t count = 0;
|
2022-08-05 03:26:36 +01:00
|
|
|
while (!EndOfStream(first, end) && !CharMatches(*first, delims))
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
|
|
|
if (array)
|
2022-08-25 07:27:11 +01:00
|
|
|
array->push_back(*first);
|
2022-08-05 01:01:41 +01:00
|
|
|
first++;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2022-08-05 03:26:36 +01:00
|
|
|
if (EndOfStream(first, end))
|
2022-08-05 01:01:41 +01:00
|
|
|
return count;
|
|
|
|
|
|
|
|
first += advancement;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2022-08-07 00:15:47 +01:00
|
|
|
template <typename OutArray = SmallVector<char, 1>>
|
2022-08-05 03:26:36 +01:00
|
|
|
size_t ReadString(const char*& first, const char* end, StringView delims, OutArray& array)
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
2022-08-05 03:26:36 +01:00
|
|
|
return ReadOrAdvance(first, end, delims, 0, &array);
|
2022-08-05 01:01:41 +01:00
|
|
|
}
|
|
|
|
|
2022-08-05 03:26:36 +01:00
|
|
|
inline size_t AdvancePast(const char*& first, const char* end, StringView delims)
|
2022-08-05 01:01:41 +01:00
|
|
|
{
|
2022-08-05 03:26:36 +01:00
|
|
|
return ReadOrAdvance(first, end, delims, 1);
|
2022-08-05 01:01:41 +01:00
|
|
|
}
|
2023-01-18 08:39:29 +00:00
|
|
|
|
|
|
|
inline bool IsStringToken(StringView fullRange, const char* first)
|
|
|
|
{
|
|
|
|
if (*first != '"')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Make sure we are in-range for the checks below.
|
|
|
|
if (fullRange.begin() == first || fullRange.begin() == first - 1)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Handle \\"
|
|
|
|
if (*(first - 2) == '\\')
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Hanle \"
|
|
|
|
if (*(first - 1) == '\\')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-18 10:16:34 +00:00
|
|
|
|
|
|
|
inline bool IsCPPComment(StringView fullRange, const char* first)
|
|
|
|
{
|
|
|
|
if (*first != '/')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (fullRange.end() == first + 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (*(first + 1) != '/')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2022-08-05 01:01:41 +01:00
|
|
|
}
|