Skip to content

Feature: Add a scratch allocator #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 29, 2024
Merged

Conversation

kimkulling
Copy link
Owner

@kimkulling kimkulling commented Oct 29, 2024

  • Add a ScratchAllocator
  • Add documentation for the allocator

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new ScratchAllocator class for dynamic memory management, allowing for efficient one-shot allocations.
    • Added a reset() method to the TPoolAllocator class for improved memory state management.
    • New unit tests for ScratchAllocator to validate creation, allocation, and clearing functionalities.
  • Bug Fixes

    • Corrected documentation formatting and output statements in Common.md for clarity.
  • Documentation

    • Added a comprehensive section on CPPCore::TScratchAllocator in Memory.md, including usage examples.
    • Updated Common.md for improved clarity and consistency in examples.
  • Style

    • Improved code readability through whitespace adjustments in various header files and test classes.

Copy link
Contributor

coderabbitai bot commented Oct 29, 2024

Warning

Rate limit exceeded

@kimkulling has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 18 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Files that changed from the base of the PR and between 2120436 and 40dd2a8.

Walkthrough

The changes in this pull request include the addition of a new test file for the ScratchAllocator, modifications to existing documentation, and minor formatting updates across several header files. A new method has been introduced in the TPoolAllocator class, while the TDefaultAllocator class has a corrected comment. The overall structure and functionality of the affected classes remain intact, with no significant alterations to existing logic or control flows.

Changes

File Change Summary
CMakeLists.txt Added new test source file test/memory/TScratchAllocatorTest.cpp to cppcore_memory_test_src.
doc/Common.md Added whitespace in TBitField example, corrected std::cout syntax, and standardized section headers.
doc/Memory.md Added new section CPPCore::TScratchAllocator with subsections on usage and examples.
include/cppcore/IO/FileSystem.h Formatting and whitespace adjustments around method declarations.
include/cppcore/Memory/TDefaultAllocator.h Corrected comment capitalization from Namespace to namespace.
include/cppcore/Memory/TPoolAllocator.h Added new public method reset() to reset the allocator state.
include/cppcore/Memory/TScratchAllocator.h Introduced new class TScratchAllocator with multiple methods for memory management.
include/cppcore/Memory/TStackAllocator.h Updated clear() and reset() methods to accurately track allocation counts.
test/Random/RandomGeneratorTest.cpp Simplified class declaration by removing empty comment block.
test/memory/TScratchAllocatorTest.cpp Added new test cases CreateTest, AllocTest, and ClearTest for ScratchAllocator.
test/memory/TStackAllocatorTest.cpp Simplified class declaration by removing protected access specifier.

Poem

In the meadow where bunnies play,
New tests and docs brighten the day.
Scratch allocators hop with delight,
Memory managed, all feels just right!
With methods added and comments neat,
Code's a garden, and oh, what a treat! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@kimkulling kimkulling changed the title Feature/add scratchallocator Feature: Add a scratch allocator Oct 29, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (12)
doc/Common.md (3)

Line range hint 41-47: Fix syntax errors in the TBitField example code.

The code example contains several C++ syntax errors that would prevent compilation:

Apply these corrections to make the example valid C++:

    TBitField<uint32_t> bitfield(0);

    // The first bit is set
    bitfield.setBit(1);
-    if (bitfield.getBit(1)) std::cout "First bit is set" << std:endl;
+    if (bitfield.getBit(1)) std::cout << "First bit is set" << std::endl;

    bitfield.clearBit(1);
-    if (!bitfield.getBit(1)) std::cout "First bit is not set" << std:endl;
+    if (!bitfield.getBit(1)) std::cout << "First bit is not set" << std::endl;

56-63: Add documentation for TSharedPtr and Variant sections.

These sections are currently empty but appear to be important utility classes. Since this PR focuses on memory management (adding ScratchAllocator), it would be valuable to properly document these memory-related components, especially TSharedPtr.

Please add:

  • Brief introduction explaining the purpose
  • Common use cases
  • Code examples demonstrating proper usage

Would you like me to help draft the documentation for these sections?


Line range hint 1-63: General documentation improvements needed.

