tdesktop/Telegram/SourceFiles/base/bytes.h

156 lines
3.9 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <gsl/gsl>
#include <gsl/gsl_byte>
namespace bytes {
using type = gsl::byte;
using span = gsl::span<type>;
using const_span = gsl::span<const type>;
using vector = std::vector<type>;
template <gsl::index Size>
using array = std::array<type, Size>;
template <
typename Container,
typename = std::enable_if_t<!std::is_const_v<Container>>>
inline span make_span(Container &container) {
return gsl::as_writeable_bytes(gsl::make_span(container));
}
template <typename Container>
inline const_span make_span(const Container &container) {
return gsl::as_bytes(gsl::make_span(container));
}
template <typename Type, std::ptrdiff_t Extent>
inline span make_span(gsl::span<Type, Extent> container) {
return gsl::as_writeable_bytes(container);
}
template <typename Type, std::ptrdiff_t Extent>
inline const_span make_span(gsl::span<const Type, Extent> container) {
return gsl::as_bytes(container);
}
template <typename Type>
inline span make_span(Type *value, std::size_t count) {
return gsl::as_writeable_bytes(gsl::make_span(value, count));
}
template <typename Type>
inline const_span make_span(const Type *value, std::size_t count) {
return gsl::as_bytes(gsl::make_span(value, count));
}
template <typename Type>
inline span object_as_span(Type *value) {
return bytes::make_span(value, 1);
}
template <typename Type>
inline const_span object_as_span(const Type *value) {
return bytes::make_span(value, 1);
}
template <typename Container>
inline vector make_vector(const Container &container) {
const auto buffer = bytes::make_span(container);
return { buffer.begin(), buffer.end() };
}
inline void copy(span destination, const_span source) {
Expects(destination.size() >= source.size());
memcpy(destination.data(), source.data(), source.size());
}
inline void move(span destination, const_span source) {
Expects(destination.size() >= source.size());
memmove(destination.data(), source.data(), source.size());
}
inline void set_with_const(span destination, type value) {
memset(
destination.data(),
gsl::to_integer<unsigned char>(value),
destination.size());
}
inline int compare(const_span a, const_span b) {
const auto aSize = a.size(), bSize = b.size();
return (aSize > bSize)
? 1
: (aSize < bSize)
? -1
: memcmp(a.data(), b.data(), aSize);
}
namespace details {
template <typename Arg>
std::size_t spansLength(Arg &&arg) {
return bytes::make_span(arg).size();
}
template <typename Arg, typename ...Args>
std::size_t spansLength(Arg &&arg, Args &&...args) {
return bytes::make_span(arg).size() + spansLength(args...);
}
template <typename Arg>
void spansAppend(span destination, Arg &&arg) {
bytes::copy(destination, bytes::make_span(arg));
}
template <typename Arg, typename ...Args>
void spansAppend(span destination, Arg &&arg, Args &&...args) {
const auto data = bytes::make_span(arg);
bytes::copy(destination, data);
spansAppend(destination.subspan(data.size()), args...);
}
} // namespace details
template <
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
vector concatenate(Args &&...args) {
const auto size = details::spansLength(args...);
auto result = vector(size);
details::spansAppend(make_span(result), args...);
return result;
}
template <
typename SpanRange>
vector concatenate(SpanRange args) {
auto size = std::size_t(0);
for (const auto &arg : args) {
size += bytes::make_span(arg).size();
}
auto result = vector(size);
auto buffer = make_span(result);
for (const auto &arg : args) {
const auto part = bytes::make_span(arg);
bytes::copy(buffer, part);
buffer = buffer.subspan(part.size());
}
return result;
}
// Implemented in base/openssl_help.h
void set_random(span destination);
} // namespace bytes