Program Listing for File Scratch.h

↰ Return to documentation for file (ADS/parallel/Scratch.h)

/*--------------------------------------------------------------------------*/
/*----------------------------- File Scratch.h -----------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*----------------------------- DEFINITIONS --------------------------------*/
/*--------------------------------------------------------------------------*/

#ifndef __ADS_Scratch
 #define __ADS_Scratch
                      /* self-identification: #endif constant */

/*--------------------------------------------------------------------------*/
/*------------------------------ INCLUDES ----------------------------------*/
/*--------------------------------------------------------------------------*/

#include "ADS/memory/HugePageAllocator.h"

#include <algorithm>
#include <cstddef>
#include <mutex>
#include <utility>

/*--------------------------------------------------------------------------*/
/*--------------------------- NAMESPACE ------------------------------------*/
/*--------------------------------------------------------------------------*/

namespace ADS::detail {

class ScratchRoom {
 public:

 static std::byte * take( std::size_t b , std::size_t & got ) {
  {
   std::lock_guard< std::mutex > g( slot().lock );
   if( slot().p && ( slot().size >= b ) ) {
    got = slot().size;
    return( std::exchange( slot().p , nullptr ) );
    }
  }
  got = b;
  return( HugePageAllocator< std::byte >().allocate( b ) );
  }

 static void give( std::byte * p , std::size_t b ) {
  std::byte * drop = p;
  std::size_t db = b;
  {
   std::lock_guard< std::mutex > g( slot().lock );
   if( ! slot().p || ( slot().size < b ) ) {
    std::swap( drop , slot().p );
    std::swap( db , slot().size );
    }
  }
  if( drop )
   HugePageAllocator< std::byte >().deallocate( drop , db );
  }

 private:

 struct Slot {
  std::mutex lock;
  std::byte * p = nullptr;
  std::size_t size = 0;
  ~Slot() {
   if( p ) HugePageAllocator< std::byte >().deallocate( p , size );
   }
  };

 static Slot & slot( void ) {
  static Slot s;
  return( s );
  }
 };

template< class T >
class ScratchBuffer {
 public:
 explicit ScratchBuffer( std::size_t n )
  : f_p( reinterpret_cast< T * >( ScratchRoom::take(
                                  std::max< std::size_t >( n , 1 ) *
                                  sizeof( T ) , f_b ) ) ) {}
 ~ScratchBuffer() {
  ScratchRoom::give( reinterpret_cast< std::byte * >( f_p ) , f_b );
  }
 ScratchBuffer( const ScratchBuffer & ) = delete;
 ScratchBuffer & operator=( const ScratchBuffer & ) = delete;
 [[nodiscard]] T * data( void ) const { return( f_p ); }
 private:
 std::size_t f_b = 0;
 T * f_p;
 };

}  // end( namespace ADS::detail )

/*--------------------------------------------------------------------------*/

#endif  /* Scratch.h included */

/*--------------------------------------------------------------------------*/
/*--------------------------- End File Scratch.h ---------------------------*/
/*--------------------------------------------------------------------------*/