A few minor improvements would enhance the documentation quality:

  1. Fix typos:
    • "USer" → "User"
    • "singe" → "single"
  2. Maintain consistent formatting across code examples (spacing, indentation)
doc/Memory.md (1)

16-18: Fix typos and enhance use cases description.

The current text needs some improvements:

  1. Fix typo: "sove" → "solve"
  2. Add missing comma: "For this, you need..."
  3. Consider adding specific examples of algorithms where this allocator would be beneficial, such as:
    • Temporary data structures in graph algorithms
    • Intermediate buffers in parsing operations
    • Scratch space for sorting algorithms

Apply this diff:

-You need to sove any kind of algorithms. For this you need to work with dynamic allocations, which will be thrown away 
-after finishing your work.
+You need to solve algorithms that require temporary storage. For this, you need to work with dynamic allocations, which will be thrown away 
+after finishing your work. Common examples include graph traversal, parsing operations, and sorting algorithms.
🧰 Tools
🪛 LanguageTool

[typographical] ~17-~17: Use a comma after an introductory phrase.
Context: ...ou need to sove any kind of algorithms. For this you need to work with dynamic allocatio...

(COMMA_INTRODUCTORY_WORDS_PHRASES)

include/cppcore/Memory/TScratchAllocator.h (2)

33-37: Fix documentation typos and enhance class description.

  1. There's a typo in the @param documentation: "apram" should be "param"
  2. The class description could benefit from additional details about:
    • Memory alignment considerations
    • Thread safety guarantees
    • Maximum allocation size limitations

Also applies to: 59-59


135-137: Rename reservedMem() to usedMem() for clarity.

The method name reservedMem() suggests it returns the total reserved memory, but it actually returns the used memory (mIndex). Consider renaming it to better reflect its purpose.

 template<class T>
