106 lines
3.3 KiB
C++
106 lines
3.3 KiB
C++
// Copyright 2021 DeepMind Technologies Limited
|
|
//
|
|
// 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
|
|
//
|
|
// http://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.
|
|
|
|
#ifndef MUJOCO_SAMPLE_ARRAY_SAFETY_H_
|
|
#define MUJOCO_SAMPLE_ARRAY_SAFETY_H_
|
|
|
|
#include <algorithm>
|
|
#include <cstdarg>
|
|
#include <cstddef>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
// Provides safe alternatives to the sizeof() operator and standard library functions for handling
|
|
// null-terminated (C-style) strings in raw char arrays.
|
|
//
|
|
// These functions make use of compile-time array sizes to limit read and write operations to within
|
|
// the array bounds. They are designed to trigger a compile error if the array size cannot be
|
|
// determined at compile time (e.g. when an array has decayed into a pointer).
|
|
//
|
|
// They do not perform runtime bound checks.
|
|
|
|
namespace mujoco {
|
|
namespace sample_util {
|
|
|
|
// returns sizeof(arr)
|
|
// use instead of sizeof() to avoid unintended array-to-pointer decay
|
|
template <typename T, int N>
|
|
static constexpr std::size_t sizeof_arr(const T(&arr)[N]) {
|
|
return sizeof(arr);
|
|
}
|
|
|
|
// like std::strcmp but it will not read beyond the bound of either lhs or rhs
|
|
template <std::size_t N1, std::size_t N2>
|
|
static inline int strcmp_arr(const char (&lhs)[N1], const char (&rhs)[N2]) {
|
|
return std::strncmp(lhs, rhs, std::min(N1, N2));
|
|
}
|
|
|
|
// like std::strlen but it will not read beyond the bound of str
|
|
// if str is not null-terminated, returns sizeof(str)
|
|
template <std::size_t N>
|
|
static inline std::size_t strlen_arr(const char (&str)[N]) {
|
|
for (std::size_t i = 0; i < N; ++i) {
|
|
if (str[i] == '\0') {
|
|
return i;
|
|
}
|
|
}
|
|
return N;
|
|
}
|
|
|
|
// like std::sprintf but will not write beyond the bound of dest
|
|
// dest is guaranteed to be null-terminated
|
|
template <std::size_t N>
|
|
static inline int sprintf_arr(char (&dest)[N], const char* format, ...) {
|
|
std::va_list vargs;
|
|
va_start(vargs, format);
|
|
int retval = std::vsnprintf(dest, N, format, vargs);
|
|
va_end(vargs);
|
|
return retval;
|
|
}
|
|
|
|
// like std::strcat but will not write beyond the bound of dest
|
|
// dest is guaranteed to be null-terminated
|
|
template <std::size_t N>
|
|
static inline char* strcat_arr(char (&dest)[N], const char* src) {
|
|
const std::size_t dest_len = strlen_arr(dest);
|
|
const std::size_t dest_size = sizeof_arr(dest);
|
|
for (std::size_t i = dest_len; i < dest_size; ++i) {
|
|
dest[i] = src[i - dest_len];
|
|
if (!dest[i]) {
|
|
break;
|
|
}
|
|
}
|
|
dest[dest_size - 1] = '\0';
|
|
return dest;
|
|
}
|
|
|
|
// like std::strcpy but won't write beyond the bound of dest
|
|
// dest is guaranteed to be null-terminated
|
|
template <std::size_t N>
|
|
static inline char* strcpy_arr(char (&dest)[N], const char* src) {
|
|
{
|
|
std::size_t i = 0;
|
|
for (; src[i] && i < N - 1; ++i) {
|
|
dest[i] = src[i];
|
|
}
|
|
dest[i] = '\0';
|
|
}
|
|
return &dest[0];
|
|
}
|
|
|
|
} // namespace sample_util
|
|
} // namespace mujoco
|
|
|
|
#endif // MUJOCO_SAMPLE_ARRAY_SAFETY_H_
|