Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
write_buffer.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 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"
25 
26 #include "lib/bits.h" // IsAligned
27 #include "lib/sysdep/cpu.h"
29 #include "lib/file/io/io.h"
30 
31 
32 static const size_t BLOCK_SIZE = 512*KiB;
33 
34 
36  : m_capacity(pageSize), m_data((u8*)rtl_AllocateAligned(m_capacity, maxSectorSize), AlignedDeleter()), m_size(0)
37 {
38 }
39 
40 
42 {
43  if(m_size + size > m_capacity)
44  {
46  shared_ptr<u8> newData;
48  memcpy(newData.get(), m_data.get(), m_size);
49  m_data = newData;
50  }
51 }
52 
53 
54 void WriteBuffer::Append(const void* data, size_t size)
55 {
57  memcpy(m_data.get() + m_size, data, size);
58  m_size += size;
59 }
60 
61 
62 void WriteBuffer::Reserve(size_t size)
63 {
65  memset(m_data.get() + m_size, 0, size);
66  m_size += size;
67 }
68 
69 
70 void WriteBuffer::Overwrite(const void* data, size_t size, size_t offset)
71 {
72  ENSURE(offset+size < m_size);
73  memcpy(m_data.get()+offset, data, size);
74 }
75 
76 
77 //-----------------------------------------------------------------------------
78 // UnalignedWriter
79 //-----------------------------------------------------------------------------
80 
82  : m_file(file), m_alignedBuf((u8*)rtl_AllocateAligned(BLOCK_SIZE, maxSectorSize), AlignedDeleter())
83 {
85  const size_t misalignment = (size_t)(ofs - m_alignedOfs);
86  if(misalignment)
87  {
90  }
91  m_bytesUsed = misalignment;
92 }
93 
94 
96 {
97  Flush();
98 }
99 
100 
101 Status UnalignedWriter::Append(const u8* data, size_t size) const
102 {
103  while(size != 0)
104  {
105  // optimization: write directly from the input buffer, if possible
106  const size_t alignedSize = (size / BLOCK_SIZE) * BLOCK_SIZE;
107  if(m_bytesUsed == 0 && IsAligned(data, maxSectorSize) && alignedSize != 0)
108  {
109  io::Operation op(*m_file.get(), (void*)data, alignedSize, m_alignedOfs);
111  m_alignedOfs += (off_t)alignedSize;
112  data += alignedSize;
113  size -= alignedSize;
114  }
115 
116  const size_t chunkSize = std::min(size, BLOCK_SIZE-m_bytesUsed);
117  memcpy(m_alignedBuf.get()+m_bytesUsed, data, chunkSize);
118  m_bytesUsed += chunkSize;
119  data += chunkSize;
120  size -= chunkSize;
121 
122  if(m_bytesUsed == BLOCK_SIZE)
124  }
125 
126  return INFO::OK;
127 }
128 
129 
131 {
132  if(m_bytesUsed)
133  {
135  (void)WriteBlock();
136  }
137 }
138 
139 
141 {
145  m_bytesUsed = 0;
146  return INFO::OK;
147 }
void * rtl_AllocateAligned(size_t size, size_t align)
Definition: gcc.cpp:66
#define u8
Definition: types.h:39
static const size_t BLOCK_SIZE
static const size_t pageSize
Definition: alignment.h:61
void Append(const void *data, size_t size)
const Status OK
Definition: status.h:386
void Reserve(size_t size)
static const uintptr_t maxSectorSize
Definition: alignment.h:82
void Flush() const
zero-initialize any remaining space in the align buffer and write it to the file. ...
bool IsAligned(T t, uintptr_t multiple)
Definition: alignment.h:8
Status WriteBlock() const
void Overwrite(const void *data, size_t size, size_t offset)
size_t m_size
Definition: write_buffer.h:53
void EnsureSufficientCapacity(size_t size)
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
T round_up_to_pow2(T x)
round up to next larger power of two.
Definition: bits.h:244
shared_ptr< u8 > m_alignedBuf
Definition: write_buffer.h:79
shared_ptr< u8 > m_data
Definition: write_buffer.h:52
shared_ptr< File > PFile
Definition: file.h:99
__int64 off_t
Definition: wposix_types.h:91
UnalignedWriter(const PFile &file, off_t ofs)
static const size_t KiB
Definition: alignment.h:71
T round_down(T n, T multiple)
Definition: bits.h:274
size_t m_bytesUsed
Definition: write_buffer.h:81
i64 Status
Error handling system.
Definition: status.h:171
static Status AllocateAligned(shared_ptr< T > &p, size_t size, size_t alignment=cacheLineSize)
Definition: shared_ptr.h:66
#define THROW_STATUS_IF_ERR(expression)
Definition: status.h:311
Status Append(const u8 *data, size_t size) const
add data to the align buffer, writing it out to disk if full.
size_t m_capacity
Definition: write_buffer.h:50
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276
static Status Run(const Operation &op, const Parameters &p=Parameters(), const CompletedHook &completedHook=CompletedHook(), const IssueHook &issueHook=IssueHook())
Definition: io.h:233