-size_t TScratchAllocator<T>::reservedMem() const {
+size_t TScratchAllocator<T>::usedMem() const {
     return mIndex;
 }
CMakeLists.txt (2)

Line range hint 58-64: Add TScratchAllocator.h to memory sources.

The new ScratchAllocator's header file needs to be added to the cppcore_memory_src variable.

Apply this diff:

 SET ( cppcore_memory_src
    include/cppcore/Memory/MemUtils.h
    include/cppcore/Memory/TDefaultAllocator.h
    include/cppcore/Memory/TStackAllocator.h
    include/cppcore/Memory/TPoolAllocator.h
+   include/cppcore/Memory/TScratchAllocator.h
    code/Memory/MemUtils.cpp
 )

167-167: Unnecessary empty line change.

This appears to be a formatting-only change and can be reverted.

include/cppcore/Memory/TStackAllocator.h (4)

188-191: Add documentation for the reset() method.

The new reset() method lacks documentation explaining its behavior and how it differs from clear(). Add doxygen-style documentation to clarify:

  • Purpose of the method
  • Difference between reset() and clear()
  • Memory management implications

Add documentation like this:

/// @brief  Resets the allocator state without deallocating memory.
/// @note   Unlike clear(), this method only resets the allocation pointer without
///         freeing memory, allowing for efficient reuse of the allocated buffer.

Line range hint 92-116: Consider adding alignment support for the allocator.

The current implementation doesn't handle alignment requirements of allocated types. This could cause issues with types requiring specific alignment (e.g., SIMD types, certain structs).

Consider:

  1. Adding alignment support in the Header structure
  2. Aligning the allocated memory appropriately

Example approach:

struct Header {
    size_t m_size;
    size_t m_alignment;  // Store alignment requirement
};

// In alloc method:
size_t align_up(size_t n, size_t alignment) {
    return (n + alignment - 1) & ~(alignment - 1);
}

Line range hint 143-150: Guard against potential overflow in reserve().

The size calculation size * sizeof(T) could overflow for large values of size.

Add overflow check:

template <class T>
inline void TStackAllocator<T>::reserve(size_t size) {
+   if (size > std::numeric_limits<size_t>::max() / sizeof(T)) {
+       throw std::overflow_error("Requested size would cause overflow");
+   }
    if (size > (m_capacity)) {
        clear();
        m_capacity = size * sizeof(T);
        m_data = new byte_t[m_capacity];
    }
}

Line range hint 29-36: Enhance class documentation with scratch allocation pattern details.

The class documentation should be expanded to include:

  • Explanation of the scratch allocation pattern
  • Usage examples
  • Memory management strategy (LIFO behavior)
  • Differences between clear() and reset()

Add to the class documentation:

///	@brief  This class implements a simple stack-based allocation scheme.
/// Initially you have to define its size. Each allocation will be done from this initially created
/// pool and must be deallocated in LIFO order. All data will be released when the allocator will
/// be released.
/// 
/// This allocator is particularly useful for scratch/temporary allocations where memory
/// can be efficiently reused. Example usage:
/// 
/// @code
/// TStackAllocator<int> allocator(1024);  // Reserve space for 1024 ints
/// int* temp1 = allocator.alloc(100);     // Allocate space for 100 ints
/// // ... use temp1 ...
/// allocator.release(temp1);              // Release in LIFO order
/// 
/// // Reuse the same memory without deallocation
/// allocator.reset();
/// int* temp2 = allocator.alloc(50);      // Reuse the memory
/// @endcode
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dbdecc6 and bec7e29.

📒 Files selected for processing (11)
  • CMakeLists.txt (2 hunks)
  • doc/Common.md (2 hunks)
  • doc/Memory.md (1 hunks)
  • include/cppcore/IO/FileSystem.h (1 hunks)
  • include/cppcore/Memory/TDefaultAllocator.h (1 hunks)
  • include/cppcore/Memory/TPoolAllocator.h (1 hunks)
  • include/cppcore/Memory/TScratchAllocator.h (1 hunks)
  • include/cppcore/Memory/TStackAllocator.h (1 hunks)
  • test/Random/RandomGeneratorTest.cpp (1 hunks)
  • test/memory/TScratchAllocatorTest.cpp (1 hunks)
  • test/memory/TStackAllocatorTest.cpp (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • include/cppcore/IO/FileSystem.h
  • include/cppcore/Memory/TDefaultAllocator.h
🧰 Additional context used
🪛 LanguageTool
doc/Memory.md

[typographical] ~17-~17: Use a comma after an introductory phrase.
Context: ...ou need to sove any kind of algorithms. For this you need to work with dynamic allocatio...

(COMMA_INTRODUCTORY_WORDS_PHRASES)

🔇 Additional comments (8)
test/memory/TScratchAllocatorTest.cpp (1)

19-28: Verify memory leak detection.

Consider adding memory leak detection to ensure the allocator properly manages memory.

doc/Memory.md (1)

11-14: LGTM!

The introduction clearly explains the purpose and behavior of the scratch allocator.

test/Random/RandomGeneratorTest.cpp (1)

28-28: LGTM! Clean class declaration.

The simplified class declaration without empty comment block is more concise and aligns with modern C++ style guidelines.

test/memory/TStackAllocatorTest.cpp (2)

29-29: LGTM! Good cleanup of empty protected section.

The simplified class declaration maintains the same functionality while removing unnecessary empty protected section. The test fixture is properly set up with Google Test framework.


29-29: Verify consistency with ScratchAllocator implementation.

Since this PR introduces a new ScratchAllocator, let's ensure consistent patterns across allocator implementations.

✅ Verification successful

Let me gather more specific information about the allocator implementations.


No consistency issues found between TStackAllocator and TScratchAllocator

After reviewing both implementations, they are intentionally different by design:

  • TStackAllocator implements a LIFO allocation scheme with explicit release
  • TScratchAllocator is designed for one-shot allocations without individual releases
  • Both allocators maintain consistent memory management patterns within their respective purposes
  • Both implement common interface methods (capacity, reservedMem, freeMem) with consistent behavior
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare allocator implementations for consistency

# Find all allocator implementations
echo "=== Searching for allocator implementations ==="
rg -l "class.*Allocator" --type cpp

# Check allocation method signatures
echo -e "\n=== Checking allocation method signatures ==="
ast-grep --pattern 'class $ALLOCATOR {
  $$$
  $RETURN_TYPE* alloc($$$) {
    $$$
  }
  $$$
}'

# Check release method signatures
echo -e "\n=== Checking release method signatures ==="
ast-grep --pattern 'class $ALLOCATOR {
  $$$
  bool release($$$) {
    $$$
  }
  $$$
}'

