LCOV - code coverage report
Current view: top level - source/lib/file/io - write_buffer.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 15 64 23.4 %
Date: 2022-06-14 00:41:00 Functions: 4 10 40.0 %

          Line data    Source code
       1             : /* Copyright (C) 2018 Wildfire Games.
       2             :  *
       3             :  * Permission is hereby granted, free of charge, to any person obtaining
       4             :  * a copy of this software and associated documentation files (the
       5             :  * "Software"), to deal in the Software without restriction, including
       6             :  * without limitation the rights to use, copy, modify, merge, publish,
       7             :  * distribute, sublicense, and/or sell copies of the Software, and to
       8             :  * permit persons to whom the Software is furnished to do so, subject to
       9             :  * the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included
      12             :  * in all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      15             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      16             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      17             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      18             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      19             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      20             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      21             :  */
      22             : 
      23             : #include "precompiled.h"
      24             : #include "lib/file/io/write_buffer.h"
      25             : 
      26             : #include "lib/bits.h" // IsAligned
      27             : #include "lib/sysdep/cpu.h"
      28             : #include "lib/allocators/shared_ptr.h"
      29             : #include "lib/file/io/io.h"
      30             : 
      31             : 
      32             : static const size_t BLOCK_SIZE = 512*KiB;
      33             : 
      34             : 
      35         116 : WriteBuffer::WriteBuffer()
      36         116 :     : m_capacity(g_PageSize), m_data((u8*)rtl_AllocateAligned(m_capacity, maxSectorSize), AlignedDeleter()), m_size(0)
      37             : {
      38         116 : }
      39             : 
      40             : 
      41        5031 : void WriteBuffer::EnsureSufficientCapacity(size_t size)
      42             : {
      43        5031 :     if(m_size + size > m_capacity)
      44             :     {
      45           0 :         m_capacity = round_up_to_pow2(m_size + size);
      46           0 :         std::shared_ptr<u8> newData;
      47           0 :         AllocateAligned(newData, m_capacity, maxSectorSize);
      48           0 :         memcpy(newData.get(), m_data.get(), m_size);
      49           0 :         m_data = newData;
      50             :     }
      51        5031 : }
      52             : 
      53             : 
      54        5031 : void WriteBuffer::Append(const void* data, size_t size)
      55             : {
      56        5031 :     EnsureSufficientCapacity(size);
      57       10062 :     memcpy(m_data.get() + m_size, data, size);
      58        5031 :     m_size += size;
      59        5031 : }
      60             : 
      61             : 
      62           0 : void WriteBuffer::Reserve(size_t size)
      63             : {
      64           0 :     EnsureSufficientCapacity(size);
      65           0 :     memset(m_data.get() + m_size, 0, size);
      66           0 :     m_size += size;
      67           0 : }
      68             : 
      69             : 
      70        1469 : void WriteBuffer::Overwrite(const void* data, size_t size, size_t offset)
      71             : {
      72        1469 :     ENSURE(offset+size < m_size);
      73        2938 :     memcpy(m_data.get()+offset, data, size);
      74        1469 : }
      75             : 
      76             : 
      77             : //-----------------------------------------------------------------------------
      78             : // UnalignedWriter
      79             : //-----------------------------------------------------------------------------
      80             : 
      81           0 : UnalignedWriter::UnalignedWriter(const PFile& file, off_t ofs)
      82           0 :     : m_file(file), m_alignedBuf((u8*)rtl_AllocateAligned(BLOCK_SIZE, maxSectorSize), AlignedDeleter())
      83             : {
      84           0 :     m_alignedOfs = round_down(ofs, (off_t)BLOCK_SIZE);
      85           0 :     const size_t misalignment = (size_t)(ofs - m_alignedOfs);
      86           0 :     if(misalignment)
      87             :     {
      88           0 :         io::Operation op(*m_file.get(), m_alignedBuf.get(), BLOCK_SIZE, m_alignedOfs);
      89           0 :         THROW_STATUS_IF_ERR(io::Run(op));
      90             :     }
      91           0 :     m_bytesUsed = misalignment;
      92           0 : }
      93             : 
      94             : 
      95           0 : UnalignedWriter::~UnalignedWriter()
      96             : {
      97           0 :     Flush();
      98           0 : }
      99             : 
     100             : 
     101           0 : Status UnalignedWriter::Append(const u8* data, size_t size) const
     102             : {
     103           0 :     while(size != 0)
     104             :     {
     105             :         // optimization: write directly from the input buffer, if possible
     106           0 :         const size_t alignedSize = (size / BLOCK_SIZE) * BLOCK_SIZE;
     107           0 :         if(m_bytesUsed == 0 && IsAligned(data, maxSectorSize) && alignedSize != 0)
     108             :         {
     109           0 :             io::Operation op(*m_file.get(), (void*)data, alignedSize, m_alignedOfs);
     110           0 :             RETURN_STATUS_IF_ERR(io::Run(op));
     111           0 :             m_alignedOfs += (off_t)alignedSize;
     112           0 :             data += alignedSize;
     113           0 :             size -= alignedSize;
     114             :         }
     115             : 
     116           0 :         const size_t chunkSize = std::min(size, BLOCK_SIZE-m_bytesUsed);
     117           0 :         memcpy(m_alignedBuf.get()+m_bytesUsed, data, chunkSize);
     118           0 :         m_bytesUsed += chunkSize;
     119           0 :         data += chunkSize;
     120           0 :         size -= chunkSize;
     121             : 
     122           0 :         if(m_bytesUsed == BLOCK_SIZE)
     123           0 :             RETURN_STATUS_IF_ERR(WriteBlock());
     124             :     }
     125             : 
     126             :     return INFO::OK;
     127             : }
     128             : 
     129             : 
     130           0 : void UnalignedWriter::Flush() const
     131             : {
     132           0 :     if(m_bytesUsed)
     133             :     {
     134           0 :         memset(m_alignedBuf.get()+m_bytesUsed, 0, BLOCK_SIZE-m_bytesUsed);
     135           0 :         (void)WriteBlock();
     136             :     }
     137           0 : }
     138             : 
     139             : 
     140           0 : Status UnalignedWriter::WriteBlock() const
     141             : {
     142           0 :     io::Operation op(*m_file.get(), m_alignedBuf.get(), BLOCK_SIZE, m_alignedOfs);
     143           0 :     RETURN_STATUS_IF_ERR(io::Run(op));
     144           0 :     m_alignedOfs += BLOCK_SIZE;
     145           0 :     m_bytesUsed = 0;
     146           0 :     return INFO::OK;
     147             : }

Generated by: LCOV version 1.13