Fix compiling, use AsyncExecutor instead of AsyncDeleter, fix warnings

This commit is contained in:
Maschell 2020-07-05 13:51:49 +02:00
parent 62c4c726ff
commit 1cffbbf2b8
16 changed files with 238 additions and 243 deletions

View File

@ -61,7 +61,6 @@ LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr
ifneq ($(BUILD),$(notdir $(CURDIR)))
#-------------------------------------------------------------------------------
FILELIST := $(shell bash ./filelist.sh)
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
@ -141,17 +140,22 @@ $(OFILES_SRC) : $(HFILES_BIN)
@echo $(notdir $<)
@$(bin2o)
%.ogg.o %_ogg.h : %.ogg
%.jpg.o %_jpg.h : %.jpg
@echo $(notdir $<)
@$(bin2o)
%.ogg.o %_ogg.h : %.ogg
@echo $(notdir $<)
@$(bin2o)
%.mp3.o %_mp3.h : %.mp3
@echo $(notdir $<)
@$(bin2o)
@$(bin2o)
%.ttf.o %_ttf.h : %.ttf
@echo $(notdir $<)
@$(bin2o)
@$(bin2o)
-include $(DEPENDS)

View File

@ -32,7 +32,7 @@ then
echo "Generating filelist.h for $count files." >&2
cat <<EOF > $outFile
/****************************************************************************
* Loadiine resource files.
* Resource files.
* This file is generated automatically.
* Includes $count files.
*
@ -57,11 +57,10 @@ for i in ${files[@]}
do
filename=${i%.*}
extension=${i##*.}
echo 'extern const unsigned char '$filename'_'$extension'[];' >> $outFile
echo 'extern const unsigned int '$filename'_'$extension'_size;' >> $outFile
echo '' >> $outFile
echo '#include "'$filename'_'$extension'.h"' >> $outFile
done
echo '' >> $outFile
echo 'static RecourceFile RecourceList[] =' >> $outFile
echo '{' >> $outFile

View File

@ -19,14 +19,14 @@
#include <proc_ui/procui.h>
#include <sysapp/launch.h>
#include "Application.h"
#include "gui/FreeTypeGX.h"
#include "gui/VPadController.h"
#include "gui/WPadController.h"
#include <gui/FreeTypeGX.h>
#include <gui/VPadController.h>
#include <gui/WPadController.h>
#include "resources/Resources.h"
#include "gui/sounds/SoundHandler.hpp"
#include <gui/sounds/SoundHandler.hpp>
#include "system/memory.h"
#include "system/AsyncDeleter.h"
#include "utils/logger.h"
#include "utils/AsyncExecutor.h"
Application *Application::applicationInstance = NULL;
bool Application::exitApplication = false;
@ -61,8 +61,8 @@ Application::~Application() {
for (int i = 0; i < 5; i++)
delete controller[i];
AsyncDeleter::destroyInstance();
DEBUG_FUNCTION_LINE("Destroy async deleter");
AsyncExecutor::destroyInstance();
DEBUG_FUNCTION_LINE("Clear resources");
Resources::Clear();
@ -240,11 +240,6 @@ void Application::executeThread(void) {
mainWindow->updateEffects();
video->waitForVSync();
//! transfer elements to real delete list here after all processes are finished
//! the elements are transfered to another list to delete the elements in a separate thread
//! and avoid blocking the GUI thread
AsyncDeleter::triggerDeleteProcess();
}
//! in case we exit to a homebrew let's smoothly fade out

View File

@ -23,7 +23,7 @@
* Constructor for the GuiButton class.
*/
Background::Background(char *picture, float scroll_speed) {
Background::Background(const char *picture, float scroll_speed) {
loc_x = 0.0f;
bgImg = Resources::GetImageData(picture);

View File

@ -27,7 +27,7 @@
//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional)
class Background : public GuiElement {
public:
Background(char *picture, float scroll_speed);
Background(const char *picture, float scroll_speed);
virtual ~Background();

View File

@ -21,7 +21,7 @@
#include "utils/StringTools.h"
#include "utils/logger.h"
#include "resources/Resources.h"
#include "system/AsyncDeleter.h"
#include "utils/AsyncExecutor.h"
MainWindow::MainWindow(int w, int h)
: width(w), height(h) {
@ -184,5 +184,5 @@ void MainWindow::OnOpenEffectFinish(GuiElement *element) {
void MainWindow::OnCloseEffectFinish(GuiElement *element) {
//! remove element from draw list and push to delete queue
remove(element);
AsyncDeleter::pushForDelete(element);
AsyncExecutor::pushForDelete(element);
}

View File

@ -1,44 +1,52 @@
#include <malloc.h>
#include <string.h>
#include <string>
#include "Resources.h"
#include "filelist.h"
#include "system/AsyncDeleter.h"
#include <gui/GuiSound.h>
#include <gui/GuiImageData.h>
#include "fs/FSUtils.h"
#include "gui/GuiImageAsync.h"
#include "gui/GuiSound.h"
#include "utils/AsyncExecutor.h"
Resources *Resources::instance = NULL;
#include <chrono>
#include <future>
#include <iostream>
#include <thread>
#include <strings.h>
Resources * Resources::instance = NULL;
void Resources::Clear() {
for (int i = 0; RecourceList[i].filename != NULL; ++i) {
if (RecourceList[i].CustomFile) {
for(int32_t i = 0; RecourceList[i].filename != NULL; ++i) {
if(RecourceList[i].CustomFile) {
free(RecourceList[i].CustomFile);
RecourceList[i].CustomFile = NULL;
}
if (RecourceList[i].CustomFileSize != 0)
if(RecourceList[i].CustomFileSize != 0)
RecourceList[i].CustomFileSize = 0;
}
if (instance)
if(instance)
delete instance;
instance = NULL;
}
bool Resources::LoadFiles(const char *path) {
if (!path)
bool Resources::LoadFiles(const char * path) {
if(!path)
return false;
bool result = false;
Clear();
for (int i = 0; RecourceList[i].filename != NULL; ++i) {
for(int32_t i = 0; RecourceList[i].filename != NULL; ++i) {
std::string fullpath(path);
fullpath += "/";
fullpath += RecourceList[i].filename;
uint8_t *buffer = NULL;
uint8_t * buffer = NULL;
uint32_t filesize = 0;
FSUtils::LoadFileToMem(fullpath.c_str(), &buffer, &filesize);
@ -51,9 +59,9 @@ bool Resources::LoadFiles(const char *path) {
return result;
}
const uint8_t *Resources::GetFile(const char *filename) {
for (int i = 0; RecourceList[i].filename != NULL; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t * Resources::GetFile(const char * filename) {
for(int32_t i = 0; RecourceList[i].filename != NULL; ++i) {
if(strcasecmp(filename, RecourceList[i].filename) == 0) {
return (RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile);
}
}
@ -61,34 +69,34 @@ const uint8_t *Resources::GetFile(const char *filename) {
return NULL;
}
uint32_t Resources::GetFileSize(const char *filename) {
for (int i = 0; RecourceList[i].filename != NULL; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
uint32_t Resources::GetFileSize(const char * filename) {
for(int32_t i = 0; RecourceList[i].filename != NULL; ++i) {
if(strcasecmp(filename, RecourceList[i].filename) == 0) {
return (RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize);
}
}
return 0;
}
GuiImageData *Resources::GetImageData(const char *filename) {
if (!instance)
GuiImageData * Resources::GetImageData(const char * filename) {
if(!instance)
instance = new Resources;
std::map<std::string, std::pair<unsigned int, GuiImageData *> >::iterator itr = instance->imageDataMap.find(std::string(filename));
if (itr != instance->imageDataMap.end()) {
std::map<std::string, std::pair<uint32_t, GuiImageData *> >::iterator itr = instance->imageDataMap.find(std::string(filename));
if(itr != instance->imageDataMap.end()) {
itr->second.first++;
return itr->second.second;
}
for (int i = 0; RecourceList[i].filename != NULL; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t *buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile;
for(int32_t i = 0; RecourceList[i].filename != NULL; ++i) {
if(strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t * buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile;
const uint32_t size = RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize;
if (buff == NULL)
if(buff == NULL)
return NULL;
GuiImageData *image = new GuiImageData(buff, size);
GuiImageData * image = new GuiImageData(buff, size);
instance->imageDataMap[std::string(filename)].first = 1;
instance->imageDataMap[std::string(filename)].second = image;
@ -99,15 +107,16 @@ GuiImageData *Resources::GetImageData(const char *filename) {
return NULL;
}
void Resources::RemoveImageData(GuiImageData *image) {
std::map<std::string, std::pair<unsigned int, GuiImageData *> >::iterator itr;
void Resources::RemoveImageData(GuiImageData * image) {
std::map<std::string, std::pair<uint32_t, GuiImageData *> >::iterator itr;
for (itr = instance->imageDataMap.begin(); itr != instance->imageDataMap.end(); itr++) {
if (itr->second.second == image) {
for(itr = instance->imageDataMap.begin(); itr != instance->imageDataMap.end(); itr++) {
if(itr->second.second == image) {
itr->second.first--;
if (itr->second.first == 0) {
AsyncDeleter::pushForDelete(itr->second.second);
if(itr->second.first == 0) {
AsyncExecutor::pushForDelete(itr->second.second);
instance->imageDataMap.erase(itr);
}
break;
@ -115,25 +124,25 @@ void Resources::RemoveImageData(GuiImageData *image) {
}
}
GuiSound *Resources::GetSound(const char *filename) {
if (!instance)
GuiSound * Resources::GetSound(const char * filename) {
if(!instance)
instance = new Resources;
std::map<std::string, std::pair<unsigned int, GuiSound *> >::iterator itr = instance->soundDataMap.find(std::string(filename));
if (itr != instance->soundDataMap.end()) {
std::map<std::string, std::pair<uint32_t, GuiSound *> >::iterator itr = instance->soundDataMap.find(std::string(filename));
if(itr != instance->soundDataMap.end()) {
itr->second.first++;
return itr->second.second;
}
for (int i = 0; RecourceList[i].filename != NULL; ++i) {
if (strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t *buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile;
for(int32_t i = 0; RecourceList[i].filename != NULL; ++i) {
if(strcasecmp(filename, RecourceList[i].filename) == 0) {
const uint8_t * buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile;
const uint32_t size = RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize;
if (buff == NULL)
if(buff == NULL)
return NULL;
GuiSound *sound = new GuiSound(buff, size);
GuiSound * sound = new GuiSound(buff, size);
instance->soundDataMap[std::string(filename)].first = 1;
instance->soundDataMap[std::string(filename)].second = sound;
@ -144,15 +153,15 @@ GuiSound *Resources::GetSound(const char *filename) {
return NULL;
}
void Resources::RemoveSound(GuiSound *sound) {
std::map<std::string, std::pair<unsigned int, GuiSound *> >::iterator itr;
void Resources::RemoveSound(GuiSound * sound) {
std::map<std::string, std::pair<uint32_t, GuiSound *> >::iterator itr;
for (itr = instance->soundDataMap.begin(); itr != instance->soundDataMap.end(); itr++) {
if (itr->second.second == sound) {
for(itr = instance->soundDataMap.begin(); itr != instance->soundDataMap.end(); itr++) {
if(itr->second.second == sound) {
itr->second.first--;
if (itr->second.first == 0) {
AsyncDeleter::pushForDelete(itr->second.second);
if(itr->second.first == 0) {
AsyncExecutor::pushForDelete(itr->second.second);
instance->soundDataMap.erase(itr);
}
break;

View File

@ -1,40 +1,30 @@
#ifndef RECOURCES_H_
#define RECOURCES_H_
#pragma once
#include <map>
#include <stdint.h>
//! forward declaration
class GuiImageData;
class GuiSound;
class Resources {
public:
static void Clear();
static bool LoadFiles(const char * path);
static const uint8_t * GetFile(const char * filename);
static uint32_t GetFileSize(const char * filename);
static bool LoadFiles(const char *path);
static const uint8_t *GetFile(const char *filename);
static uint32_t GetFileSize(const char *filename);
static GuiImageData *GetImageData(const char *filename);
static void RemoveImageData(GuiImageData *image);
static GuiSound *GetSound(const char *filename);
static void RemoveSound(GuiSound *sound);
static GuiImageData * GetImageData(const char * filename);
static void RemoveImageData(GuiImageData * image);
static GuiSound * GetSound(const char * filename);
static void RemoveSound(GuiSound * sound);
private:
static Resources *instance;
Resources() {}
~Resources() {}
std::map<std::string, std::pair<unsigned int, GuiImageData *> > imageDataMap;
std::map<std::string, std::pair<unsigned int, GuiSound *> > soundDataMap;
};
#endif
std::map<std::string, std::pair<uint32_t, GuiImageData *> > imageDataMap;
std::map<std::string, std::pair<uint32_t, GuiSound *> > soundDataMap;
};

View File

@ -1,62 +0,0 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "AsyncDeleter.h"
AsyncDeleter *AsyncDeleter::deleterInstance = NULL;
AsyncDeleter::AsyncDeleter()
: CThread(CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff), exitApplication(false) {
}
AsyncDeleter::~AsyncDeleter() {
exitApplication = true;
}
void AsyncDeleter::triggerDeleteProcess(void) {
if (!deleterInstance)
deleterInstance = new AsyncDeleter;
//! to trigger the event after GUI process is finished execution
//! this function is used to swap elements from one to next array
if (!deleterInstance->deleteElements.empty()) {
deleterInstance->deleteMutex.lock();
while (!deleterInstance->deleteElements.empty()) {
deleterInstance->realDeleteElements.push(deleterInstance->deleteElements.front());
deleterInstance->deleteElements.pop();
}
deleterInstance->deleteMutex.unlock();
deleterInstance->resumeThread();
}
}
void AsyncDeleter::executeThread(void) {
while (!exitApplication) {
suspendThread();
//! delete elements that require post process deleting
//! because otherwise they would block or do invalid access on GUI thread
while (!realDeleteElements.empty()) {
deleteMutex.lock();
GuiElement *element = realDeleteElements.front();
realDeleteElements.pop();
deleteMutex.unlock();
delete element;
}
}
}

View File

@ -1,63 +0,0 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _ASYNC_DELETER_H
#define _ASYNC_DELETER_H
#include <queue>
#include <gui/gui.h>
#include "CThread.h"
#include "CMutex.h"
class AsyncDeleter : public CThread {
public:
static void destroyInstance() {
delete deleterInstance;
deleterInstance = NULL;
}
class Element {
public:
Element() {}
virtual ~Element() {}
};
static void pushForDelete(GuiElement *e) {
if (!deleterInstance)
deleterInstance = new AsyncDeleter;
deleterInstance->deleteElements.push(e);
}
static void triggerDeleteProcess(void);
private:
AsyncDeleter();
virtual ~AsyncDeleter();
static AsyncDeleter *deleterInstance;
void executeThread(void);
bool exitApplication;
std::queue<GuiElement *> deleteElements;
std::queue<GuiElement *> realDeleteElements;
CMutex deleteMutex;
};
#endif // _ASYNC_DELETER_H

View File

@ -0,0 +1,59 @@
#include "AsyncExecutor.h"
#include "utils/logger.h"
AsyncExecutor *AsyncExecutor::instance = NULL;
void AsyncExecutor::pushForDeleteInternal(GuiElement *ptr) {
deleteListMutex.lock();
deleteList.push(ptr);
deleteListMutex.unlock();
}
AsyncExecutor::AsyncExecutor() {
thread = new std::thread([&]() {
while (!exitThread) {
mutex.lock();
bool emptyList = elements.empty();
auto it = elements.begin();
while (it != elements.end()) {
auto future = it;
auto status = future->wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
it = elements.erase(it);
} else {
++it;
}
}
if (!emptyList && elements.empty()) {
DEBUG_FUNCTION_LINE("All tasks are done");
}
mutex.unlock();
deleteListMutex.lock();
while (!deleteList.empty()) {
GuiElement *ptr = deleteList.front();
deleteList.pop();
delete ptr;
}
deleteListMutex.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(16));
DCFlushRange((void *) &exitThread, sizeof(exitThread));
}
});
}
AsyncExecutor::~AsyncExecutor() {
exitThread = true;
DCFlushRange((void *) &exitThread, sizeof(exitThread));
thread->join();
}
void AsyncExecutor::executeInternal(std::function<void()> func) {
if (elements.size() > 10) {
DEBUG_FUNCTION_LINE("Warning, many tasks running currently");
//std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
mutex.lock();
elements.push_back(std::async(std::launch::async, func));
mutex.unlock();
}

53
src/utils/AsyncExecutor.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <vector>
#include <future>
#include <thread>
#include <queue>
#include <gui/GuiElement.h>
#include <coreinit/cache.h>
#include "utils/logger.h"
class AsyncExecutor {
public:
static void pushForDelete(GuiElement *element) {
if (!instance) {
instance = new AsyncExecutor();
}
instance->pushForDeleteInternal(element);
}
static void execute(std::function<void()> func) {
if (!instance) {
instance = new AsyncExecutor();
}
instance->executeInternal(func);
}
static void destroyInstance() {
if (instance) {
delete instance;
instance = NULL;
}
}
private:
static AsyncExecutor *instance;
AsyncExecutor();
~AsyncExecutor();
void pushForDeleteInternal(GuiElement *element);
void executeInternal(std::function<void()> func);
std::recursive_mutex mutex;
std::thread *thread;
volatile bool exitThread = false;
std::vector<std::future<void>> elements;
std::recursive_mutex deleteListMutex;
std::queue<GuiElement *> deleteList;
};

View File

@ -37,7 +37,8 @@
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
if (b.size() > a.size()) return false;
if (b.size() > a.size())
return false;
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
}
@ -95,7 +96,7 @@ const wchar_t *StringTools::wfmt(const char *format, ...) {
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
int bt;
int32_t bt;
int32_t strlength = strlen(tmp);
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
@ -144,7 +145,7 @@ BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
if (!strChar || !dest)
return false;
int bt;
int32_t bt;
bt = mbstowcs(dest, strChar, strlen(strChar));
if (bt > 0) {
dest[bt] = 0;
@ -208,3 +209,12 @@ std::vector<std::string> StringTools::stringSplit(const std::string &inValue, co
}
return result;
}
bool StringTools::findStringIC(const std::string &strHaystack, const std::string &strNeedle) {
auto it = std::search(
strHaystack.begin(), strHaystack.end(),
strNeedle.begin(), strNeedle.end(),
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
);
return (it != strHaystack.end());
}

View File

@ -23,12 +23,13 @@
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef __STRING_TOOLS_H
#define __STRING_TOOLS_H
#pragma once
#include <vector>
#include <string>
#include <wut_types.h>
#include <algorithm>
#include <cctype>
class StringTools {
public:
@ -53,7 +54,8 @@ public:
static int32_t strextcmp(const char *string, const char *extension, char seperator);
static const char *FullpathToFilename(const char *path) {
if (!path) return path;
if (!path)
return path;
const char *ptr = path;
const char *Filename = ptr;
@ -82,7 +84,7 @@ public:
}
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
// https://stackoverflow.com/a/19839371
static bool findStringIC(const std::string &strHaystack, const std::string &strNeedle);
};
#endif /* __STRING_TOOLS_H */

View File

@ -1,10 +1,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <malloc.h>
#include <utils/logger.h>
#include <whb/log.h>
#include "utils/logger.h"
// https://gist.github.com/ccbrown/9722406
void dumpHex(const void *data, size_t size) {
@ -13,28 +10,28 @@ void dumpHex(const void *data, size_t size) {
ascii[16] = '\0';
DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
log_printf("%02X ", ((unsigned char *) data)[i]);
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *) data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i + 1) % 8 == 0 || i + 1 == size) {
log_printf(" ");
WHBLogWritef(" ");
if ((i + 1) % 16 == 0) {
log_printf("| %s \n", ascii);
WHBLogPrintf("| %s ", ascii);
if (i + 1 < size) {
DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", data + i + 1, i + 1);
}
} else if (i + 1 == size) {
ascii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8) {
log_printf(" ");
WHBLogWritef(" ");
}
for (j = (i + 1) % 16; j < 16; ++j) {
log_printf(" ");
WHBLogWritef(" ");
}
log_printf("| %s \n", ascii);
WHBLogPrintf("| %s ", ascii);
}
}
}

View File

@ -1,5 +1,4 @@
#ifndef __UTILS_H_
#define __UTILS_H_
#pragma once
#include <malloc.h>
@ -21,6 +20,11 @@ extern "C" {
#define ALIGN4(x) (((x) + 3) & ~3)
#define ALIGN32(x) (((x) + 31) & ~31)
// those work only in powers of 2
#define ROUNDDOWN(val, align) ((val) & ~(align-1))
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align-1)), align)
#define le16(i) ((((uint16_t) ((i) & 0xFF)) << 8) | ((uint16_t) (((i) & 0xFF00) >> 8)))
#define le32(i) ((((uint32_t)le16((i) & 0xFFFF)) << 16) | ((uint32_t)le16(((i) & 0xFFFF0000) >> 16)))
#define le64(i) ((((uint64_t)le32((i) & 0xFFFFFFFFLL)) << 32) | ((uint64_t)le32(((i) & 0xFFFFFFFF00000000LL) >> 32)))
@ -30,6 +34,4 @@ void dumpHex(const void *data, size_t size);
#ifdef __cplusplus
}
#endif
#endif // __UTILS_H_
#endif