Length of output: 954


Script:

#!/bin/bash
# Let's examine the actual allocator implementations more closely

# Check TStackAllocator.h implementation
echo "=== TStackAllocator.h Contents ==="
cat include/cppcore/Memory/TStackAllocator.h

# Check TScratchAllocator.h implementation
echo -e "\n=== TScratchAllocator.h Contents ==="
cat include/cppcore/Memory/TScratchAllocator.h

# Search for allocation patterns
echo -e "\n=== Searching for allocation patterns ==="
rg "alloc\(" include/cppcore/Memory/ -A 2

# Search for deallocation/release patterns
echo -e "\n=== Searching for deallocation patterns ==="
rg "release\(" include/cppcore/Memory/ -A 2

Length of output: 14736

CMakeLists.txt (2)

153-153: LGTM: Test file addition looks good.

The test file is correctly added to the memory test group and follows the existing pattern.


Line range hint 1-186: Verify implementation file for ScratchAllocator.

If the ScratchAllocator has a separate implementation file (*.cpp), it should be added to the source files.

include/cppcore/Memory/TPoolAllocator.h (1)

97-97: ⚠️ Potential issue

The reset() implementation needs improvement.

The current implementation of reset() only sets m_current back to m_first but doesn't properly handle the internal state:

  1. It doesn't reset m_currentIdx in the pools, which could lead to incorrect allocation tracking
  2. The m_freeList state is not addressed, potentially causing memory management issues
  3. Documentation doesn't explain the implications of calling reset()

Consider this improved implementation:

/// @brief  Will reset the allocator to its initial state.
/// @note   This will invalidate all previously allocated memory. Ensure all allocated objects
///         are properly destroyed before calling reset().
/// @thread_safety This method is not thread-safe and should not be called concurrently
///               with other allocator operations.
void reset() {
    if (nullptr == m_first) {
        return;
    }
    // Reset allocation counters
    Pool* current = m_first;
    while (current != nullptr) {
        current->m_currentIdx = 0;
        current = current->m_next;
    }
    // Move all subsequent pools to free list
    if (m_first->m_next != nullptr) {
        if (m_freeList != nullptr) {
            // Find end of current chain
            Pool* last = m_first->m_next;
            while (last->m_next != nullptr) {
                last = last->m_next;
            }
            // Link to existing free list
            last->m_next = m_freeList;
        }
        m_freeList = m_first->m_next;
        m_first->m_next = nullptr;
    }
    m_current = m_first;
}

Let's verify the usage of reset() in tests:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (6)
doc/Memory.md (1)

11-14: Enhance the introduction with more technical details.

Consider adding more specific details about:

  • The memory management model (linear allocation)
  • Thread safety considerations
  • Memory alignment guarantees

Apply this diff to enhance the introduction:

 ## CPPCore::TScratchAllocator
 ### Introduction
-The scratch allocator preallocates a memory block which can be used in your program. You do not have to deallocate any of the allocations. 
-This will be done when clearing the allocator. All allocations will be invalidated.
+The scratch allocator implements a linear allocation model by preallocating a contiguous memory block.
+Individual allocations are performed sequentially without tracking, eliminating the need for explicit
+deallocation. The entire memory block can be reset instantly using the clear() operation, which
+invalidates all previous allocations. Note: This allocator is not thread-safe and does not guarantee
+any specific memory alignment.
test/memory/TScratchAllocatorTest.cpp (1)

23-27: Enhance header includes and namespace usage.

  1. Add <cstddef> for proper size_t type definition
  2. Consider avoiding using namespace directive in header files to prevent potential naming conflicts
 #include <cppcore/Memory/TScratchAllocator.h>
+#include <cstddef>
 
 #include <gtest/gtest.h>
 
