venerdì 31 agosto 2007

No OOXML, no piccolo&moscio

Intanto subito subito una visita al sito: http://www.noooxml.org/.
E ora la mia critica: supponiamo che io voglia scrivere del software in grado di interagire con documenti salvati in formato ODF: è uno standard aperto e mi garantisce la compatibilità con tutti i sistemi SERI. Perchè mai dovrei scrivere anche il "codec" per la lettura dei documenti ooxml? Ma chi me lo fa fare di spendere il doppio di tempo (soldi)?
Uno standard c'è già, e funziona.
VOTATE LA PETIZIONE CONTRO M$, NON FATEMI LAVORARE IL DOPPIO!

mercoledì 29 agosto 2007

Memory manager errata corrige

E' inutile... non riesco a far visualizzare correttamente i parametri dei template...
Se a qualcuno interessa il codice giusto, mandatemi una mail che ve lo spedisco!

MemoryManager.cpp

#include "MemoryManager.h"

namespace ManagedMemory
{
using namespace std;

MemoryManagerImpl::MemoryManagerImpl(void *p, size_t heapSize):
_heapSize(heapSize),
_heap(p)
{
_freeBlocks.push_front(MemBlock(_heap, _heapSize));
}

MemoryManagerImpl::~MemoryManagerImpl(void)
{
}

void * MemoryManagerImpl::alloc(size_t amount) throw(MemoryAllocationException)
{
for(list::iterator it = _freeBlocks.begin(); it != _freeBlocks.end(); it++)
{
if(it->_size >= amount)
{
void *memPointer = it->_pointer;
size_t memResidua = it->_size - amount;
_freeBlocks.erase(it);
_usedBlocks.push_back(MemBlock(memPointer, amount));
if(memResidua > 0)
_freeBlocks.push_back(
MemBlock(reinterpret_cast(
reinterpret_cast(memPointer)+amount),
memResidua));
return memPointer;
}
}
return 0;
}

void MemoryManagerImpl::free(void *p) throw(NotOwnedMemoryException, DeallocOnNotAllocatedMemory)
{
if(
( reinterpret_cast(p) <>(_heap)) ||
( reinterpret_cast(p) >= (reinterpret_cast(_heap) + _heapSize))
) throw NotOwnedMemoryException();

for(list::iterator it = _usedBlocks.begin(); it != _usedBlocks.end(); it++)
{
if(it->_pointer == p)
{
_freeBlocks.push_back(*it);
defrag();
_usedBlocks.erase(it);
return;
}
}
throw DeallocOnNotAllocatedMemory();
}

void MemoryManagerImpl::defrag()
{
if(_freeBlocks.size() < 2) return;
_freeBlocks.sort();
list::iterator it1 = _freeBlocks.begin();
list::iterator it2 = _freeBlocks.begin();
it2++;

while(it2 != _freeBlocks.end())
{
if(
(reinterpret_cast(it1->_pointer) +
it1->_size) == (reinterpret_cast(it2->_pointer)))
{
// Unisco e libero
_freeBlocks.push_back(MemBlock(it1->_pointer, it1->_size + it2->_size));
_freeBlocks.erase(it2);
_freeBlocks.erase(it1);

// Ricomincio
if(_freeBlocks.size() < 2) return;
_freeBlocks.sort();
it1 = _freeBlocks.begin();
it2 = _freeBlocks.begin();
it2++;
}
else
{
it1++;
it2++;
}
}
}
};

MemoryManager.h

#pragma once
#pragma warning( disable : 4290 )

#include
#include "MemoryExceptions.h"

