blob: 577bc61578cbb228b97982d9eb61fb50ec9b8866 [file] [log] [blame]
/*
* Copyright 2018 The Hafnium Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hf/memiter.h"
#include "hf/check.h"
#include "hf/dlog.h"
#include "hf/std.h"
/**
* Initialises the given memory iterator.
*/
void memiter_init(struct memiter *it, const void *data, size_t size)
{
it->next = data;
it->limit = it->next + size;
}
/**
* Determines if the next character is a whitespace.
*/
static bool memiter_isspace(struct memiter *it)
{
switch (*it->next) {
case ' ':
case '\t':
case '\n':
case '\r':
return true;
default:
return false;
}
}
/**
* Moves iterator to the next non-whitespace character.
*/
static void memiter_skip_space(struct memiter *it)
{
while (it->next < it->limit && memiter_isspace(it)) {
it->next++;
}
}
/**
* Compares the iterator to a null-terminated string.
*/
bool memiter_iseq(const struct memiter *it, const char *str)
{
size_t it_len = it->limit - it->next;
size_t len = strnlen_s(str, it_len + 1);
if (len != it_len) {
return false;
}
return memcmp(it->next, str, len) == 0;
}
/**
* Retrieves the next string that is delimited by whitespaces. The result is
* stored in "str".
*/
bool memiter_parse_str(struct memiter *it, struct memiter *str)
{
/* Skip all white space and fail if we reach the end of the buffer. */
memiter_skip_space(it);
if (it->next >= it->limit) {
return false;
}
str->next = it->next;
/* Find the end of the string. */
while (it->next < it->limit && !memiter_isspace(it)) {
it->next++;
}
str->limit = it->next;
return true;
}
/**
* Parses the next string that represents a 64-bit number.
*/
bool memiter_parse_uint(struct memiter *it, uint64_t *value)
{
uint64_t v = 0;
/* Skip all white space and fail if we reach the end of the buffer. */
memiter_skip_space(it);
if (it->next >= it->limit) {
return false;
}
/* Fail if it's not a number. */
if (*it->next < '0' || *it->next > '9') {
return false;
}
/* Parse the number. */
do {
v = v * 10 + *it->next - '0';
it->next++;
} while (it->next < it->limit && *it->next >= '0' && *it->next <= '9');
*value = v;
return true;
}
/**
* Advances the iterator by the given number of bytes. Returns true if the
* iterator was advanced without going over its limit; returns false and leaves
* the iterator unmodified otherwise.
*/
bool memiter_advance(struct memiter *it, size_t v)
{
const char *p = it->next + v;
if (p < it->next || p > it->limit) {
return false;
}
it->next = p;
return true;
}
/**
* Decrements the limit of iterator by the given number of bytes. Returns true
* if the limit was reduced without going over the base; returns false and
* leaves the iterator unmodified otherwise.
*/
bool memiter_restrict(struct memiter *it, size_t v)
{
size_t s = memiter_size(it);
if (v > s) {
return false;
}
it->limit = it->next + (s - v);
return true;
}
/**
* Initializes `newit` with the first `v` bytes of `it` and advances `it` by
* the same number of bytes. This splits the original range into two iterators
* after `v` bytes.
* Returns true on success; returns false and leaves `it` unmodified and `newit`
* uninitialized otherwise.
*/
bool memiter_consume(struct memiter *it, size_t v, struct memiter *newit)
{
if (v > memiter_size(it)) {
return false;
}
memiter_init(newit, memiter_base(it), v);
CHECK(memiter_advance(it, v));
return true;
}
const void *memiter_base(const struct memiter *it)
{
return (const void *)it->next;
}
/**
* Returns the number of bytes in interval [it.next, it.limit).
*/
size_t memiter_size(const struct memiter *it)
{
return it->limit - it->next;
}