-using namespace cppcore;
+// Prefer explicit namespace usage
+using cppcore::ScratchAllocator;
include/cppcore/Memory/TScratchAllocator.h (4)

58-59: Fix typo in parameter documentation.

There's a typo in the @param tag: @apram should be @param.

-    /// @apram[in] size    The pool size to reserve.
+    /// @param[in] size    The pool size to reserve.

33-38: Enhance class documentation.

The documentation should include important details about:

  • Thread safety guarantees
  • Memory ownership model
  • Alignment guarantees
  • Potential exceptions
 /// @brief A simple scratch allocator.
 ///
 /// You can use it to manage all the dynamic allocations without caring about cleaning it up. All
 /// Allocations will be a one-shot alloc, which do not need to get released. When calling clear
-/// all allocation will be invalidated and cannot be used anymore.
+/// all allocations will be invalidated and cannot be used anymore.
+///
+/// @note This allocator is not thread-safe. Access from multiple threads must be externally synchronized.
+/// @note Memory is owned by the allocator and will be automatically freed when the allocator is destroyed.
+/// @note No alignment guarantees are provided for allocated memory.
+/// @throw std::bad_alloc if memory allocation fails

81-83: Document private member variables.

Add documentation for private member variables to improve maintainability.

 private:
+    /// Pointer to the allocated memory block
     T *mBlock;
+    /// Total size of the allocated block in number of elements
     size_t mSize;
+    /// Current allocation index within the block
     size_t mIndex;

92-96: Add noexcept specification and document exceptions.

The constructor that allocates memory should document potential exceptions.

 template<class T>
-inline TScratchAllocator<T>::TScratchAllocator(size_t numItems) :
+inline TScratchAllocator<T>::TScratchAllocator(size_t numItems) noexcept(false) :
         mBlock(nullptr), mSize(numItems), mIndex(0u) {
     reserve(numItems);
 }

Add to the documentation:

     /// @brief  The class constructor with the pool size.
     /// @param[in]  numItems    The buffer size.
+    /// @throw std::bad_alloc if memory allocation fails
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between bec7e29 and e52a80f.

📒 Files selected for processing (3)
  • doc/Memory.md (1 hunks)
  • include/cppcore/Memory/TScratchAllocator.h (1 hunks)
  • test/memory/TScratchAllocatorTest.cpp (1 hunks)
🧰 Additional context used
🪛 LanguageTool
doc/Memory.md

[typographical] ~17-~17: Use a comma after an introductory phrase.
Context: ...ou need to save any kind of algorithms. For this you need to work with dynamic allocatio...

(COMMA_INTRODUCTORY_WORDS_PHRASES)

🔇 Additional comments (3)
doc/Memory.md (1)

20-38: 🛠️ Refactor suggestion

The example code needs comprehensive updates.

The previous review comments about typos in the include path are still valid. Additionally, the example could be more comprehensive.

Beyond the changes suggested in the previous review, consider enhancing the example further:

-#include <Memroy/TScrachtAllocator.h>
+#include <Memory/TScratchAllocator.h>
 
 using namespace ::cppcore;
 
+struct Vector3 { float x, y, z; };
+
 int main() {
-    // Will work
     ScratchAllocator myAllocator(1024);
-    char *ptr1 = myAllocator.alloc(512);
+    
+    // Basic allocation
+    char* ptr1 = myAllocator.alloc(512);
     assert(ptr1 != nullptr);
 
-    // Overrange shall get catched
+    // Allocation of array of objects
+    Vector3* vertices = static_cast<Vector3*>(
+        myAllocator.alloc(10 * sizeof(Vector3)));
+    assert(vertices != nullptr);
+    
+    // Demonstrate out-of-memory handling
     char *ptr2 = myAllocator.alloc(600);
     assert(ptr2 == nullptr);
 
+    // Clear all allocations
+    myAllocator.clear();
+    
+    // After clearing, memory can be reused
+    ptr2 = myAllocator.alloc(600);
+    assert(ptr2 != nullptr);
+
     return 0;
 }
test/memory/TScratchAllocatorTest.cpp (1)

64-65: Verify expected behavior after clear().

