Click here to Skip to main content
15,897,187 members
Articles / Programming Languages / C++

Undo and Redo the "Easy" Way

Rate me:
Please Sign up or sign in to vote.
4.95/5 (42 votes)
20 Jun 2004CPOL22 min read 290.8K   8.6K   114  
This article introduces a simple approach to in-memory transactions that can be used to implement Undo and Redo. The technique uses SEH and Virtual Memory and requires only STL and Win32.
#include <memory.h>

namespace Mm {
	template <class FieldType, size_t WindowSize = sizeof(FieldType) * 8>
	struct RleCodeBlock {
		enum { windowSize = WindowSize };

		inline bool Bit(size_t shift) { return ((FieldType)(1 << shift) & descriptor) != 0; }
		inline void ClearBit(size_t shift) { descriptor &= ~(FieldType)(1 << shift); }
		inline void SetBit(size_t shift) {  descriptor |= (FieldType)(1 << shift); }

		FieldType		descriptor;
		FieldType		fields[WindowSize - 1];

		bool Decode(FieldType*& buf, unsigned long& count)
		{ 
			FieldType len = 1;
			for (unsigned char i = 0; i < (windowSize - 1); ++ i) {
				if (Bit(i)) {
					if (fields[i]) for (FieldType j = 0; j < len; ++j) *(buf++) = fields[i];
					else buf += len;
					count += len; // added len bytes
					len = 1; // reset len
				} else {
					len = fields[i];

					if (len == 0) return false;
				}
			}
			return true;
		}

		bool Encode(FieldType*& buf, unsigned long& count)
		{ 
			const unsigned char limit = (windowSize - 2);
			bool more = true;

			const unsigned long lenMax = (1 << (sizeof(FieldType) * 8)) - 1;
			for (unsigned char i = 0; i < (windowSize - 1); ++i) {
				if (count == 0) {
					ClearBit(i);
					fields[i] = 0;
					more = false;
					break;
				}

				FieldType* end = buf + 1;
				FieldType len = 1;
				if (i < limit) { 
					while ((len < count) && (len < lenMax) && (*end == *buf)) {
						++end; 
						++len; 
					}
				}

				switch (len) {
				default:
					ClearBit(i);
					fields[i] = len;
					++i;

				case 1:
					SetBit(i);
					fields[i] = *buf;
				}

				buf += len;
				count -= len;
			}
		
			return more;
		}

		size_t Write(FieldType*& buf)
		{
			const FieldType* start = buf;

			*(buf++) = descriptor;

			for (size_t i = 0; i < (windowSize - 1); ++i) {
				*(buf++) = fields[i];
				if (!Bit(i) && !fields[i]) break;
			}

			if (buf - start > windowSize) throw;

			return buf - start;
		}

		bool DecodeAsDelta(FieldType*& buf, unsigned long& count)
		{ 
			FieldType len = 1;
			for (unsigned char i = 0; i < (windowSize - 1); ++ i) {
				if (Bit(i)) {
					if (fields[i]) for (FieldType j = 0; j < len; ++j) *(buf++) ^= fields[i];
					else buf += len;
					count += len; // added len bytes
					len = 1; // reset len
				} else {
					len = fields[i];

					if (len == 0) return false;
				}
			}
			return true;
		}

	};

	typedef unsigned short FieldType;
	typedef RleCodeBlock<FieldType> BlockType;

	int Compress(void* in, void* out)
	{
		BlockType block;
		FieldType* inc = (FieldType*)in;
		FieldType* outc = (FieldType*)out;
		
		unsigned long in_count = 4096 / sizeof(FieldType);
		unsigned long out_count = 0;
		
		bool more = false;
		do {
			more = block.Encode(inc, in_count);
			unsigned long c = block.Write(outc);
			out_count += c * sizeof(FieldType);
		} while (more);

		return out_count;
	}

	int Decompress(void* in, void* out)
	{
		unsigned long count = 0;
		BlockType* block = (BlockType*)in;
		FieldType* buf = (FieldType*)out;
		while (block->Decode(buf, count) && (count * sizeof(FieldType) < 4096)) 
			++block;

		return count;
	}

	int ApplyCompressedDelta(void* page, void* delta)
	{
		FieldType* pagec = (FieldType*)page;
		unsigned long count = 0;
		BlockType* block = (BlockType*)delta;
		while (block->DecodeAsDelta(pagec, count) && (count * sizeof(FieldType) < 4096)) 
			++block;

		return count;
	}
};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
A compiler warns of bogasity, ignore it at your peril. Unless you've done the compiler's job yourself, don't criticize it.

Comments and Discussions