1
1
forked from 0ad/0ad
0ad/source/lib/allocators/dynarray.cpp
wraitii 369c2e8801 Further header & precompiled cleanup, fix no-PCH builds.
GUIObjectBase is made a IGUIObject* to avoid including those headers
un-necessarily. Subsequent diffs ought to clean up the various of
pointers for that with a similar type with reference semantics.

Also:
- Add standard C and C++ headers (mostly cstring for memcpy, string and
vector) where needed.
- Swap out some includes for forward declarations
- Clean up un-necessary boost includes in precompiled and other headers.
- Clean up precompiled headers, including fewer things.
- Move ACPI to the windows-specific folder as it's included there only
and mostly specific to that platform.

Thanks Stan for the testing.

Differential Revision: https://code.wildfiregames.com/D3129
This was SVN commit r24352.
2020-12-09 14:39:14 +00:00

148 lines
4.0 KiB
C++

/* Copyright (C) 2020 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* dynamic (expandable) array
*/
#include "precompiled.h"
#include "lib/allocators/dynarray.h"
#include "lib/alignment.h"
#include "lib/sysdep/vm.h"
#include <cstring>
#include <string>
static Status validate_da(DynArray* da)
{
if(!da)
WARN_RETURN(ERR::INVALID_POINTER);
// u8* const base = da->base;
const size_t max_size_pa = da->max_size_pa;
const size_t cur_size = da->cur_size;
const size_t pos = da->pos;
// note: this happens if max_size == 0
// if(debug_IsPointerBogus(base))
// WARN_RETURN(ERR::_1);
// note: don't check if base is page-aligned -
// might not be true for 'wrapped' mem regions.
if(!IsAligned(max_size_pa, g_PageSize))
WARN_RETURN(ERR::_3);
if(cur_size > max_size_pa)
WARN_RETURN(ERR::_4);
if(pos > cur_size || pos > max_size_pa)
WARN_RETURN(ERR::_5);
return INFO::OK;
}
#define CHECK_DA(da) RETURN_STATUS_IF_ERR(validate_da(da))
Status da_alloc(DynArray* da, size_t max_size)
{
ENSURE(max_size != 0);
const size_t max_size_pa = Align<g_PageSize>(max_size);
u8* p = (u8*)vm::ReserveAddressSpace(max_size_pa);
if(!p)
return ERR::NO_MEM; // NOWARN (already done in vm)
da->base = p;
da->max_size_pa = max_size_pa;
da->cur_size = 0;
da->cur_size_pa = 0;
da->pos = 0;
CHECK_DA(da);
return INFO::OK;
}
Status da_free(DynArray* da)
{
CHECK_DA(da);
vm::ReleaseAddressSpace(da->base, da->max_size_pa);
// wipe out the DynArray for safety
memset(da, 0, sizeof(*da));
return INFO::OK;
}
Status da_set_size(DynArray* da, size_t new_size)
{
CHECK_DA(da);
// determine how much to add/remove
const size_t cur_size_pa = Align<g_PageSize>(da->cur_size);
const size_t new_size_pa = Align<g_PageSize>(new_size);
const ssize_t size_delta_pa = (ssize_t)new_size_pa - (ssize_t)cur_size_pa;
// not enough memory to satisfy this expand request: abort.
// note: do not complain - some allocators (e.g. file_cache)
// legitimately use up all available space.
if(new_size_pa > da->max_size_pa)
return ERR::LIMIT; // NOWARN
u8* end = da->base + cur_size_pa;
bool ok = true;
// expanding
if(size_delta_pa > 0)
{
ok = vm::Commit(uintptr_t(end), size_delta_pa);
if(!ok)
debug_printf("Commit failed (%p %lld)\n", (void *)end, (long long)size_delta_pa);
}
// shrinking
else if(size_delta_pa < 0)
ok = vm::Decommit(uintptr_t(end+size_delta_pa), -size_delta_pa);
// else: no change in page count, e.g. if going from size=1 to 2
// (we don't want mem_* to have to handle size=0)
da->cur_size = new_size;
da->cur_size_pa = new_size_pa;
CHECK_DA(da);
return ok? INFO::OK : ERR::FAIL;
}
Status da_reserve(DynArray* da, size_t size)
{
if(da->pos+size > da->cur_size_pa)
RETURN_STATUS_IF_ERR(da_set_size(da, da->cur_size_pa+size));
da->cur_size = std::max(da->cur_size, da->pos+size);
return INFO::OK;
}
Status da_append(DynArray* da, const void* data, size_t size)
{
RETURN_STATUS_IF_ERR(da_reserve(da, size));
memcpy(da->base+da->pos, data, size);
da->pos += size;
return INFO::OK;
}