namespace ManagedMemory
{
struct MemBlock
{
void *_pointer;
size_t _size;

MemBlock(void *pointer, size_t size):
_pointer(pointer), _size(size)
{}

bool operator< (const MemBlock& b) const
{
return
reinterpret_cast(_pointer) <
reinterpret_cast(b._pointer);
}
};

/**
Interfaccia per gestore di memoria
*/
class MemoryManager
{
public:
virtual void *alloc(size_t amount) throw(MemoryAllocationException) = 0;
virtual void free(void *p) throw(NotOwnedMemoryException) = 0;
};

class MemoryManagerImpl: public MemoryManager
{
void *_heap;
size_t _heapSize;

std::list _usedBlocks;
std::list _freeBlocks;

protected:
void defrag();

public:
MemoryManagerImpl(void *p, size_t heapSize);
virtual ~MemoryManagerImpl(void);

virtual void *alloc(size_t amount) throw(MemoryAllocationException);
virtual void free(void *p) throw(NotOwnedMemoryException, DeallocOnNotAllocatedMemory);

};
};

MemoryExceptions.h

#pragma once

namespace ManagedMemory
{
class MemoryException
{};
class MemoryAllocationException: public MemoryException
{};
class NotOwnedMemoryException: public MemoryException
{};
class DeallocOnNotAllocatedMemory: public MemoryException
{};
};

Memory management in C++

Ripensando sempre al discorso di gestione della memoria, ho scritto un gestore di memoria minimalista in C++, eventualmente utilizzabile per un sistema embedded, utilizzando come parametri di costruzione del gestore di memoria direttamente l'indirizzo fisico dello heap e la sua grandezza. Posto il file sorgenti separatamente, perche' altrimenti impazzisco con la formattazione (trasformare i < in &lt; ecc...)

lunedì 27 agosto 2007

Pool di risorse e gestione della memoria

Recentemente mi sono messo a meditare sulla gestione della memoria in Java: visto l’alto costo della new, pensavo di creare un generico contenitore template Pool in grado di contenere e riutilizzare risorse senza invocare la new; chiaramente gli oggetti avrebbero dovuto essere “abilitati” al riutilizzo attraverso un metodo di “rigenerazione” che facesse lo stesso lavoro di un’invocazione al distruttore + un’invocazione al costruttore senza coinvolgere il gestore della memoria della virtual machine (in C++ basterebbe sovraccaricare l’operatore di assegnamento). A questo punto avrei voluto implementare un qualche sistema per “sentire” l’uscita dallo scope di una reference all’oggetto per poter indicare al Pool quando segnare l’oggetto come inutilizzato e renderlo disponibile per essere riutilizzato. Non ci sono riuscito, e mi sono accontentato di un metodo “release” da invocare manualmente, rendendo così l’utilizzo di questo sistema soggetto ai soliti errori di memory leak, e quindi inutile.

Così ho cominciato a ragionare in C++: il meccanismo più efficiente per abbattere i costi dell’allocazione di memoria (in particolare la copia di oggetti complessi) è l’utilizzo di referenze come parametri di funzioni che consentono un comportamento “Java like” (e quindi il polimorfismo…) in modo totalmente trasparente al programmatore (che non deve gestire cioè manualmente la memoria): il limite delle referenze è che funzionano solo in una direzione (verso l’alto dello stack) e quindi non possono essere utilizzate per delle object factory. La soluzione è utilizzare gli auto_ptr, per consentire l’utilizzo di simil-referenze anche verso il basso dello stack: è così possibile creare una funzione del tipo:auto_ptr<resourcehandler> getResource(…);

A questo punto il distruttore di ResourceHandler avrà il compito di “rilasciare” la risorsa dal pool, e questo rilascio avverrà in automatico all’atto dell’uscita dallo scope dell’auto_ptr (bisogna quindi definire come virtuale il distruttore, per poter specializzare liberamente ResourceHandler).

Rimane però un problema: gli auto_ptr non possono essere utilizzati nei contenitori stl standard (o forse si… non mi ricordo come funzionano gli allocatori…). Certo che se Java mettesse a disposizione una callback tipo “finalize” (chiamiamola “referenceOutOfScope”) all’uscita dello scope di una referenza, il suo potenziale espressivo crescerebbe molto, mantenendo comunque la semplicità della gestione automatica della memoria.

sabato 4 agosto 2007

Doxygen&graphviz

Per creare la documentazione del codice, disponibile sia per Linux che per Windows, l'accoppiata doxygen + graphviz permette di generare files HTML, LaTex, RTF con tanto di diagrammi UML. Imperdibile!