]> git.ameliathe1st.gay Git - voyage-au-centre-des-fichiers.git/commitdiff
Plein d'assertions, pour un code plus sûr.
authorAmelia Coutard <eliottulio.coutard@gmail.com>
Fri, 29 Dec 2023 04:46:58 +0000 (05:46 +0100)
committerAmelia Coutard <eliottulio.coutard@gmail.com>
Fri, 29 Dec 2023 04:46:58 +0000 (05:46 +0100)
Makefile
libcpp/allocator.hpp
libcpp/memory.hpp
libcpp/vector.hpp

index 9fe55cf15f513da20cffe838f8918184927e734c..e7a3b3175b56ea272aeb6a9e8a6bc1bf4c2e9fa8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ endif
 
 build: # Build as default target
 
-CXXFLAGS := -std=c++20 -fno-strict-aliasing -Wall -Wextra -pedantic -Werror \
+CXXFLAGS := -std=c++23 -fno-strict-aliasing -Wall -Wextra -pedantic -Werror \
             -mgeneral-regs-only -fno-exceptions -fno-rtti -ffreestanding -O2 \
             -I libcpp $(CXXFLAGS)
 LDFLAGS := $(CXXFLAGS) $(LDFLAGS)
index f3987792b11fdfad1987c5f83be1561b029b7be8..131459ef6fa668b8c2267be682b82d1a730ee61f 100644 (file)
@@ -59,6 +59,12 @@ concept allocator = requires(T allocator) {
        { allocator.deallocate(amy::declval<void*>(), amy::declval<amy::size>(), amy::declval<amy::size>()) } -> amy::same_as<void>;
 };
 
+template <typename T>
+concept knowning_allocator = allocator<T> && requires(T allocator) {
+       // owns(ptr) returns true if, and only if, ptr is a pointer to a memory area allocated by this allocator.
+       // pre: ptr is a pointer to a memory area allocated by **ANY** allocator
+       { allocator.owns(amy::declval<void*>()) } -> amy::same_as<bool>;
+};
 
 // reallocate(allocator, ptr, old_size, new_size, align) tries to resize this memory area, or to create a new one, such that
 // the contents of it, up to the byte min(old_size, new_size), are identical, and the resulting area is aligned to align.