The test expects capacity and freeMem to become 0 after clear(), which seems incorrect. The clear operation should typically:

  1. Reset the allocator to its initial state
  2. Maintain the original capacity
  3. Restore all memory as free

Either:

  • The test assertions are incorrect and should expect BufferSize
  • There's a potential bug in ScratchAllocator::clear()
✅ Verification successful

Test assertions are correct, clear() behavior is by design

Looking at the TScratchAllocator implementation, the clear() method is designed to:

  1. Delete the allocated block
  2. Set the block pointer to nullptr
  3. Reset size to 0
  4. Reset index to 0

The test assertions are correct because:

  • capacity() returns mSize which is set to 0 in clear()
  • freeMem() returns mSize - mIndex, which is 0 when mSize is 0

This is a deliberate design choice where clear() completely deallocates the memory and resets the allocator to its initial empty state, rather than just resetting the index. The allocator needs to be explicitly reserve()'d again to be reused.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for ScratchAllocator implementation to verify clear() behavior
ast-grep --pattern 'class ScratchAllocator {
  $$$
  void clear() {
    $$$
  }
  $$$
}'

Length of output: 90


Script:

#!/bin/bash
# Let's try searching for the file containing ScratchAllocator implementation
fd -e h -e hpp -e cpp "ScratchAllocator" --exec cat {}

Length of output: 6977

include/cppcore/Memory/TScratchAllocator.h (1)

144-144: LGTM!

The type alias provides a convenient way to use the allocator with char type.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (3)
include/cppcore/Memory/TScratchAllocator.h (3)

31-39: Enhance class documentation.

The documentation should include important details about:

  • Thread safety guarantees
  • Exception safety guarantees
  • Alignment guarantees for allocations
 /// @brief A simple scratch allocator.
 ///
 /// You can use it to manage all the dynamic allocations without caring about cleaning it up. All
 /// Allocations will be a one-shot alloc, which do not need to get released. When calling clear
-/// all allocation will be invalidated and cannot be used anymore.
+/// all allocation will be invalidated and cannot be used anymore.
+///
+/// @note This allocator is not thread-safe. External synchronization is required for concurrent access.
+/// @note Strong exception guarantee: if an allocation fails, the allocator state remains unchanged.
+/// @note Allocations are aligned according to the alignment requirements of type T.

58-60: Fix typo in parameter documentation.

There's a typo in the @param tag.

     /// @brief  Will reserve the pool.
-    /// @apram[in] size    The pool size to reserve.
+    /// @param[in] size    The pool size to reserve.
     void reserve(size_t size);

158-158: Add documentation for the type alias.

Document the purpose and common use cases for the char-based allocator alias.

+/// @brief Convenience alias for a byte-based scratch allocator.
+/// @details Useful for allocating raw memory blocks or byte buffers.
 using ScratchAllocator = TScratchAllocator<char>;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7889884 and a99d03a.

📒 Files selected for processing (2)
  • doc/Memory.md (1 hunks)
  • include/cppcore/Memory/TScratchAllocator.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • doc/Memory.md
🔇 Additional comments (1)
include/cppcore/Memory/TScratchAllocator.h (1)

128-134: ⚠️ Potential issue

Add error handling in reserve().

The method should maintain the object's invariants if allocation fails.

 template<class T>
-void TScratchAllocator<T>::reserve(size_t size) {
+void TScratchAllocator<T>::reserve(size_t size) noexcept(false) {
+    if (size == 0) {
+        clear();
+        return;
+    }
+    
+    T* newBlock = nullptr;
+    try {
+        newBlock = new T[size];
+    } catch (const std::bad_alloc&) {
+        // Keep existing state unchanged
+        return;
+    }
+    
     clear();
-    mBlock = new T[size];
+    mBlock = newBlock;
     mSize = size;
     mIndex = 0u;
 }

Likely invalid or redundant comment.

@kimkulling kimkulling merged commit 0ed84a8 into master Oct 29, 2024
1 check passed
@kimkulling kimkulling deleted the feature/add_scratchallocator branch October 29, 2024 20:17
Copy link

@coderabbitai coderabbitai bot mentioned this pull request Feb 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants