#ifndef STRSLICE_H
#define STRSLICE_H

#include <string.h>
#include "strbuf.h"

struct strslice {
	size_t len;
	const char *buf;
};

static inline
struct strslice empty_strslice()
{
	struct strslice result = { 0, NULL };
	return result;
}

static inline
struct strslice strslice_from_str(const char *buf)
{
	struct strslice result = { strlen(buf), buf };
	return result;
}

static inline
struct strslice strslice_slice(struct strslice slice, size_t start, size_t len)
{
	struct strslice result;
	if (start >= slice.len)
		len = 0;
	else if (slice.len - start < len)
		len = slice.len - start;
	result.len = len;
	result.buf = len ? slice.buf + start : strbuf_slopbuf;
	return result;
}

static inline struct strslice strbuf_as_slice(const struct strbuf *buf)
{
	struct strslice result = { buf->len, buf->buf };
	return result;
}

static inline struct strslice strbuf_slice(const struct strbuf *buf,
                                           size_t start, size_t len)
{
	return strslice_slice(strbuf_as_slice(buf), start, len);
}

static inline void strbuf_addslice(struct strbuf *buf, struct strslice slice)
{
	strbuf_add(buf, slice.buf, slice.len);
}

static inline size_t strslice_index(struct strslice slice, int c)
{
	const char *needle = memchr(slice.buf, c, slice.len);
	return needle ? needle - slice.buf : SIZE_MAX;
}

static inline size_t strslice_rindex(struct strslice slice, int c)
{
	size_t i;
	for (i = slice.len; i;) {
		if (slice.buf[--i] == c)
			return i;
	}
	return SIZE_MAX;
}

static inline
struct strslice _strslice_split_at(struct strslice *slice, size_t off)
{
	struct strslice result;
	result = strslice_slice(*slice, 0, off == SIZE_MAX ? 0 : off);
	*slice = strslice_slice(*slice, off == SIZE_MAX ? 0 : off + 1,
	                        SIZE_MAX);
	return result;
}

static inline
struct strslice strslice_split_once(struct strslice *slice, int c)
{
	return _strslice_split_at(slice, strslice_index(*slice, c));
}

static inline
struct strslice strslice_rsplit_once(struct strslice *slice, int c)
{
	return _strslice_split_at(slice, strslice_rindex(*slice, c));
}

static inline int strslice_cmp(const struct strslice a,
                               const struct strslice b)
{
	size_t len = a.len < b.len ? a.len : b.len;
	int cmp = memcmp(a.buf, b.buf, len);
	if (cmp)
		return cmp;
	return a.len < b.len ? -1 : a.len != b.len;
}

static inline int strslice_startswith(const struct strslice a,
                                      const struct strslice b)
{
	if (b.len <= a.len) {
		struct strslice prefix = { b.len, a.buf };
		return strslice_cmp(prefix, b) == 0;
	} else {
		return 0;
	}
}

#endif