@@ -67,6 +73,11 @@ concept allocator = requires(T allocator) {
 // pre: ptr is a pointer to a memory area of size old_size and alignment align allocated by the allocator allocator.
 // pre: new_size ≥ 1
 void* reallocate(allocator auto& allocator, void* ptr, amy::size old_size, amy::size new_size, amy::size align) {
+       assert(ptr != amy::nil);
+       if constexpr (knowning_allocator<decltype(allocator)>) {
+               assert(allocator.owns(ptr));
+       }
+       assert(new_size >= 1);
        if (allocator.expand(ptr, old_size, new_size - old_size)) {
                return ptr;
        }
@@ -79,23 +90,26 @@ void* reallocate(allocator auto& allocator, void* ptr, amy::size old_size, amy::
        return res;
 }
 
-template <typename T>
-concept knowning_allocator = allocator<T> && requires(T allocator) {
-       // owns(ptr) returns true if, and only if, ptr is a pointer to a memory area allocated by this allocator.
-       // pre: ptr is a pointer to a memory area allocated by **ANY** allocator
-       { allocator.owns(amy::declval<void*>()) } -> amy::same_as<bool>;
-};
-
 template <amy::size data_size, amy::size data_align> struct stack_allocator {
        static_assert(data_size >= 0);
        static_assert(data_align >= 1);
        static_assert((data_align & (data_align - 1)) == 0); // Assert power of 2.
 
-       static constexpr amy::size good_size(amy::size size, amy::size) {
+       static constexpr amy::size good_size(amy::size size, amy::size align) {
+               if ! consteval {
+                       assert(size >= 1);
+                       assert(align >= 1);
+                       assert((align & (align - 1)) == 0);
+                       assert(align <= max_align);
+               }
                return size;
        }
        static constexpr amy::size max_align = data_align;
        void* allocate(amy::size size, amy::size align) {
+               assert(size >= 1);
+               assert(align >= 1);
+               assert((align & (align - 1)) == 0);
+               assert(align <= max_align);
                amy::diff aligned_first_free_byte = (first_free_byte + (align - 1)) / align * align;
                if (aligned_first_free_byte + size > data_size) {
                        return amy::nil;
@@ -104,6 +118,8 @@ template <amy::size data_size, amy::size data_align> struct stack_allocator {
                return &data[aligned_first_free_byte];
        }
        bool expand(void* ptr, amy::size size, amy::diff delta) {
+               assert(owns(ptr));
+               assert(size + delta >= 1);
                if (delta == 0) {
                        return true;
                }
@@ -118,6 +134,7 @@ template <amy::size data_size, amy::size data_align> struct stack_allocator {
                }
        }
        void deallocate(void* ptr, amy::size size, amy::size) {
+               assert(owns(ptr));
                if ((amy::byte*)ptr - data + size == first_free_byte) {
                        first_free_byte = (amy::byte*)ptr - data;
                }
@@ -134,7 +151,6 @@ template <allocator suballocator_t, amy::size min_data_size, amy::size max_data_
 struct freelist {
        static_assert(min_data_size >= 1);
        static_assert(max_data_size >= min_data_size);
-       // static_assert(max_data_size >= amy::byte_size<amy::byte*>()); // Enough room for intrusive list.
        static_assert(min_data_align >= 1);
        static_assert(max_data_align >= min_data_align);
        static_assert((min_data_align & (min_data_align - 1)) == 0); // Assert power of 2.
@@ -150,6 +166,12 @@ private:
 
 public:
        static constexpr amy::size good_size(amy::size size, amy::size align) {
+               if ! consteval {
+                       assert(size >= 1);
+                       assert(align >= 1);
+                       assert((align & (align - 1)) == 0);
+                       assert(align <= max_align);
+               }
                if (size < min_data_size || max_data_size < size || align < min_data_align || max_data_align < align) {
                        return suballocator_t::good_size(size, align);
                }
@@ -157,6 +179,10 @@ public:
        }
        static constexpr amy::size max_align = suballocator_t::max_align;
        void* allocate(amy::size size, amy::size align) {
+               assert(size >= 1);
+               assert(align >= 1);
+               assert((align & (align - 1)) == 0);
+               assert(align <= max_align);
                if (size < min_data_size || max_data_size < size || align < min_data_align || max_data_align < align) {
                        return sub.allocate(size, align);
                }
@@ -170,6 +196,11 @@ public:
                return old_head;
        }
        bool expand(void* ptr, amy::size size, amy::diff delta) {
+               assert(ptr != amy::nil);
+               if constexpr (knowning_allocator<freelist>) {
+                       assert(owns(ptr));
+               }
+               assert(size + delta >= 1);
                if (min_data_size <= size && size <= max_data_size) {
                        delta = (size + delta) - max_data_size;
                        size = max_data_size;
@@ -180,6 +211,10 @@ public:
                return sub.expand(ptr, size, delta);
        }
        void deallocate(void* ptr, amy::size size, amy::size align) {
+               assert(ptr != amy::nil);
+               if constexpr (knowning_allocator<freelist>) {
+                       assert(owns(ptr));
+               }
                if (size < min_data_size || max_data_size < size || align < min_data_align || max_data_align < align) {
                        return sub.deallocate(ptr, size, align);
                }
index f8c3b7eb08512499b5eb20df9583c5bd1f26e043..a0b24973719520ae398783cc4a7dfd805f2ef6d5 100644 (file)
@@ -13,6 +13,7 @@
 
 #pragma once
 
+#include <assert.hpp>
 #include <types.hpp>
 
 // See the C++ documentation for documentation.
@@ -37,10 +38,14 @@ template <typename T>
 
 
 template <typename T> constexpr size byte_size() {
-       return sizeof(T);
+       constexpr size res = sizeof(T);
+       static_assert(res >= 0);
+       return res;
 }
 template <typename T> constexpr size byte_align() {
-       return alignof(T);
+       constexpr size res = alignof(T);
+       static_assert(res >= 0);
+       return res;
 }
 // Implementation based on https://en.cppreference.com/w/cpp/utility/declval
 template <typename T> constexpr T&& declval() noexcept {
@@ -49,12 +54,16 @@ template <typename T> constexpr T&& declval() noexcept {
 
 
 extern "C" inline void* memset(void* dest, int c, amy::size n) {
+       assert(n >= 0);
+       assert(0 <= c && c <= 255);
        while (n-- > 0) {
                reinterpret_cast<amy::byte*>(dest)[n] = amy::byte(c);
        }
        return dest;
 }
 extern "C" inline void* memcpy(void* dest, const void* src, amy::size n) {
+       assert(n >= 0);
+       assert(amy::ptr(dest) + n <= amy::ptr(src) || amy::ptr(src) + n <= amy::ptr(dest));
        while (n-- > 0) {
                reinterpret_cast<amy::byte*>(dest)[n] = reinterpret_cast<const amy::byte*>(src)[n];
        }
index 97cd731a3a54a9348a03098b291689153d9c4ace..84577e6e11a9ea205a92f97ff08cda8c738dbc50 100644 (file)
@@ -58,16 +58,38 @@ public:
                size_ = other.size_;
                capacity_ = other.capacity_;
        }
-       vector& operator=(const vector& other) = delete; // Later, when contracts work. Because allocators must be the same.
-       vector& operator=(vector&& other) = delete;
+       vector& operator=(const vector& other) {
+               assert(&allocator == &other.allocator);
+               vector(other).swap(*this);
+       }
+       vector& operator=(vector&& other) {
+               assert(&allocator == &other.allocator);
+               this->swap(other);
+       }
+
+       void swap(vector& other) {
+               assert(&allocator == &other.allocator);
+               amy::size bak = size_;
+               size_ = other.size_;
+               other.size_ = bak;
+               bak = capacity_;
+               capacity_ = other.capacity_;
+               other.capacity_ = bak;
+               T* bak_ = data;
+               data = other.data;
+               other.data = bak;
+       }
 
        amy::size size() {
+               assert(!construction_failed());
                return size_;
        }
        amy::size capacity() {
+               assert(!construction_failed());
                return capacity_;
        }
        bool push_back(const T& v) {
+               assert(!construction_failed());
                if (size_ == capacity_) {
                        if (allocator.expand(data, capacity_ * amy::byte_size<T>(), amy::byte_size<T>())) {
                                capacity_++;
@@ -83,10 +105,14 @@ public:
                new(&data[size_ - 1]) T(v);
                return true;
        }
-       T& operator[](amy::size i) {
+       T& operator[](amy::diff i) {
+               assert(!construction_failed());
+               assert(0 <= i && i < size_);
                return data[i];
        }
-       const T& operator[](amy::size i) const {
+       const T& operator[](amy::diff i) const {
+               assert(!construction_failed());
+               assert(0 <= i && i < size_);
                return data[i];
        }