<commit_before>#ifndef UNION_SSE_HPP_
#define UNION_SSE_HPP_

#include <immintrin.h>

#include <algorithm>

#include "branchless.hpp"

size_t union_vector_sse(const uint32_t *list1, size_t size1, const uint32_t *list2, size_t size2, uint32_t *result){
	size_t count = 0;
#ifdef __SSE2__
	size_t i_a = 0, i_b = 0;
	// trim lengths to be a multiple of 4
	size_t st_a = ((size1-1) / 4) * 4;
	size_t st_b = ((size2-1) / 4) * 4;
	uint32_t endofblock=~0, a_nextfirst, b_nextfirst;
	uint32_t maxtail[4];

	if(i_a < st_a && i_b < st_b){
		__m128i v_a = _mm_load_si128((__m128i*)&list1[i_a]);
		__m128i v_b = _mm_load_si128((__m128i*)&list2[i_b]);

		do {
			__m128i step1min = _mm_min_epu32(v_a, v_b);
			__m128i step1max = _mm_max_epu32(v_a, v_b);

			constexpr int32_t cyclic_shift = _MM_SHUFFLE(2,1,0,3);
			__m128i tmp = _mm_shuffle_epi32(step1max, cyclic_shift);
			__m128i step2min = _mm_min_epu32(step1min, tmp);
			__m128i step2max = _mm_max_epu32(step1min, tmp);

			__m128i tmp2 = _mm_shuffle_epi32(step2max, cyclic_shift);
			__m128i step3min = _mm_min_epu32(step2min, tmp2);
			__m128i step3max = _mm_max_epu32(step2min, tmp2);

			__m128i tmp3 = _mm_shuffle_epi32(step3max, cyclic_shift);
			__m128i step4min = _mm_min_epu32(step3min, tmp3);
			__m128i step4max = _mm_max_epu32(step3min, tmp3);

			__m128i tmp4 = _mm_shuffle_epi32(step4max, cyclic_shift);

			// deduplicate over block end, 1 2 3 4 | 4 5 6 7
			uint32_t first = _mm_extract_epi32(step4min, 0);
			count -= (endofblock==first);
			endofblock = _mm_extract_epi32(step4min, 3);
			// in register deduplicate, only removes inside one vector
			__m128i dedup = _mm_shuffle_epi32(step4min, cyclic_shift);
			__m128i dedup_mask = _mm_cmpeq_epi32(step4min, dedup);
			// flip mask
			dedup_mask = _mm_andnot_si128(dedup_mask, _mm_cmpeq_epi32(tmp, tmp));
			// compress shuffle like in intersect
			// convert the 128-bit mask to the 4-bit mask
			int32_t mask = _mm_movemask_ps((__m128)dedup_mask);
			__m128i p = _mm_shuffle_epi8(step4min, shuffle_mask[mask]);
			_mm_storeu_si128((__m128i*)&result[count], p);
			count += _mm_popcnt_u32(mask); // a number of elements is a weight of the mask

			v_a = tmp4;
			// compare first element of the next block in both lists
			a_nextfirst = list1[i_a+4];
			b_nextfirst = list2[i_b+4];
			// write minimum as above out to result
			// keep maximum and do the same steps as above with next block
			// next block from one list, which first element in new block is smaller
			asm(".intel_syntax noprefix;"

				"xor rax, rax;"
				"xor rbx, rbx;"
				"cmp %5, %6;"
				"setbe al;"
				"seta  bl;"
				"lea %q0, [%q0 + rax*4];"
				"lea %q1, [%q1 + rbx*4];"

				// load next block from list with smaller first element
				"mov r10, %q8;"
				"mov r11, %q1;"
				"cmovbe r10, %q7;"
				"cmovbe r11, %q0;"
				"vmovdqa %2, [r10 + r11*4];" //FIXME: this might read past the end of one array, not used afterwards as loop head fails

				".att_syntax"
				: "=r"(i_a), "=r"(i_b), "=x"(v_b)
				: "0"(i_a), "1"(i_b), "r"(a_nextfirst), "r"(b_nextfirst), "r"(list1), "r"(list2)
				: "%eax","%ebx", "%r10","%r11", "cc"
			);
		}while(i_a < st_a && i_b < st_b);
		// v_a contains max vector from last comparison, v_b contains new, might be out of bounds
		// indices i_a and i_b correct, still need to handle v_a
		_mm_storeu_si128((__m128i*)maxtail, v_a);

		size_t mti=0;
		size_t mtsize = std::unique(maxtail, maxtail+4) - maxtail; // deduplicate tail
		if(a_nextfirst <= b_nextfirst){
			// endofblock needs to be considered too, for deduplication
			if(endofblock == std::min(maxtail[0],list1[i_a])) --count;
			// compare maxtail with list1
	// 		count += union_scalar_branchless(maxtail, 4, list1+i_a, size1-i_a, result+count);
			while(mti < mtsize && i_a < size1){
				if(maxtail[mti] < list1[i_a]){
					result[count++] = maxtail[mti];
					mti++;
				}else if(maxtail[mti] > list1[i_a]){
					result[count++] = list1[i_a];
					i_a++;
				}else{
					result[count++] = maxtail[mti];
					mti++; i_a++;
				}
			}
			i_b += 4;
		}else{
			// endofblock needs to be considered too, for deduplication
			if(endofblock == std::min(maxtail[0],list2[i_b])) --count;
			// compare maxtail with list2
	// 		count += union_scalar_branchless(maxtail, 4, list2+i_b, size2-i_b, result+count);
			while(mti < mtsize && i_b < size2){
				if(maxtail[mti] < list2[i_b]){
					result[count++] = maxtail[mti];
					mti++;
				}else if(maxtail[mti] > list2[i_b]){
					result[count++] = list2[i_b];
					i_b++;
				}else{
					result[count++] = maxtail[mti];
					mti++; i_b++;
				}
			}
			i_a += 4;
		}
		while(mti < mtsize){
			result[count++] = maxtail[mti++];
		}
	}

	// scalar tail
	count += union_scalar_branchless(list1+i_a, size1-i_a, list2+i_b, size2-i_b, result+count);
#endif

	return count;
}

#endif
<commit_msg>added new deduplication variant to SSE set_union<commit_after>#ifndef UNION_SSE_HPP_
#define UNION_SSE_HPP_

#include <immintrin.h>

#include <algorithm>

#include "branchless.hpp"

#define BLEND 1
#if BLEND
static constexpr constarray<uint8_t,16*16> prepare_shuffle(){
	constarray<uint8_t,16*16> arr = {0xff};
	int size=0;
	for(int i=0; i<16; ++i){
		int counter=0;
		for(int j=0; j<4; ++j){
			if((i & (1 << j)) == 0){
				arr[size+counter*4  ] = 4*j;
				arr[size+counter*4+1] = 4*j + 1;
				arr[size+counter*4+2] = 4*j + 2;
				arr[size+counter*4+3] = 4*j + 3;
				++counter;
			}
		}
		size += 16;
	}
	return arr;
}
static const constexpr auto shuffle_arr = prepare_shuffle();
static const constexpr __m128i *shuffle = (__m128i*)shuffle_arr.elems;
#endif

size_t union_vector_sse(const uint32_t *list1, size_t size1, const uint32_t *list2, size_t size2, uint32_t *result){
	size_t count = 0;
#ifdef __SSE2__
	size_t i_a = 0, i_b = 0;
	// trim lengths to be a multiple of 4
	size_t st_a = ((size1-1) / 4) * 4;
	size_t st_b = ((size2-1) / 4) * 4;
	uint32_t a_nextfirst, b_nextfirst;
#if !BLEND
	uint32_t endofblock=~0;
#else
	__m128i old = _mm_set1_epi32(-1); //FIXME: hardcoded, use something related to the lists
#endif
	uint32_t maxtail[4];

	if(i_a < st_a && i_b < st_b){
		__m128i v_a = _mm_load_si128((__m128i*)&list1[i_a]);
		__m128i v_b = _mm_load_si128((__m128i*)&list2[i_b]);

		do {
			__m128i step1min = _mm_min_epu32(v_a, v_b);
			__m128i step1max = _mm_max_epu32(v_a, v_b);

			constexpr int32_t cyclic_shift = _MM_SHUFFLE(2,1,0,3);
			__m128i tmp = _mm_shuffle_epi32(step1max, cyclic_shift);
			__m128i step2min = _mm_min_epu32(step1min, tmp);
			__m128i step2max = _mm_max_epu32(step1min, tmp);

			__m128i tmp2 = _mm_shuffle_epi32(step2max, cyclic_shift);
			__m128i step3min = _mm_min_epu32(step2min, tmp2);
			__m128i step3max = _mm_max_epu32(step2min, tmp2);

			__m128i tmp3 = _mm_shuffle_epi32(step3max, cyclic_shift);
			__m128i step4min = _mm_min_epu32(step3min, tmp3);
			__m128i step4max = _mm_max_epu32(step3min, tmp3);

			__m128i tmp4 = _mm_shuffle_epi32(step4max, cyclic_shift);

#if !BLEND
			// deduplicate over block end, 1 2 3 4 | 4 5 6 7
			uint32_t first = _mm_extract_epi32(step4min, 0);
			count -= (endofblock==first);
			endofblock = _mm_extract_epi32(step4min, 3);
			// in register deduplicate, only removes inside one vector
			__m128i dedup = _mm_shuffle_epi32(step4min, cyclic_shift);
			__m128i dedup_mask = _mm_cmpeq_epi32(step4min, dedup);
			// flip mask
			dedup_mask = _mm_andnot_si128(dedup_mask, _mm_cmpeq_epi32(tmp, tmp));
			// compress shuffle like in intersect
			// convert the 128-bit mask to the 4-bit mask
			int32_t mask = _mm_movemask_ps((__m128)dedup_mask);
			__m128i p = _mm_shuffle_epi8(step4min, shuffle_mask[mask]);
			_mm_storeu_si128((__m128i*)&result[count], p);
			count += _mm_popcnt_u32(mask); // a number of elements is a weight of the mask
#else
			// deduplicate over block end, 1 2 3 4 | 4 5 6 7
			// remember previous minimum vector, only use highest value
			__m128i recon = _mm_blend_epi32(old, step4min, 0b0111);
			// in register deduplicate, removes duplicates in one vector
			// and across as we moved in the highest previous value
			__m128i dedup = _mm_shuffle_epi32(recon, cyclic_shift);
			// compress shuffle like in intersect but flipped, use flipped lut
			// convert the 128-bit mask to the 4-bit mask
			int32_t mask = _mm_movemask_ps((__m128)_mm_cmpeq_epi32(dedup, step4min));
			__m128i p = _mm_shuffle_epi8(step4min, shuffle[mask]);
			_mm_storeu_si128((__m128i*)&result[count], p);
			count += 4 - _mm_popcnt_u32(mask); // a number of elements is a weight of the mask
			// remember minimum for next iteration
			old = step4min;
#endif

			v_a = tmp4;
			// compare first element of the next block in both lists
			a_nextfirst = list1[i_a+4];
			b_nextfirst = list2[i_b+4];
			// write minimum as above out to result
			// keep maximum and do the same steps as above with next block
			// next block from one list, which first element in new block is smaller
			asm(".intel_syntax noprefix;"

				"xor rax, rax;"
				"xor rbx, rbx;"
				"cmp %5, %6;"
				"setbe al;"
				"seta  bl;"
				"lea %q0, [%q0 + rax*4];"
				"lea %q1, [%q1 + rbx*4];"

				// load next block from list with smaller first element
				"mov r10, %q8;"
				"mov r11, %q1;"
				"cmovbe r10, %q7;"
				"cmovbe r11, %q0;"
				"vmovdqa %2, [r10 + r11*4];" //FIXME: this might read past the end of one array, not used afterwards as loop head fails

				".att_syntax"
				: "=r"(i_a), "=r"(i_b), "=x"(v_b)
				: "0"(i_a), "1"(i_b), "r"(a_nextfirst), "r"(b_nextfirst), "r"(list1), "r"(list2)
				: "%eax","%ebx", "%r10","%r11", "cc"
			);
		}while(i_a < st_a && i_b < st_b);
		// v_a contains max vector from last comparison, v_b contains new, might be out of bounds
		// indices i_a and i_b correct, still need to handle v_a
		_mm_storeu_si128((__m128i*)maxtail, v_a);
#if BLEND
		uint32_t endofblock = _mm_extract_epi32(old, 3);
#endif

		size_t mti=0;
		size_t mtsize = std::unique(maxtail, maxtail+4) - maxtail; // deduplicate tail
		if(a_nextfirst <= b_nextfirst){
			// endofblock needs to be considered too, for deduplication
			if(endofblock == std::min(maxtail[0],list1[i_a])) --count;
			// compare maxtail with list1
	// 		count += union_scalar_branchless(maxtail, 4, list1+i_a, size1-i_a, result+count);
			while(mti < mtsize && i_a < size1){
				if(maxtail[mti] < list1[i_a]){
					result[count++] = maxtail[mti];
					mti++;
				}else if(maxtail[mti] > list1[i_a]){
					result[count++] = list1[i_a];
					i_a++;
				}else{
					result[count++] = maxtail[mti];
					mti++; i_a++;
				}
			}
			i_b += 4;
		}else{
			// endofblock needs to be considered too, for deduplication
			if(endofblock == std::min(maxtail[0],list2[i_b])) --count;
			// compare maxtail with list2
	// 		count += union_scalar_branchless(maxtail, 4, list2+i_b, size2-i_b, result+count);
			while(mti < mtsize && i_b < size2){
				if(maxtail[mti] < list2[i_b]){
					result[count++] = maxtail[mti];
					mti++;
				}else if(maxtail[mti] > list2[i_b]){
					result[count++] = list2[i_b];
					i_b++;
				}else{
					result[count++] = maxtail[mti];
					mti++; i_b++;
				}
			}
			i_a += 4;
		}
		while(mti < mtsize){
			result[count++] = maxtail[mti++];
		}
	}

	// scalar tail
	count += union_scalar_branchless(list1+i_a, size1-i_a, list2+i_b, size2-i_b, result+count);
#endif

	return count;
}

#endif
<|endoftext|>


<commit_before>#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<assert.h>
#include<thread>
#include<mutex>

#include"ParallelTest.h"
#include"INode.h"
#include"CDirectory.h"

#define MAXSIZE 0xFFFFF

// ----------------------

static SimpleFilesystem *fs;

// ----------------------

typedef struct
{
    INODEPTR node;
    char filename[256];
    int size;
    std::mutex mtx;
    char data[MAXSIZE+2];
    unsigned int g_seed;
} FSTRUCT;

static FSTRUCT *files;

static unsigned int niter = 2000;
static unsigned int nfiles = 10;
static unsigned int nthreads = 10;

static unsigned int g_seed = 0;

inline int fastrand(unsigned int &g_seed)
{
  g_seed = (214013*g_seed+2531011);
  return (g_seed>>16)&0x7FFF;
}

// ----------------------

void Execute(int tid)
{
    char *data = new char[MAXSIZE+2];
    CDirectory dir = fs->OpenDir("/");

    //printf("thread %i:\n", tid);
    for(unsigned int iter=0; iter<niter; iter++)
    {
        int cmd = fastrand(g_seed)%6;
        int id = fastrand(g_seed)%nfiles;
        int ofs = 0;

        files[id].mtx.lock();
        //printf("cmd=%i id=%i\n", cmd, id);
        switch(cmd)
        {

        case 0: // Truncate
        {
            int newsize = rand() & MAXSIZE;
            printf("tid %1i %5i: Truncate %i size=%i\n", tid, iter, id, newsize);
            if (newsize > files[id].size)
            {
                memset(&(files[id].data[ files[id].size ]), 0, newsize-files[id].size);
            }
            files[id].size = newsize;
            files[id].node->Truncate(newsize);
        }
        break;

        case 1: // write
        {
            if (files[id].size > 0) ofs = rand() % files[id].size;
            int newsize = rand() & MAXSIZE;
            if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1;
            if (newsize < 0) newsize = 0;

            printf("tid %1i %5i: write %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize);
            for(int i=0; i<newsize; i++)
            {
                files[id].data[ofs+i] = fastrand(files[id].g_seed);
            }

            files[id].node->Write((int8_t*)&(files[id].data[ofs]), ofs, newsize);
            if (ofs+newsize > files[id].size) files[id].size = ofs+newsize;
        }
        break;

        case 2: // read
        {
            if (files[id].size > 0) ofs = rand() % files[id].size;
            int newsize = rand() & MAXSIZE;
            if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1;
            if (newsize < 0) newsize = 0;

            printf("tid %1i %5i: read %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize);
            if (ofs+newsize > files[id].size) newsize = files[id].size - ofs - 1;
            if (newsize < 0) newsize = 0;
            files[id].node->Read((int8_t*)data, ofs, newsize);

            for(int i=0; i<newsize; i++)
            {
                if (data[i] != files[id].data[ofs+i])
                {
                    printf("read data from file %i does not match at ofs=%i read=%i but should be %i\n", id, ofs+i, data[i], files[id].data[ofs+i]);
                    exit(1);
                }
            }
        }
        break;

        case 3: // check filesize
        {
            printf("tid %1i %5i: filesize %i\n", tid, iter, id);
            if (files[id].node->size != (unsigned int)files[id].size)
            {
                printf("size of file %i does not match %i %lli\n", id, files[id].size, (long long int)files[id].node->size);
                exit(1);
            }
        }
        break;

        case 4: // rename
        {
            printf("tid %1i %5i: rename %i\n", tid, iter, id);
            char newfilename[256];
            sprintf(newfilename, "tests%02i_%03i.dat", id, rand()%999);
            fs->Rename(files[id].node, dir, newfilename);
            strncpy(files[id].filename, newfilename, 256);
        }
        break;

        case 5: // create&remove
        {
            printf("tid %1i %5i: create&remove %i\n", tid, iter, id);
            char newfilename[256];
            sprintf(newfilename, "tests%02i_check.dat", id);
            dir.CreateFile(newfilename);
            INODEPTR node = fs->OpenNode(newfilename);
            node->Remove();
        }
        break;

        } // switch
        files[id].mtx.unlock();

    }

}

void ParallelTest(unsigned int _nfiles, unsigned int _nthreads, unsigned int _niter, SimpleFilesystem &_fs)
{
    printf("Number of files %i\n", nfiles);
    printf("Number of threads: %i\n", nthreads);
    printf("Number of iterations per thread: %i\n", niter);

    srand (time(NULL));
    g_seed = time(NULL);

    nfiles = _nfiles;
    nthreads = _nthreads;
    niter = _niter;
    fs = &_fs;
    CDirectory dir = fs->OpenDir("/");

    files = new FSTRUCT[nfiles];
    for(unsigned int i=0; i<nfiles; i++)
    {
        files[i].g_seed = 0xA0A0A0+i;
        sprintf(files[i].filename, "tests%02i_%03i.dat", i, 0);
        try
        {
            dir.CreateFile(files[i].filename);
        }
        catch(...)
        {
            // file already exists
        }
        files[i].node = fs->OpenNode(files[i].filename);
        files[i].node->Truncate(0);

        files[i].size = 0;
        memset(files[i].data, 0, MAXSIZE+1);
    }

    std::thread *t = new std::thread[nthreads];

    for(unsigned int i=0; i<nthreads; i++)
    {
        t[i] = std::thread(Execute, i);
    }

    for(unsigned int i=0; i<nthreads; i++)
    {
        t[i].join();
    }
    printf("Tests done\n");

}
<commit_msg>Remove memory leaks<commit_after>#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<assert.h>
#include<thread>
#include<mutex>

#include"ParallelTest.h"
#include"INode.h"
#include"CDirectory.h"

#define MAXSIZE 0xFFFFF

// ----------------------

static SimpleFilesystem *fs;

// ----------------------

typedef struct
{
    INODEPTR node;
    char filename[256];
    int size;
    std::mutex mtx;
    char data[MAXSIZE+2];
    unsigned int g_seed;
} FSTRUCT;

static FSTRUCT *files;

static unsigned int niter = 2000;
static unsigned int nfiles = 10;
static unsigned int nthreads = 10;

static unsigned int g_seed = 0;

inline int fastrand(unsigned int &g_seed)
{
  g_seed = (214013*g_seed+2531011);
  return (g_seed>>16)&0x7FFF;
}

// ----------------------

void Execute(int tid)
{
    char *data = new char[MAXSIZE+2];
    CDirectory dir = fs->OpenDir("/");

    //printf("thread %i:\n", tid);
    for(unsigned int iter=0; iter<niter; iter++)
    {
        int cmd = fastrand(g_seed)%6;
        int id = fastrand(g_seed)%nfiles;
        int ofs = 0;

        files[id].mtx.lock();
        //printf("cmd=%i id=%i\n", cmd, id);
        switch(cmd)
        {

        case 0: // Truncate
        {
            int newsize = rand() & MAXSIZE;
            printf("tid %1i %5i: Truncate %i size=%i\n", tid, iter, id, newsize);
            if (newsize > files[id].size)
            {
                memset(&(files[id].data[ files[id].size ]), 0, newsize-files[id].size);
            }
            files[id].size = newsize;
            files[id].node->Truncate(newsize);
        }
        break;

        case 1: // write
        {
            if (files[id].size > 0) ofs = rand() % files[id].size;
            int newsize = rand() & MAXSIZE;
            if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1;
            if (newsize < 0) newsize = 0;

            printf("tid %1i %5i: write %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize);
            for(int i=0; i<newsize; i++)
            {
                files[id].data[ofs+i] = fastrand(files[id].g_seed);
            }

            files[id].node->Write((int8_t*)&(files[id].data[ofs]), ofs, newsize);
            if (ofs+newsize > files[id].size) files[id].size = ofs+newsize;
        }
        break;

        case 2: // read
        {
            if (files[id].size > 0) ofs = rand() % files[id].size;
            int newsize = rand() & MAXSIZE;
            if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1;
            if (newsize < 0) newsize = 0;

            printf("tid %1i %5i: read %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize);
            if (ofs+newsize > files[id].size) newsize = files[id].size - ofs - 1;
            if (newsize < 0) newsize = 0;
            files[id].node->Read((int8_t*)data, ofs, newsize);

            for(int i=0; i<newsize; i++)
            {
                if (data[i] != files[id].data[ofs+i])
                {
                    printf("read data from file %i does not match at ofs=%i read=%i but should be %i\n", id, ofs+i, data[i], files[id].data[ofs+i]);
                    exit(1);
                }
            }
        }
        break;

        case 3: // check filesize
        {
            printf("tid %1i %5i: filesize %i\n", tid, iter, id);
            if (files[id].node->size != (unsigned int)files[id].size)
            {
                printf("size of file %i does not match %i %lli\n", id, files[id].size, (long long int)files[id].node->size);
                exit(1);
            }
        }
        break;

        case 4: // rename
        {
            printf("tid %1i %5i: rename %i\n", tid, iter, id);
            char newfilename[256];
            sprintf(newfilename, "tests%02i_%03i.dat", id, rand()%999);
            fs->Rename(files[id].node, dir, newfilename);
            strncpy(files[id].filename, newfilename, 256);
        }
        break;

        case 5: // create&remove
        {
            printf("tid %1i %5i: create&remove %i\n", tid, iter, id);
            char newfilename[256];
            sprintf(newfilename, "tests%02i_check.dat", id);
            dir.CreateFile(newfilename);
            INODEPTR node = fs->OpenNode(newfilename);
            node->Remove();
        }
        break;

        } // switch
        files[id].mtx.unlock();

    }
    delete[] data;
}

void ParallelTest(unsigned int _nfiles, unsigned int _nthreads, unsigned int _niter, SimpleFilesystem &_fs)
{
    printf("Number of files %i\n", nfiles);
    printf("Number of threads: %i\n", nthreads);
    printf("Number of iterations per thread: %i\n", niter);

    srand (time(NULL));
    g_seed = time(NULL);

    nfiles = _nfiles;
    nthreads = _nthreads;
    niter = _niter;
    fs = &_fs;
    CDirectory dir = fs->OpenDir("/");

    files = new FSTRUCT[nfiles];
    for(unsigned int i=0; i<nfiles; i++)
    {
        files[i].g_seed = 0xA0A0A0+i;
        sprintf(files[i].filename, "tests%02i_%03i.dat", i, 0);
        try
        {
            dir.CreateFile(files[i].filename);
        }
        catch(...)
        {
            // file already exists
        }
        files[i].node = fs->OpenNode(files[i].filename);
        files[i].node->Truncate(0);

        files[i].size = 0;
        memset(files[i].data, 0, MAXSIZE+1);
    }

    std::thread *t = new std::thread[nthreads];

    for(unsigned int i=0; i<nthreads; i++)
    {
        t[i] = std::thread(Execute, i);
    }

    for(unsigned int i=0; i<nthreads; i++)
    {
        t[i].join();
    }
    delete[] t;
    delete[] files;

    printf("Tests done\n");

}
<|endoftext|>


<commit_before>#ifndef __RUBBISH_ADD_QUALIFIER__
#define __RUBBISH_ADD_QUALIFIER__

#include "basic_traits.hpp"
#include "remove_qualifier.hpp"

namespace rubbish{

    namespace helper{
        template <class T,bool function_type=false> struct add_pointer_h {typedef typename remove_reference<T>::type type;};
        template <class T> struct add_pointer_h<T,true> {typedef T type;};
        template < class T,class ...Args> struct add_pointer_h<T(Args...),true> {using type = T(*)(Args...);};
        template < class T,class ...Args> struct add_pointer_h<T(Args...,...),true> {using type = T(*)(Args...,...);};
    } // namespace helper

    template <class T> struct add_const {typedef const T type;};

    template <class T> struct add_volatile {typedef volatile T type;};

    template <class T> struct add_cv {typedef typename add_const<typename add_volatile<T>::type>::type type;};

    // Always set `type` as an lvalue reference
    template <class T> struct add_lvalue_reference {typedef T& type;};
    template <class T> struct add_lvalue_reference<T&> {typedef T& type;};
    template <class T> struct add_lvalue_reference<T&&> {typedef T& type;};

    // Always set `type` as an rvalue reference
    template <class T> struct add_rvalue_reference {typedef T&& type;};
    template <class T> struct add_rvalue_reference<T&> {typedef T&& type;};
    template <class T> struct add_rvalue_reference<T&&> {typedef T&& type;};

    template <class T> struct add_pointer:public helper::add_pointer_h<T,is_function<T>::value> {};

    template <class T> struct decay {
        private:
            typedef typename remove_reference<T>::type U;
        public:
            typedef typename condition<is_array<U>::value,
                typename remove_extent<U>::type*,
                typename condition<is_function<U>::value,
                    typename add_pointer<U>::type,
                    typename remove_cv<U>::type
                >::type
            >::type type;
    };
}
#endif // __RUBBISH_ADD_QUALIFIER__
<commit_msg>Fixed a bug<commit_after>#ifndef __RUBBISH_ADD_QUALIFIER__
#define __RUBBISH_ADD_QUALIFIER__

#include "basic_traits.hpp"
#include "is_checkers.hpp"
#include "remove_qualifier.hpp"

namespace rubbish{

    namespace helper{
        template <class T,bool function_type=false> struct add_pointer_h {typedef typename remove_reference<T>::type type;};
        template <class T> struct add_pointer_h<T,true> {typedef T type;};
        template < class T,class ...Args> struct add_pointer_h<T(Args...),true> {using type = T(*)(Args...);};
        template < class T,class ...Args> struct add_pointer_h<T(Args...,...),true> {using type = T(*)(Args...,...);};
    } // namespace helper

    template <class T> struct add_const {typedef const T type;};

    template <class T> struct add_volatile {typedef volatile T type;};

    template <class T> struct add_cv {typedef typename add_const<typename add_volatile<T>::type>::type type;};

    // Always set `type` as an lvalue reference
    template <class T> struct add_lvalue_reference {typedef T& type;};
    template <class T> struct add_lvalue_reference<T&> {typedef T& type;};
    template <class T> struct add_lvalue_reference<T&&> {typedef T& type;};

    // Always set `type` as an rvalue reference
    template <class T> struct add_rvalue_reference {typedef T&& type;};
    template <class T> struct add_rvalue_reference<T&> {typedef T&& type;};
    template <class T> struct add_rvalue_reference<T&&> {typedef T&& type;};

    template <class T> struct add_pointer:public helper::add_pointer_h<T,is_function<T>::value> {};

    template <class T> struct decay {
        private:
            typedef typename remove_reference<T>::type U;
        public:
            typedef typename condition<is_array<U>::value,
                typename remove_extent<U>::type*,
                typename condition<is_function<U>::value,
                    typename add_pointer<U>::type,
                    typename remove_cv<U>::type
                >::type
            >::type type;
    };
}
#endif // __RUBBISH_ADD_QUALIFIER__
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkDisplayVectorInteractor.h"
#include "mitkOperation.h"
#include "mitkDisplayCoordinateOperation.h"
#include "mitkDisplayPositionEvent.h"
#include "mitkUndoController.h"
#include "mitkStateEvent.h"
#include "mitkInteractionConst.h"
#include "mitkAction.h"

void mitk::DisplayVectorInteractor::ExecuteOperation(Operation* itkNotUsed( operation ) )
{
  /*DisplayCoordinateOperation* dcOperation = static_cast<DisplayCoordinateOperation*>(operation);
  if(dcOperation==NULL) return;

  switch(operation->GetOperationType())
  {
  case OpSELECTPOINT:
    m_Sender=dcOperation->GetRenderer();
    m_StartDisplayCoordinate=dcOperation->GetStartDisplayCoordinate();
    m_LastDisplayCoordinate=dcOperation->GetLastDisplayCoordinate();
    m_CurrentDisplayCoordinate=dcOperation->GetCurrentDisplayCoordinate();
//    MITK_INFO << m_CurrentDisplayCoordinate << std::endl;

    MITK_INFO<<"Message from DisplayVectorInteractor.cpp::ExecuteOperation() : "
      << "StartDisplayCoordinate:" <<     m_StartDisplayCoordinate
      << "LastDisplayCoordinate:" <<      m_LastDisplayCoordinate
      << "CurrentDisplayCoordinate:" <<   m_CurrentDisplayCoordinate
      << std::endl;

    break;
  }*/

}

bool mitk::DisplayVectorInteractor::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent)
{
  bool ok=false;

  const DisplayPositionEvent* posEvent=dynamic_cast<const DisplayPositionEvent*>(stateEvent->GetEvent());
  if(posEvent==NULL) return false;

  int actionId = action->GetActionId();
  //initzoom and initmove is the same!
  if (actionId == AcINITZOOM)
    actionId = AcINITMOVE;
  switch(actionId)
  {
  //case 0:
  //  {
  //    DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpTEST,  posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition());
  //    if (m_UndoEnabled)  //write to UndoMechanism
  //    {
  //      DisplayCoordinateOperation* undoOp = new DisplayCoordinateOperation(OpTEST, m_Sender, m_StartDisplayCoordinate, m_LastDisplayCoordinate, m_CurrentDisplayCoordinate);
  //
  //
  //      OperationEvent *operationEvent = new OperationEvent(this, doOp, undoOp);
  //      m_UndoController->SetOperationEvent(operationEvent);
  //    }
  //
  //    //execute the Operation
  //    m_Destination->ExecuteOperation(doOp);
  //    ok = true;
  //    break;
  //  }
  case AcSENDCOORDINATES:
    {
      DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpSENDCOORDINATES,  posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition());
      m_Destination->ExecuteOperation(doOp);
      ok = true;
      break;
    }
  case AcINITMOVE:
    {
      m_Sender=posEvent->GetSender();

      mitk::Vector2D origin = m_Sender->GetDisplayGeometry()->GetOriginInMM();
       double scaleFactorMMPerDisplayUnit = m_Sender->GetDisplayGeometry()->GetScaleFactorMMPerDisplayUnit();

      m_StartDisplayCoordinate=posEvent->GetDisplayPosition();
      m_LastDisplayCoordinate=posEvent->GetDisplayPosition();
      m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition();
      m_StartCoordinateInMM=mitk::Point2D( ( origin+m_StartDisplayCoordinate.GetVectorFromOrigin()*scaleFactorMMPerDisplayUnit ).GetDataPointer() );
      ok = true;
      break; if (m_UndoEnabled)  //write to UndoMechanism
      {
       // DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpMOVE,  m_Sender, m_StartDisplayCoordinate, m_StartDisplayCoordinate, posEvent->GetDisplayPosition());
        //DisplayCoordinateOperation* undoOp = new mitk::DisplayCoordinateOperation(OpMOVE,  posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), m_StartDisplayCoordinate);

        //OperationEvent *operationEvent = new OperationEvent(m_Destination, doOp, undoOp, "Move view");
       // m_UndoController->SetOperationEvent(operationEvent);
      }
    }
  case AcMOVE:
    {
      DisplayCoordinateOperation* doOp = new DisplayCoordinateOperation(OpMOVE,  m_Sender, m_StartDisplayCoordinate, m_CurrentDisplayCoordinate, posEvent->GetDisplayPosition());
      //make Operation
      m_LastDisplayCoordinate=m_CurrentDisplayCoordinate;
      m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition();

      //execute the Operation
      m_Destination->ExecuteOperation(doOp);
      ok = true;
      break;
    }
  case AcFINISHMOVE:
    {
      ok = true;
      break;
    }
  case AcZOOM:
    {
      DisplayCoordinateOperation* doOp = new DisplayCoordinateOperation(OpZOOM,  m_Sender, m_StartDisplayCoordinate, m_LastDisplayCoordinate, posEvent->GetDisplayPosition(),m_StartCoordinateInMM);

      //make Operation
      m_LastDisplayCoordinate=m_CurrentDisplayCoordinate;
      m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition();
      //MITK_INFO << m_CurrentDisplayCoordinate << std::endl;

      //execute the Operation
      m_Destination->ExecuteOperation(doOp);
      ok = true;
      break;
    }
  default:
    ok = false;
    break;
  }
  return ok;
}

mitk::DisplayVectorInteractor::DisplayVectorInteractor(const char * type, mitk::OperationActor* destination)
  : mitk::StateMachine(type), m_Sender(NULL), m_Destination(destination)
{
  m_StartDisplayCoordinate.Fill(0);
  m_LastDisplayCoordinate.Fill(0);
  m_CurrentDisplayCoordinate.Fill(0);

  if(m_Destination==NULL)
    m_Destination=this;
}

mitk::DisplayVectorInteractor::~DisplayVectorInteractor()
{
}

<commit_msg>clean up<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkDisplayVectorInteractor.h"
#include "mitkOperation.h"
#include "mitkDisplayCoordinateOperation.h"
#include "mitkDisplayPositionEvent.h"
#include "mitkUndoController.h"
#include "mitkStateEvent.h"
#include "mitkInteractionConst.h"
#include "mitkAction.h"

void mitk::DisplayVectorInteractor::ExecuteOperation(Operation* itkNotUsed( operation ) )
{
  /*DisplayCoordinateOperation* dcOperation = static_cast<DisplayCoordinateOperation*>(operation);
  if(dcOperation==NULL) return;

  switch(operation->GetOperationType())
  {
  case OpSELECTPOINT:
    m_Sender=dcOperation->GetRenderer();
    m_StartDisplayCoordinate=dcOperation->GetStartDisplayCoordinate();
    m_LastDisplayCoordinate=dcOperation->GetLastDisplayCoordinate();
    m_CurrentDisplayCoordinate=dcOperation->GetCurrentDisplayCoordinate();
//    MITK_INFO << m_CurrentDisplayCoordinate << std::endl;

    MITK_INFO<<"Message from DisplayVectorInteractor.cpp::ExecuteOperation() : "
      << "StartDisplayCoordinate:" <<     m_StartDisplayCoordinate
      << "LastDisplayCoordinate:" <<      m_LastDisplayCoordinate
      << "CurrentDisplayCoordinate:" <<   m_CurrentDisplayCoordinate
      << std::endl;

    break;
  }*/

}

bool mitk::DisplayVectorInteractor::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent)
{
  bool ok=false;

  const DisplayPositionEvent* posEvent=dynamic_cast<const DisplayPositionEvent*>(stateEvent->GetEvent());
  if(posEvent==NULL) return false;

  int actionId = action->GetActionId();
  //initzoom and initmove is the same!
  if (actionId == AcINITZOOM)
    actionId = AcINITMOVE;
  switch(actionId)
  {
  //case 0:
  //  {
  //    DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpTEST,  posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition());
  //
  //    //execute the Operation
  //    m_Destination->ExecuteOperation(doOp);
  //    ok = true;
  //    break;
  //  }
  case AcSENDCOORDINATES:
    {
      DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpSENDCOORDINATES,  posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition());
      m_Destination->ExecuteOperation(doOp);
      ok = true;
      break;
    }
  case AcINITMOVE:
    {
      m_Sender=posEvent->GetSender();

      mitk::Vector2D origin = m_Sender->GetDisplayGeometry()->GetOriginInMM();
       double scaleFactorMMPerDisplayUnit = m_Sender->GetDisplayGeometry()->GetScaleFactorMMPerDisplayUnit();

      m_StartDisplayCoordinate=posEvent->GetDisplayPosition();
      m_LastDisplayCoordinate=posEvent->GetDisplayPosition();
      m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition();
      m_StartCoordinateInMM=mitk::Point2D( ( origin+m_StartDisplayCoordinate.GetVectorFromOrigin()*scaleFactorMMPerDisplayUnit ).GetDataPointer() );
      ok = true;
      break;
    }
  case AcMOVE:
    {
      DisplayCoordinateOperation* doOp = new DisplayCoordinateOperation(OpMOVE,  m_Sender, m_StartDisplayCoordinate, m_CurrentDisplayCoordinate, posEvent->GetDisplayPosition());
      //make Operation
      m_LastDisplayCoordinate=m_CurrentDisplayCoordinate;
      m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition();

      //execute the Operation
      m_Destination->ExecuteOperation(doOp);
      ok = true;
      break;
    }
  case AcFINISHMOVE:
    {
      ok = true;
      break;
    }
  case AcZOOM:
    {
      DisplayCoordinateOperation* doOp = new DisplayCoordinateOperation(OpZOOM,  m_Sender, m_StartDisplayCoordinate, m_LastDisplayCoordinate, posEvent->GetDisplayPosition(),m_StartCoordinateInMM);

      //make Operation
      m_LastDisplayCoordinate=m_CurrentDisplayCoordinate;
      m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition();
      //MITK_INFO << m_CurrentDisplayCoordinate << std::endl;

      //execute the Operation
      m_Destination->ExecuteOperation(doOp);
      ok = true;
      break;
    }
  default:
    ok = false;
    break;
  }
  return ok;
}

mitk::DisplayVectorInteractor::DisplayVectorInteractor(const char * type, mitk::OperationActor* destination)
  : mitk::StateMachine(type), m_Sender(NULL), m_Destination(destination)
{
  m_StartDisplayCoordinate.Fill(0);
  m_LastDisplayCoordinate.Fill(0);
  m_CurrentDisplayCoordinate.Fill(0);

  if(m_Destination==NULL)
    m_Destination=this;
}

mitk::DisplayVectorInteractor::~DisplayVectorInteractor()
{
}

<|endoftext|>


<commit_before>#include <pangolin/pangolin.h>
#include <pangolin/video/video_record_repeat.h>
#include <pangolin/gl/gltexturecache.h>
#include <pangolin/gl/glpixformat.h>

template<typename T>
std::pair<float,float> GetOffsetScale(const pangolin::Image<unsigned char>& img, float type_max, float format_max)
{
    std::pair<float,float> mm(std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
    for(size_t i=0; i < img.Area(); ++i) {
        const T val = ((T*)img.ptr)[i];
        if(val != 0) {
            if(val < mm.first) mm.first = val;
            if(val > mm.second) mm.second = val;
        }
    }

    const float type_scale = format_max / type_max;
    const float offset = -type_scale* mm.first;
    const float scale = type_max / (mm.second - mm.first);
    return std::pair<float,float>(offset, scale);
}

void VideoViewer(const std::string& input_uri, const std::string& output_uri)
{
    // Open Video by URI
    pangolin::VideoRecordRepeat video(input_uri, output_uri);
    int total_frames = std::numeric_limits<int>::max();

    if(video.Streams().size() == 0) {
        pango_print_error("No video streams from device.\n");
        return;
    }

    // Check if video supports VideoPlaybackInterface
    pangolin::VideoPlaybackInterface* video_playback = video.Cast<pangolin::VideoPlaybackInterface>();
    if( video_playback ) {
        total_frames = video_playback->GetTotalFrames();
        std::cout << "Video length: " << total_frames << " frames" << std::endl;
    }

    std::vector<unsigned char> buffer;
    buffer.resize(video.SizeBytes()+1);

    // Create OpenGL window - guess sensible dimensions
    pangolin::CreateWindowAndBind( "VideoViewer",
        video.Width() * video.Streams().size(), video.Height()
    );

    // Setup resizable views for video streams
    std::vector<pangolin::GlPixFormat> glfmt;
    std::vector<std::pair<float,float> > gloffsetscale;

    pangolin::DisplayBase().SetLayout(pangolin::LayoutEqual);
    for(unsigned int d=0; d < video.Streams().size(); ++d) {
        pangolin::View& view = pangolin::CreateDisplay().SetAspect(video.Streams()[d].Aspect());
        pangolin::DisplayBase().AddDisplay(view);
        glfmt.push_back(pangolin::GlPixFormat(video.Streams()[d].PixFormat()));
        gloffsetscale.push_back(std::pair<float,float>(0.0f, 1.0f) );
    }

    int frame = 0;
    pangolin::Var<int>  max_frame("max_frame", total_frames );
    pangolin::Var<bool> linear_sampling("linear_sampling", true );

    std::vector<pangolin::Image<unsigned char> > images;

#ifdef CALLEE_HAS_CPP11
    const int FRAME_SKIP = 30;

    // Show/hide streams
    for(size_t v=0; v < pangolin::DisplayBase().NumChildren() && v < 9; v++) {
        pangolin::RegisterKeyPressCallback('1'+v, [v](){
            pangolin::DisplayBase()[v].ToggleShow();
        } );
    }

    pangolin::RegisterKeyPressCallback('r', [&](){
        if(!video.IsRecording()) {
            video.Record();
            pango_print_info("Started Recording.\n");
        }else{
            video.Stop();
            pango_print_info("Finished recording.\n");
        }
        fflush(stdout);
    });
    pangolin::RegisterKeyPressCallback('p', [&](){
        video.Play();
        max_frame = std::numeric_limits<int>::max();
        pango_print_info("Playing from file log.\n");
        fflush(stdout);
    });
    pangolin::RegisterKeyPressCallback('s', [&](){
        video.Source();
        max_frame = std::numeric_limits<int>::max();
        pango_print_info("Playing from source input.\n");
        fflush(stdout);
    });
    pangolin::RegisterKeyPressCallback(' ', [&](){
        max_frame = (frame < max_frame) ? frame : std::numeric_limits<int>::max();
    });
    pangolin::RegisterKeyPressCallback(pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_LEFT, [&](){
        if(video_playback) {
            const int frame = std::min(video_playback->GetCurrentFrameId()-FRAME_SKIP, video_playback->GetTotalFrames()-1);
            video_playback->Seek(frame);
        }else{
            // We can't go backwards
        }
    });
    pangolin::RegisterKeyPressCallback(pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_RIGHT, [&](){
        if(video_playback) {
            const int frame = std::max(video_playback->GetCurrentFrameId()+FRAME_SKIP, 0);
            video_playback->Seek(frame);
        }else{
            // Pause at this frame
            max_frame = frame+1;
        }
    });
    pangolin::RegisterKeyPressCallback('l', [&](){ linear_sampling = true; });
    pangolin::RegisterKeyPressCallback('n', [&](){ linear_sampling = false; });

    pangolin::RegisterKeyPressCallback('a', [&](){
        // Adapt scale
        for(unsigned int i=0; i<images.size(); ++i) {
            if(pangolin::DisplayBase()[i].HasFocus()) {
                std::pair<float,float> os(0.0f, 1.0f);
                if(glfmt[i].gltype == GL_UNSIGNED_BYTE) {
                    os = GetOffsetScale<unsigned char>(images[i], 255.0f, 1.0f);
                }else if(glfmt[i].gltype == GL_UNSIGNED_SHORT) {
                    os = GetOffsetScale<unsigned short>(images[i], 65535.0f, 1.0f);
                }else if(glfmt[i].gltype == GL_FLOAT) {
                    os = GetOffsetScale<float>(images[i], 1.0f, 1.0f);
                }
                gloffsetscale[i] = os;
            }
        }
    });
#endif

    // Stream and display video
    while(!pangolin::ShouldQuit())
    {
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
        glColor3f(1.0f, 1.0f, 1.0f);

        if (frame == 0 || frame < max_frame) {
            if (video.Grab(&buffer[0], images) ){
                ++frame;
            }
        }

        for(unsigned int i=0; i<images.size(); ++i)
        {
            if(pangolin::DisplayBase()[i].IsShown()) {
                pangolin::DisplayBase()[i].Activate();
                const std::pair<float,float> os = gloffsetscale[i];
                pangolin::GlSlUtilities::OffsetAndScale(os.first, os.second);
                pangolin::RenderToViewport(images[i], glfmt[i], false, true, linear_sampling);
                pangolin::GlSlUtilities::UseNone();
            }
        }

        pangolin::FinishFrame();
    }
}

int main( int argc, char* argv[] )
{
    const std::string dflt_output_uri = "pango://video.pango";

    if( argc > 1 ) {
        const std::string input_uri = std::string(argv[1]);
        const std::string output_uri = (argc > 2) ? std::string(argv[2]) : dflt_output_uri;
        try{
            VideoViewer(input_uri, output_uri);
        } catch (pangolin::VideoException e) {
            std::cout << e.what() << std::endl;
        }
    }else{
        const std::string input_uris[] = {
            "dc1394:[fps=30,dma=10,size=640x480,iso=400]//0",
            "convert:[fmt=RGB24]//v4l:///dev/video0",
            "convert:[fmt=RGB24]//v4l:///dev/video1",
            "openni:[img1=rgb]//",
            "test:[size=160x120,n=1,fmt=RGB24]//"
            ""
        };

        std::cout << "Usage  : VideoViewer [video-uri]" << std::endl << std::endl;
        std::cout << "Where video-uri describes a stream or file resource, e.g." << std::endl;
        std::cout << "\tfile:[realtime=1]///home/user/video/movie.pvn" << std::endl;
        std::cout << "\tfile:///home/user/video/movie.avi" << std::endl;
        std::cout << "\tfiles:///home/user/seqiemce/foo%03d.jpeg" << std::endl;
        std::cout << "\tdc1394:[fmt=RGB24,size=640x480,fps=30,iso=400,dma=10]//0" << std::endl;
        std::cout << "\tdc1394:[fmt=FORMAT7_1,size=640x480,pos=2+2,iso=400,dma=10]//0" << std::endl;
        std::cout << "\tv4l:///dev/video0" << std::endl;
        std::cout << "\tconvert:[fmt=RGB24]//v4l:///dev/video0" << std::endl;
        std::cout << "\tmjpeg://http://127.0.0.1/?action=stream" << std::endl;
        std::cout << "\topenni:[img1=rgb]//" << std::endl;
        std::cout << std::endl;

        // Try to open some video device
        for(int i=0; !input_uris[i].empty(); ++i )
        {
            try{
                pango_print_info("Trying: %s\n", input_uris[i].c_str());
                VideoViewer(input_uris[i], dflt_output_uri);
                return 0;
            }catch(pangolin::VideoException) { }
        }
    }

    return 0;
}
<commit_msg>VideoViewer: Assume packed video data unless otherwise specified.<commit_after>#include <pangolin/pangolin.h>
#include <pangolin/video/video_record_repeat.h>
#include <pangolin/gl/gltexturecache.h>
#include <pangolin/gl/glpixformat.h>

template<typename T>
std::pair<float,float> GetOffsetScale(const pangolin::Image<unsigned char>& img, float type_max, float format_max)
{
    std::pair<float,float> mm(std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
    for(size_t i=0; i < img.Area(); ++i) {
        const T val = ((T*)img.ptr)[i];
        if(val != 0) {
            if(val < mm.first) mm.first = val;
            if(val > mm.second) mm.second = val;
        }
    }

    const float type_scale = format_max / type_max;
    const float offset = -type_scale* mm.first;
    const float scale = type_max / (mm.second - mm.first);
    return std::pair<float,float>(offset, scale);
}

void VideoViewer(const std::string& input_uri, const std::string& output_uri)
{
    // Open Video by URI
    pangolin::VideoRecordRepeat video(input_uri, output_uri);
    int total_frames = std::numeric_limits<int>::max();

    if(video.Streams().size() == 0) {
        pango_print_error("No video streams from device.\n");
        return;
    }

    // Check if video supports VideoPlaybackInterface
    pangolin::VideoPlaybackInterface* video_playback = video.Cast<pangolin::VideoPlaybackInterface>();
    if( video_playback ) {
        total_frames = video_playback->GetTotalFrames();
        std::cout << "Video length: " << total_frames << " frames" << std::endl;
    }

    std::vector<unsigned char> buffer;
    buffer.resize(video.SizeBytes()+1);

    // Create OpenGL window - guess sensible dimensions
    pangolin::CreateWindowAndBind( "VideoViewer",
        video.Width() * video.Streams().size(), video.Height()
    );

    // Assume packed OpenGL data unless otherwise specified
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);

    // Setup resizable views for video streams
    std::vector<pangolin::GlPixFormat> glfmt;
    std::vector<std::pair<float,float> > gloffsetscale;

    pangolin::DisplayBase().SetLayout(pangolin::LayoutEqual);
    for(unsigned int d=0; d < video.Streams().size(); ++d) {
        pangolin::View& view = pangolin::CreateDisplay().SetAspect(video.Streams()[d].Aspect());
        pangolin::DisplayBase().AddDisplay(view);
        glfmt.push_back(pangolin::GlPixFormat(video.Streams()[d].PixFormat()));
        gloffsetscale.push_back(std::pair<float,float>(0.0f, 1.0f) );
    }

    int frame = 0;
    pangolin::Var<int>  max_frame("max_frame", total_frames );
    pangolin::Var<bool> linear_sampling("linear_sampling", true );

    std::vector<pangolin::Image<unsigned char> > images;

#ifdef CALLEE_HAS_CPP11
    const int FRAME_SKIP = 30;

    // Show/hide streams
    for(size_t v=0; v < pangolin::DisplayBase().NumChildren() && v < 9; v++) {
        pangolin::RegisterKeyPressCallback('1'+v, [v](){
            pangolin::DisplayBase()[v].ToggleShow();
        } );
    }

    pangolin::RegisterKeyPressCallback('r', [&](){
        if(!video.IsRecording()) {
            video.Record();
            pango_print_info("Started Recording.\n");
        }else{
            video.Stop();
            pango_print_info("Finished recording.\n");
        }
        fflush(stdout);
    });
    pangolin::RegisterKeyPressCallback('p', [&](){
        video.Play();
        max_frame = std::numeric_limits<int>::max();
        pango_print_info("Playing from file log.\n");
        fflush(stdout);
    });
    pangolin::RegisterKeyPressCallback('s', [&](){
        video.Source();
        max_frame = std::numeric_limits<int>::max();
        pango_print_info("Playing from source input.\n");
        fflush(stdout);
    });
    pangolin::RegisterKeyPressCallback(' ', [&](){
        max_frame = (frame < max_frame) ? frame : std::numeric_limits<int>::max();
    });
    pangolin::RegisterKeyPressCallback(pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_LEFT, [&](){
        if(video_playback) {
            const int frame = std::min(video_playback->GetCurrentFrameId()-FRAME_SKIP, video_playback->GetTotalFrames()-1);
            video_playback->Seek(frame);
        }else{
            // We can't go backwards
        }
    });
    pangolin::RegisterKeyPressCallback(pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_RIGHT, [&](){
        if(video_playback) {
            const int frame = std::max(video_playback->GetCurrentFrameId()+FRAME_SKIP, 0);
            video_playback->Seek(frame);
        }else{
            // Pause at this frame
            max_frame = frame+1;
        }
    });
    pangolin::RegisterKeyPressCallback('l', [&](){ linear_sampling = true; });
    pangolin::RegisterKeyPressCallback('n', [&](){ linear_sampling = false; });

    pangolin::RegisterKeyPressCallback('a', [&](){
        // Adapt scale
        for(unsigned int i=0; i<images.size(); ++i) {
            if(pangolin::DisplayBase()[i].HasFocus()) {
                std::pair<float,float> os(0.0f, 1.0f);
                if(glfmt[i].gltype == GL_UNSIGNED_BYTE) {
                    os = GetOffsetScale<unsigned char>(images[i], 255.0f, 1.0f);
                }else if(glfmt[i].gltype == GL_UNSIGNED_SHORT) {
                    os = GetOffsetScale<unsigned short>(images[i], 65535.0f, 1.0f);
                }else if(glfmt[i].gltype == GL_FLOAT) {
                    os = GetOffsetScale<float>(images[i], 1.0f, 1.0f);
                }
                gloffsetscale[i] = os;
            }
        }
    });
#endif

    // Stream and display video
    while(!pangolin::ShouldQuit())
    {
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
        glColor3f(1.0f, 1.0f, 1.0f);

        if (frame == 0 || frame < max_frame) {
            if (video.Grab(&buffer[0], images) ){
                ++frame;
            }
        }

        for(unsigned int i=0; i<images.size(); ++i)
        {
            if(pangolin::DisplayBase()[i].IsShown()) {
                pangolin::DisplayBase()[i].Activate();
                const std::pair<float,float> os = gloffsetscale[i];
                pangolin::GlSlUtilities::OffsetAndScale(os.first, os.second);
                pangolin::RenderToViewport(images[i], glfmt[i], false, true, linear_sampling);
                pangolin::GlSlUtilities::UseNone();
            }
        }

        pangolin::FinishFrame();
    }
}

int main( int argc, char* argv[] )
{
    const std::string dflt_output_uri = "pango://video.pango";

    if( argc > 1 ) {
        const std::string input_uri = std::string(argv[1]);
        const std::string output_uri = (argc > 2) ? std::string(argv[2]) : dflt_output_uri;
        try{
            VideoViewer(input_uri, output_uri);
        } catch (pangolin::VideoException e) {
            std::cout << e.what() << std::endl;
        }
    }else{
        const std::string input_uris[] = {
            "dc1394:[fps=30,dma=10,size=640x480,iso=400]//0",
            "convert:[fmt=RGB24]//v4l:///dev/video0",
            "convert:[fmt=RGB24]//v4l:///dev/video1",
            "openni:[img1=rgb]//",
            "test:[size=160x120,n=1,fmt=RGB24]//"
            ""
        };

        std::cout << "Usage  : VideoViewer [video-uri]" << std::endl << std::endl;
        std::cout << "Where video-uri describes a stream or file resource, e.g." << std::endl;
        std::cout << "\tfile:[realtime=1]///home/user/video/movie.pvn" << std::endl;
        std::cout << "\tfile:///home/user/video/movie.avi" << std::endl;
        std::cout << "\tfiles:///home/user/seqiemce/foo%03d.jpeg" << std::endl;
        std::cout << "\tdc1394:[fmt=RGB24,size=640x480,fps=30,iso=400,dma=10]//0" << std::endl;
        std::cout << "\tdc1394:[fmt=FORMAT7_1,size=640x480,pos=2+2,iso=400,dma=10]//0" << std::endl;
        std::cout << "\tv4l:///dev/video0" << std::endl;
        std::cout << "\tconvert:[fmt=RGB24]//v4l:///dev/video0" << std::endl;
        std::cout << "\tmjpeg://http://127.0.0.1/?action=stream" << std::endl;
        std::cout << "\topenni:[img1=rgb]//" << std::endl;
        std::cout << std::endl;

        // Try to open some video device
        for(int i=0; !input_uris[i].empty(); ++i )
        {
            try{
                pango_print_info("Trying: %s\n", input_uris[i].c_str());
                VideoViewer(input_uris[i], dflt_output_uri);
                return 0;
            }catch(pangolin::VideoException) { }
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "ex13_42_TextQuery.h"
#include <sstream>
#include <algorithm>

using std::string;

TextQuery::TextQuery(std::ifstream& ifs) : input(new StrVec)
{
    size_t lineNo = 0;
    for (string line; std::getline(ifs, line); ++lineNo) {
        input->push_back(line);
        std::istringstream line_stream(line);
        for (string text, word; line_stream >> text; word.clear()) {
            // avoid read a word followed by punctuation(such as: word, )
            std::remove_copy_if(text.begin(), text.end(),
                                std::back_inserter(word), ispunct);
            // use reference avoid count of shared_ptr add.
            auto& nos = result[word];
            if (!nos) nos.reset(new std::set<size_t>);
            nos->insert(lineNo);
        }
    }
}

QueryResult TextQuery::query(const string& str) const
{
    // use static just allocate once.
    static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
    auto found = result.find(str);
    if (found == result.end())
        return QueryResult(str, nodate, input);
    else
        return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
    out << qr.word << " occurs " << qr.nos->size()
        << (qr.nos->size() > 1 ? " times" : " time") << std::endl;
    for (auto i : *qr.nos)
        out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl;
    return out;
}
<commit_msg>Update ex13_42_TextQuery.cpp<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstddef>
#include <algorithm>
#include <iterator>
#include <cctype>
#include "ex13_40.h"
#include "ex12_27_30.h"

using namespace std;

TextQuery::TextQuery(ifstream &is):file(new StrVec)
{
    string line;
    while(getline(is, line))
    {
        file->push_back(line);
        int n=file->size()-1;
        istringstream in(line);
        string text, word;
        while(in>>text)
        {
            //avoid read a word followed by punctuation(such as: word,)
            remove_copy_if(text.begin(), text.end(), back_inserter(word), [](const char &ch) {return ispunct(ch);});
            auto &lines=wm[word];
            if(!lines)
                lines.reset(new set<size_t>);
            lines->insert(n);
            word.clear();
        }
    }
}

QueryResult TextQuery::query(const string &sought) const
{
    //use static just allocate once
    static shared_ptr<set<size_t>> nodata(new set<size_t>);

    auto loc=wm.find(sought);
    if(loc==wm.end())
        return QueryResult(sought, nodata, file);
    else
        return QueryResult(sought, loc->second, file);
}

ostream &print(ostream &os, const QueryResult &qr)
{
    os<<qr.sought<<" occurs "<<qr.lines->size()<<(qr.lines->size()>1 ? " times" : " time")<<endl;
    for(auto num : *qr.lines)
        os<<"\t(line "<<num+1<<") "<<qr.file->at(num)<<endl;
    return os;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 */

#include "QXmppElement.h"
#include "QXmppUtils.h"

#include <QDomElement>

class QXmppElementPrivate
{
public:
    QXmppElementPrivate();
    QXmppElementPrivate(const QDomElement &element);
    ~QXmppElementPrivate();

    QAtomicInt counter;

    QXmppElementPrivate *parent;
    QMap<QString, QString> attributes;
    QList<QXmppElementPrivate*> children;
    QString name;
    QString value;
};

QXmppElementPrivate::QXmppElementPrivate()
    : counter(1), parent(NULL)
{
}

QXmppElementPrivate::QXmppElementPrivate(const QDomElement &element)
    : counter(1), parent(NULL)
{
    if (element.isNull())
        return;

    name = element.tagName();
    QString xmlns = element.namespaceURI();
    QString parentns = element.parentNode().namespaceURI();
    if (!xmlns.isEmpty() && xmlns != parentns)
        attributes.insert("xmlns", xmlns);
    QDomNamedNodeMap attrs = element.attributes();
    for (int i = 0; i < attrs.size(); i++)
    {
        QDomAttr attr = attrs.item(i).toAttr();
        attributes.insert(attr.name(), attr.value());
    }

    QDomNode childNode = element.firstChild();
    while (!childNode.isNull())
    {
        if (childNode.isElement())
        {
            QXmppElementPrivate *child = new QXmppElementPrivate(childNode.toElement());
            child->parent = this;
            children.append(child);
        } else if (childNode.isText()) {
            value += childNode.toText().data();
        }
        childNode = childNode.nextSibling();
    }
}

QXmppElementPrivate::~QXmppElementPrivate()
{
    foreach (QXmppElementPrivate *child, children)
        if (!child->counter.deref())
            delete child;
}

QXmppElement::QXmppElement()
{
    d = new QXmppElementPrivate();
}

QXmppElement::QXmppElement(const QXmppElement &other)
{
    other.d->counter.ref();
    d = other.d;
}

QXmppElement::QXmppElement(QXmppElementPrivate *other)
{
    other->counter.ref();
    d = other;
}

QXmppElement::QXmppElement(const QDomElement &element)
{
    d = new QXmppElementPrivate(element);
}

QXmppElement::~QXmppElement()
{
    if (!d->counter.deref())
        delete d;
}

QXmppElement &QXmppElement::operator=(const QXmppElement &other)
{
    other.d->counter.ref();
    if (!d->counter.deref())
        delete d;
    d = other.d;
    return *this;
}

QStringList QXmppElement::attributeNames() const
{
    return d->attributes.keys();
}

QString QXmppElement::attribute(const QString &name) const
{
    return d->attributes.value(name);
}

void QXmppElement::setAttribute(const QString &name, const QString &value)
{
    d->attributes.insert(name, value);
}

void QXmppElement::appendChild(const QXmppElement &child)
{
    if (child.d->parent == d)
        return;

    if (child.d->parent)
        child.d->parent->children.removeAll(child.d);
    else
        child.d->counter.ref();
    d->children.append(child.d);
}

QXmppElement QXmppElement::firstChildElement(const QString &name) const
{
    foreach (QXmppElementPrivate *child_d, d->children)
        if (name.isEmpty() || child_d->name == name)
            return QXmppElement(child_d);
    return QXmppElement();
}

QXmppElement QXmppElement::nextSiblingElement(const QString &name) const
{
    if (!d->parent)
        return QXmppElement();
    const QList<QXmppElementPrivate*> &siblings_d = d->parent->children;
    for (int i = siblings_d.indexOf(d) + 1; i < siblings_d.size(); i++)
        if (name.isEmpty() || siblings_d[i]->name == name)
            return QXmppElement(siblings_d[i]);
    return QXmppElement();
}

bool QXmppElement::isNull() const
{
    return d->name.isEmpty();
}

void QXmppElement::removeChild(const QXmppElement &child)
{
    if (child.d->parent != d)
        return;

    d->children.removeAll(child.d);
    child.d->counter.deref();
    child.d->parent = NULL;
}

QString QXmppElement::tagName() const
{
    return d->name;
}

void QXmppElement::setTagName(const QString &tagName)
{
    d->name = tagName;
}

QString QXmppElement::value() const
{
    return d->value;
}

void QXmppElement::setValue(const QString &value)
{
    d->value = value;
}

void QXmppElement::toXml(QXmlStreamWriter *writer) const
{
    if (isNull())
        return;

    writer->writeStartElement(d->name);
    if (d->attributes.contains("xmlns"))
        helperToXmlAddAttribute(writer, "xmlns", d->attributes.value("xmlns"));
    foreach (const QString &attr, d->attributes.keys())
        if (attr != "xmlns")
            helperToXmlAddAttribute(writer, attr, d->attributes.value(attr));
    if (!d->value.isEmpty())
        writer->writeCharacters(d->value);
    foreach (const QXmppElement &child, d->children)
        child.toXml(writer);
    writer->writeEndElement();
}

QXmppElementList::QXmppElementList()
{
}

QXmppElementList::QXmppElementList(const QXmppElement &element)
{
    append(element);
}

QXmppElementList::QXmppElementList(const QList<QXmppElement> &other)
    : QList<QXmppElement>(other)
{
}

<commit_msg>fix QXmppElement parenting so that nextSiblingElement() actually works<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 */

#include "QXmppElement.h"
#include "QXmppUtils.h"

#include <QDomElement>

class QXmppElementPrivate
{
public:
    QXmppElementPrivate();
    QXmppElementPrivate(const QDomElement &element);
    ~QXmppElementPrivate();

    QAtomicInt counter;

    QXmppElementPrivate *parent;
    QMap<QString, QString> attributes;
    QList<QXmppElementPrivate*> children;
    QString name;
    QString value;
};

QXmppElementPrivate::QXmppElementPrivate()
    : counter(1), parent(NULL)
{
}

QXmppElementPrivate::QXmppElementPrivate(const QDomElement &element)
    : counter(1), parent(NULL)
{
    if (element.isNull())
        return;

    name = element.tagName();
    QString xmlns = element.namespaceURI();
    QString parentns = element.parentNode().namespaceURI();
    if (!xmlns.isEmpty() && xmlns != parentns)
        attributes.insert("xmlns", xmlns);
    QDomNamedNodeMap attrs = element.attributes();
    for (int i = 0; i < attrs.size(); i++)
    {
        QDomAttr attr = attrs.item(i).toAttr();
        attributes.insert(attr.name(), attr.value());
    }

    QDomNode childNode = element.firstChild();
    while (!childNode.isNull())
    {
        if (childNode.isElement())
        {
            QXmppElementPrivate *child = new QXmppElementPrivate(childNode.toElement());
            child->parent = this;
            children.append(child);
        } else if (childNode.isText()) {
            value += childNode.toText().data();
        }
        childNode = childNode.nextSibling();
    }
}

QXmppElementPrivate::~QXmppElementPrivate()
{
    foreach (QXmppElementPrivate *child, children)
        if (!child->counter.deref())
            delete child;
}

QXmppElement::QXmppElement()
{
    d = new QXmppElementPrivate();
}

QXmppElement::QXmppElement(const QXmppElement &other)
{
    other.d->counter.ref();
    d = other.d;
}

QXmppElement::QXmppElement(QXmppElementPrivate *other)
{
    other->counter.ref();
    d = other;
}

QXmppElement::QXmppElement(const QDomElement &element)
{
    d = new QXmppElementPrivate(element);
}

QXmppElement::~QXmppElement()
{
    if (!d->counter.deref())
        delete d;
}

QXmppElement &QXmppElement::operator=(const QXmppElement &other)
{
    other.d->counter.ref();
    if (!d->counter.deref())
        delete d;
    d = other.d;
    return *this;
}

QStringList QXmppElement::attributeNames() const
{
    return d->attributes.keys();
}

QString QXmppElement::attribute(const QString &name) const
{
    return d->attributes.value(name);
}

void QXmppElement::setAttribute(const QString &name, const QString &value)
{
    d->attributes.insert(name, value);
}

void QXmppElement::appendChild(const QXmppElement &child)
{
    if (child.d->parent == d)
        return;

    if (child.d->parent)
        child.d->parent->children.removeAll(child.d);
    else
        child.d->counter.ref();
    child.d->parent = d;
    d->children.append(child.d);
}

QXmppElement QXmppElement::firstChildElement(const QString &name) const
{
    foreach (QXmppElementPrivate *child_d, d->children)
        if (name.isEmpty() || child_d->name == name)
            return QXmppElement(child_d);
    return QXmppElement();
}

QXmppElement QXmppElement::nextSiblingElement(const QString &name) const
{
    if (!d->parent)
        return QXmppElement();
    const QList<QXmppElementPrivate*> &siblings_d = d->parent->children;
    for (int i = siblings_d.indexOf(d) + 1; i < siblings_d.size(); i++)
        if (name.isEmpty() || siblings_d[i]->name == name)
            return QXmppElement(siblings_d[i]);
    return QXmppElement();
}

bool QXmppElement::isNull() const
{
    return d->name.isEmpty();
}

void QXmppElement::removeChild(const QXmppElement &child)
{
    if (child.d->parent != d)
        return;

    d->children.removeAll(child.d);
    child.d->counter.deref();
    child.d->parent = NULL;
}

QString QXmppElement::tagName() const
{
    return d->name;
}

void QXmppElement::setTagName(const QString &tagName)
{
    d->name = tagName;
}

QString QXmppElement::value() const
{
    return d->value;
}

void QXmppElement::setValue(const QString &value)
{
    d->value = value;
}

void QXmppElement::toXml(QXmlStreamWriter *writer) const
{
    if (isNull())
        return;

    writer->writeStartElement(d->name);
    if (d->attributes.contains("xmlns"))
        helperToXmlAddAttribute(writer, "xmlns", d->attributes.value("xmlns"));
    foreach (const QString &attr, d->attributes.keys())
        if (attr != "xmlns")
            helperToXmlAddAttribute(writer, attr, d->attributes.value(attr));
    if (!d->value.isEmpty())
        writer->writeCharacters(d->value);
    foreach (const QXmppElement &child, d->children)
        child.toXml(writer);
    writer->writeEndElement();
}

QXmppElementList::QXmppElementList()
{
}

QXmppElementList::QXmppElementList(const QXmppElement &element)
{
    append(element);
}

QXmppElementList::QXmppElementList(const QList<QXmppElement> &other)
    : QList<QXmppElement>(other)
{
}

<|endoftext|>


<commit_before>/*
	Copyright (C) 2015-2016 Claude SIMON (http://q37.info/contact/).

	This file is part of dmnzq.

    dmnzq is free software: you can redistribute it and/or
	modify it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

    dmnzq 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
	Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with dmnzq.  If not, see <http://www.gnu.org/licenses/>
*/

#include "misc.h"

#include "registry.h"

#include "scltool.h"
#include "sclerror.h"

#include "csdlec.h"

#include "err.h"
#include "cio.h"
#include "epsmsc.h"
#include "xpp.h"
#include "fnm.h"
#include "flf.h"
#include "plgn.h"

using cio::CErr;
using cio::COut;
using cio::CIn;

# define NAME_MC			"dmnzq"
# define NAME_LC			"dmnzq"
# define NAME_UC			"DMNZQ"
# define WEBSITE_URL		"http://q37.info/"
# define AUTHOR_NAME		"Claude SIMON"
# define AUTHOR_CONTACT		"http://q37.info/contact/"
# define OWNER_NAME			"Claude SIMON"
# define OWNER_CONTACT		"http://q37.info/contact/"
# define COPYRIGHT			COPYRIGHT_YEARS " " OWNER_NAME " (" OWNER_CONTACT ")"

static void PrintHeader_( void )
{
	COut << NAME_MC " V" VERSION << " (" WEBSITE_URL ")" << txf::nl;
	COut << "Copyright (C) " COPYRIGHT << txf::nl;
	COut << txf::pad << "Build : " __DATE__ " " __TIME__ << " (" << cpe::GetDescription() << ')' << txf::nl;
}

namespace {
	using misc::sModule;

	csdlec::library_embedded_client_core__ *Core_ = NULL;

	void ExitFunction_( void )
	{
	qRH
		str::string Message;
	qRB
		if ( Core_ != NULL ) {
			Message.Init();
			COut << sclmisc::GetBaseTranslation( "TerminatingModule", Message ) << txf::nl << txf::commit;
			delete Core_;
			COut << sclmisc::GetBaseTranslation( "ModuleTerminated", Message ) << txf::nl << txf::commit;
		}

		Core_ = NULL;
	qRR
	qRT
	qRE
	}

	void LoadModule_( const bso::char__ *ModuleFilename )
	{
	qRH
		lcl::locale SharedLocale;
		rgstry::registry SharedRegistry;
		csdlec::library_data__ LibraryData;
		lcl::meaning Meaning, MeaningBuffer;
		str::string Translation;
		err::buffer__ ErrBuffer;
		sclmisc::sRack SCLRack;
	qRB
		SharedLocale.Init();
		SharedRegistry.Init();

		SCLRack.Init( *err::qRRor, *sclerror::SCLERRORError, cio::GetCurrentSet(), scllocale::GetRack() );

		LibraryData.Init( csdleo::cRegular, ModuleFilename, &SCLRack, csdleo::mRemote );

		if ( ( Core_ = new csdlec::library_embedded_client_core__ ) == NULL )
			qRAlc();

		if ( !Core_->Init( ModuleFilename, LibraryData, err::hUserDefined ) ) {
			Meaning.Init();
			Meaning.SetValue( "UnableToLoadModule" );
			Meaning.AddTag( ModuleFilename );
			sclerror::SetMeaning( Meaning );
			qRAbort();
		}
	qRR
		Meaning.Init();
		Meaning.SetValue( "ModuleError" );
		Meaning.AddTag( ModuleFilename );

		if ( ERRType >= err::t_amount ) {
			if ( sclerror::IsErrorPending() ) {
				MeaningBuffer.Init();
				Meaning.AddTag( sclerror::GetMeaning( MeaningBuffer ) );
			} else {
				Translation.Init();
				Meaning.AddTag( sclmisc::GetBaseTranslation( "UnkonwnError", Translation ) );
			}
		} else {
			Meaning.AddTag( err::Message( ErrBuffer ) );
		}

		Translation.Init();
		sclmisc::GetBaseTranslation( Meaning, Translation );

		cio::CErr << Translation << txf::nl << txf::commit;
	qRT
	qRE
	}

	using misc::cHandler;

	void Process_(
		cHandler &Handler,
		sModule &Module )
	{
		Handler.Handle( Module );
	}

	void Process_( misc::sModule &Module )
	{
	qRH
		plgn::rRetriever<cHandler> Retriever;
		str::wString PluginId, PluginArguments;
	qRB
		PluginId.Init();
		PluginArguments.Init();
		Module.Preferences( PluginId, PluginArguments );

		Retriever.Init();

		sclmisc::Plug( misc::SlotPluginTarget, PluginId, PluginArguments, NULL, Retriever );

		Process_( Retriever.Plugin(), Module );
	qRR
	qRT
	qRE
	}

	void Process_( void )
	{
	qRH
		TOL_CBUFFER___ Buffer;
	qRB
		atexit( ExitFunction_ );

		cio::COut.Commit();

		LoadModule_( sclmisc::MGetValue( registry::Module, Buffer ) );

		Process_( Core_->GetCallback() );
	qRR
	qRT
	qRE
	}

	void AboutPlugin_( void )
	{
	qRH
		plgn::rRetriever<cHandler> Retriever;
	qRB
		Retriever.Init();

		sclmisc::Plug( misc::SlotPluginTarget, NULL, Retriever );

		cio::COut << Retriever.About() << txf::nl << Retriever.Identifier() << txf::commit;
	qRR
	qRT
	qRE
	}
}

#define C( name )\
	else if ( Command == #name )\
		name##_()

int scltool::SCLTOOLMain(
	const str::string_ &Command,
	const scltool::oddities__ &Oddities )
{
	int ExitValue = EXIT_FAILURE;
qRH
qRB
	if ( Command == "Version" )
		PrintHeader_();
	else if ( Command == "License" )
		epsmsc::PrintLicense( NAME_MC );
	C( Process );
	C( AboutPlugin );
	else
		qRGnr();

	ExitValue = EXIT_SUCCESS;
qRR
qRT
qRE
	return ExitValue;
}

#undef C

const char *sclmisc::SCLMISCTargetName = NAME_LC;

Q37_GCTOR( dmnzq )
{
}<commit_msg>27/03/2016 11:40:43<commit_after>/*
	Copyright (C) 2015-2016 Claude SIMON (http://q37.info/contact/).

	This file is part of dmnzq.

    dmnzq is free software: you can redistribute it and/or
	modify it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

    dmnzq 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
	Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with dmnzq.  If not, see <http://www.gnu.org/licenses/>
*/

#include "misc.h"

#include "registry.h"

#include "scltool.h"
#include "sclerror.h"

#include "csdlec.h"

#include "err.h"
#include "cio.h"
#include "epsmsc.h"
#include "xpp.h"
#include "fnm.h"
#include "flf.h"
#include "plgn.h"

using cio::CErr;
using cio::COut;
using cio::CIn;

# define NAME_MC			"dmnzq"
# define NAME_LC			"dmnzq"
# define NAME_UC			"DMNZQ"
# define WEBSITE_URL		"http://q37.info/"
# define AUTHOR_NAME		"Claude SIMON"
# define AUTHOR_CONTACT		"http://q37.info/contact/"
# define OWNER_NAME			"Claude SIMON"
# define OWNER_CONTACT		"http://q37.info/contact/"
# define COPYRIGHT			COPYRIGHT_YEARS " " OWNER_NAME " (" OWNER_CONTACT ")"

static void PrintHeader_( void )
{
	COut << NAME_MC " V" VERSION << " (" WEBSITE_URL ")" << txf::nl;
	COut << "Copyright (C) " COPYRIGHT << txf::nl;
	COut << txf::pad << "Build : " __DATE__ " " __TIME__ << " (" << cpe::GetDescription() << ')' << txf::nl;
}

namespace {
	using misc::sModule;

	csdlec::library_embedded_client_core__ *Core_ = NULL;

	void ExitFunction_( void )
	{
	qRH
		str::string Message;
	qRB
		if ( Core_ != NULL ) {
			Message.Init();
			COut << sclmisc::GetBaseTranslation( "TerminatingModule", Message ) << txf::nl << txf::commit;
			delete Core_;
			COut << sclmisc::GetBaseTranslation( "ModuleTerminated", Message ) << txf::nl << txf::commit;
		}

		Core_ = NULL;
	qRR
	qRT
	qRE
	}

	void LoadModule_( const bso::char__ *ModuleFilename )
	{
	qRH
		lcl::locale SharedLocale;
		rgstry::registry SharedRegistry;
		csdlec::library_data__ LibraryData;
		lcl::meaning Meaning, MeaningBuffer;
		str::string Translation;
		err::buffer__ ErrBuffer;
		sclmisc::sRack SCLRack;
	qRB
		SharedLocale.Init();
		SharedRegistry.Init();

		SCLRack.Init( *err::qRRor, *sclerror::SCLERRORError, cio::GetCurrentSet(), scllocale::GetRack() );

		LibraryData.Init( csdleo::cRegular, ModuleFilename, &SCLRack, csdleo::mRemote );

		if ( ( Core_ = new csdlec::library_embedded_client_core__ ) == NULL )
			qRAlc();

		if ( !Core_->Init( ModuleFilename, LibraryData, err::hUserDefined ) ) {
			Meaning.Init();
			Meaning.SetValue( "UnableToLoadModule" );
			Meaning.AddTag( ModuleFilename );
			sclerror::SetMeaning( Meaning );
			qRAbort();
		}
	qRR
		Meaning.Init();
		Meaning.SetValue( "ModuleError" );
		Meaning.AddTag( ModuleFilename );

		if ( ERRType >= err::t_amount ) {
			if ( sclerror::IsErrorPending() ) {
				MeaningBuffer.Init();
				Meaning.AddTag( sclerror::GetMeaning( MeaningBuffer ) );
			} else {
				Translation.Init();
				Meaning.AddTag( sclmisc::GetBaseTranslation( "UnkonwnError", Translation ) );
			}
		} else {
			Meaning.AddTag( err::Message( ErrBuffer ) );
		}

		Translation.Init();
		sclmisc::GetBaseTranslation( Meaning, Translation );

		cio::CErr << Translation << txf::nl << txf::commit;
	qRT
	qRE
	}

	using misc::cHandler;

	void Process_(
		cHandler &Handler,
		sModule &Module )
	{
		Handler.Handle( Module );
	}

	void Process_( misc::sModule &Module )
	{
	qRH
		plgn::rRetriever<cHandler> Retriever;
		str::wString PluginId, PluginArguments;
	qRB
		PluginId.Init();
		PluginArguments.Init();
		Module.Preferences( PluginId, PluginArguments );

		Retriever.Init();

		sclmisc::Plug( misc::SlotPluginTarget, PluginId, PluginArguments, NULL, Retriever );

		Process_( Retriever.Plugin(), Module );
	qRR
	qRT
	qRE
	}

	void Process_( void )
	{
	qRH
		TOL_CBUFFER___ Buffer;
	qRB
		atexit( ExitFunction_ );

		cio::COut.Commit();

		LoadModule_( sclmisc::MGetValue( registry::Module, Buffer ) );

		Process_( Core_->GetCallback() );
	qRR
	qRT
	qRE
	}

	void AboutPlugin_( void )
	{
	qRH
		plgn::rRetriever<cHandler> Retriever;
	qRB
		Retriever.Init();

		sclmisc::Plug( misc::SlotPluginTarget, NULL, Retriever );

		cio::COut << Retriever.Details() << txf::nl << Retriever.Identifier() << txf::commit;
	qRR
	qRT
	qRE
	}
}

#define C( name )\
	else if ( Command == #name )\
		name##_()

int scltool::SCLTOOLMain(
	const str::string_ &Command,
	const scltool::oddities__ &Oddities )
{
	int ExitValue = EXIT_FAILURE;
qRH
qRB
	if ( Command == "Version" )
		PrintHeader_();
	else if ( Command == "License" )
		epsmsc::PrintLicense( NAME_MC );
	C( Process );
	C( AboutPlugin );
	else
		qRGnr();

	ExitValue = EXIT_SUCCESS;
qRR
qRT
qRE
	return ExitValue;
}

#undef C

const char *sclmisc::SCLMISCTargetName = NAME_LC;

Q37_GCTOR( dmnzq )
{
}<|endoftext|>


<commit_before>// This file is part of the "x0" project
//   (c) 2009-2014 Christian Parpart <trapni@gmail.com>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/RuntimeError.h>
#include <xzero/Tokenizer.h>
#include <xzero/Buffer.h>
#include <xzero/sysconfig.h>
#include <typeinfo>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>

#if defined(HAVE_EXECINFO_H)
#include <execinfo.h>
#endif

#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
#endif

namespace xzero {

#define MAX_FRAMES 64
#define SKIP_FRAMES 2

class Pipe { // {{{
 private:
  Pipe(const Pipe&) = delete;
  Pipe& operator=(Pipe&) = delete;

 public:
  Pipe();
  Pipe(Pipe&& other);
  Pipe& operator=(Pipe&& other);
  ~Pipe();

  int readFd() const noexcept { return pfd_[0]; }
  int writeFd() const noexcept { return pfd_[1]; }

  void close();
  void closeRead();
  void closeWrite();

 private:
  int pfd_[2];
};

Pipe::Pipe() {
#if defined(HAVE_PIPE2)
  int rv = pipe2(pfd_, O_CLOEXEC);
#else
  int rv = pipe(pfd_);
#endif
  if (rv < 0) {
    throw RUNTIME_ERROR(strerror(errno)); // FIXME: not thread safe
  }
}

Pipe::Pipe(Pipe&& other) {
  pfd_[0] = other.pfd_[0];
  pfd_[1] = other.pfd_[1];

  other.pfd_[0] = -1;
  other.pfd_[1] = -1;
}

Pipe& Pipe::operator=(Pipe&& other) {
  pfd_[0] = other.pfd_[0];
  pfd_[1] = other.pfd_[1];

  other.pfd_[0] = -1;
  other.pfd_[1] = -1;

  return *this;
}

Pipe::~Pipe() {
  close();
}

void Pipe::close() {
  closeRead();
  closeWrite();
}

void Pipe::closeRead() {
  if (readFd() >= 0)
    ::close(readFd());
}

void Pipe::closeWrite() {
  if (writeFd() >= 0)
    ::close(writeFd());
}
// }}}

std::string demangleSymbol(const char* symbol) {
  return symbol; // TODO: __cxa_demangle()
}

void consoleLogger(const std::exception& e) {
  if (auto rt = dynamic_cast<const RuntimeError*>(&e)) {
    fprintf(stderr, "Unhandled exception caught in executor [%s:%d] (%s): %s\n",
            rt->sourceFile(), rt->sourceLine(),
            demangleSymbol(typeid(e).name()).c_str(),
            rt->what());
    auto bt = rt->backtrace();
    for (size_t i = 0; i < bt.size(); ++i)
      fprintf(stderr, "  [%zu] %s\n", i, bt[i].c_str());
    return;
  }

  fprintf(stderr, "Unhandled exception caught in executor (%s): %s\n",
          demangleSymbol(typeid(e).name()).c_str(), e.what());
}

RuntimeError::RuntimeError(const std::string& what,
                           const char* sourceFile,
                           int sourceLine)
  : std::runtime_error(what),
    sourceFile_(sourceFile),
    sourceLine_(sourceLine),
#if defined(HAVE_BACKTRACE)
    frames_(MAX_FRAMES ? new void*[SKIP_FRAMES + MAX_FRAMES] : nullptr),
    frameCount_(MAX_FRAMES ? ::backtrace(frames_, SKIP_FRAMES + MAX_FRAMES) : 0)
#else
    frames_(nullptr),
    frameCount_(0)
#endif
{
}

RuntimeError::~RuntimeError() {
  delete[] frames_;
}

std::vector<std::string> RuntimeError::backtrace() const {
#if defined(HAVE_DLFCN_H) && defined(HAVE_DUP2) && defined(HAVE_FORK)
  if (!frameCount_ || !frames_)
    return {};

  std::vector<std::string> output;

  Buffer rawFramesText;
  for (int i = SKIP_FRAMES; i <= frameCount_; ++i) {
    Dl_info info;
    if (dladdr(frames_[i], &info)) {
      char buf[512];
      int n = snprintf(buf, sizeof(buf), "%s %p", info.dli_fname, frames_[i]);
      rawFramesText.push_back(buf, n);
      rawFramesText.push_back('\n');
      output.push_back(buf);
    }
  }

  Pipe fin;
  Pipe fout;

  std::string symbolizerPath = "/usr/bin/llvm-symbolizer";
  if (const char* p = getenv("SYMBOLIZER"))
    symbolizerPath = p;

  pid_t pid = fork();
  if (pid < 0) {
    // error
    return output;
  } else if (pid == 0) {
    // child
    dup2(fin.readFd(), STDIN_FILENO);
    dup2(fout.writeFd(), STDOUT_FILENO);
    dup2(fout.writeFd(), STDERR_FILENO);
    fin.close();
    fout.close();

    execl(symbolizerPath.c_str(), symbolizerPath.c_str(), nullptr);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    abort();
  } else {
    // parent
    fin.closeRead();
    fout.closeWrite();

    write(fin.writeFd(), rawFramesText.data(), rawFramesText.size());
    fin.closeWrite();

    Buffer symbolizerOutput;
    char chunk[1024];
    for (;;) {
      int n = read(fout.readFd(), chunk, sizeof(chunk));
      if (n <= 0)
        break;
      symbolizerOutput.push_back(chunk, n);
    }

    int status = 0;
    waitpid(pid, &status, 0);

    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
      // symbolizer failed. return raw output.
      return output;

    if (symbolizerOutput.empty())
      // symbolizer returned nothing
      return output;

    output.clear();
    auto lines = Tokenizer<BufferRef>::tokenize(symbolizerOutput.ref(), "\n");
    for (size_t i = 0; i + 1 < lines.size(); i += 2) {
      Buffer buf;
      buf.push_back(lines[i]);
      buf.push_back(" in ");
      buf.push_back(lines[i + 1]);
      output.push_back(buf.str());
    }
    return output;
  }
#else
  return {};
#endif
}

} // namespace xzero
<commit_msg>RuntimeError: make fallback backtrace output slightly more readable<commit_after>// This file is part of the "x0" project
//   (c) 2009-2014 Christian Parpart <trapni@gmail.com>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/RuntimeError.h>
#include <xzero/Tokenizer.h>
#include <xzero/Buffer.h>
#include <xzero/sysconfig.h>
#include <typeinfo>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>

#if defined(HAVE_EXECINFO_H)
#include <execinfo.h>
#endif

#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
#endif

namespace xzero {

#define MAX_FRAMES 64
#define SKIP_FRAMES 2

class Pipe { // {{{
 private:
  Pipe(const Pipe&) = delete;
  Pipe& operator=(Pipe&) = delete;

 public:
  Pipe();
  Pipe(Pipe&& other);
  Pipe& operator=(Pipe&& other);
  ~Pipe();

  int readFd() const noexcept { return pfd_[0]; }
  int writeFd() const noexcept { return pfd_[1]; }

  void close();
  void closeRead();
  void closeWrite();

 private:
  int pfd_[2];
};

Pipe::Pipe() {
#if defined(HAVE_PIPE2)
  int rv = pipe2(pfd_, O_CLOEXEC);
#else
  int rv = pipe(pfd_);
#endif
  if (rv < 0) {
    throw RUNTIME_ERROR(strerror(errno)); // FIXME: not thread safe
  }
}

Pipe::Pipe(Pipe&& other) {
  pfd_[0] = other.pfd_[0];
  pfd_[1] = other.pfd_[1];

  other.pfd_[0] = -1;
  other.pfd_[1] = -1;
}

Pipe& Pipe::operator=(Pipe&& other) {
  pfd_[0] = other.pfd_[0];
  pfd_[1] = other.pfd_[1];

  other.pfd_[0] = -1;
  other.pfd_[1] = -1;

  return *this;
}

Pipe::~Pipe() {
  close();
}

void Pipe::close() {
  closeRead();
  closeWrite();
}

void Pipe::closeRead() {
  if (readFd() >= 0)
    ::close(readFd());
}

void Pipe::closeWrite() {
  if (writeFd() >= 0)
    ::close(writeFd());
}
// }}}

std::string demangleSymbol(const char* symbol) {
  return symbol; // TODO: __cxa_demangle()
}

void consoleLogger(const std::exception& e) {
  if (auto rt = dynamic_cast<const RuntimeError*>(&e)) {
    fprintf(stderr, "Unhandled exception caught in executor [%s:%d] (%s): %s\n",
            rt->sourceFile(), rt->sourceLine(),
            demangleSymbol(typeid(e).name()).c_str(),
            rt->what());
    auto bt = rt->backtrace();
    for (size_t i = 0; i < bt.size(); ++i)
      fprintf(stderr, "  [%zu] %s\n", i, bt[i].c_str());
    return;
  }

  fprintf(stderr, "Unhandled exception caught in executor (%s): %s\n",
          demangleSymbol(typeid(e).name()).c_str(), e.what());
}

RuntimeError::RuntimeError(const std::string& what,
                           const char* sourceFile,
                           int sourceLine)
  : std::runtime_error(what),
    sourceFile_(sourceFile),
    sourceLine_(sourceLine),
#if defined(HAVE_BACKTRACE)
    frames_(MAX_FRAMES ? new void*[SKIP_FRAMES + MAX_FRAMES] : nullptr),
    frameCount_(MAX_FRAMES ? ::backtrace(frames_, SKIP_FRAMES + MAX_FRAMES) : 0)
#else
    frames_(nullptr),
    frameCount_(0)
#endif
{
}

RuntimeError::~RuntimeError() {
  delete[] frames_;
}

std::vector<std::string> RuntimeError::backtrace() const {
#if defined(HAVE_DLFCN_H) && defined(HAVE_DUP2) && defined(HAVE_FORK)
  if (!frameCount_ || !frames_)
    return {};

  std::vector<std::string> output;

  Buffer rawFramesText;
  for (int i = SKIP_FRAMES; i <= frameCount_; ++i) {
    Dl_info info;
    if (dladdr(frames_[i], &info)) {
      char buf[512];
      int n = snprintf(buf, sizeof(buf), "%s %p", info.dli_fname, frames_[i]);
      rawFramesText.push_back(buf, n);
      rawFramesText.push_back('\n');

      if (info.dli_sname)
        n = snprintf(buf, sizeof(buf), "%s", info.dli_sname);
      else
        n = snprintf(buf, sizeof(buf), "%p %s", frames_[i], info.dli_fname);

      output.push_back(std::string(buf, n));
    }
  }

  Pipe fin;
  Pipe fout;

  std::string symbolizerPath = "/usr/bin/llvm-symbolizer";
  if (const char* p = getenv("SYMBOLIZER"))
    symbolizerPath = p;

  pid_t pid = fork();
  if (pid < 0) {
    // error
    return output;
  } else if (pid == 0) {
    // child
    dup2(fin.readFd(), STDIN_FILENO);
    dup2(fout.writeFd(), STDOUT_FILENO);
    dup2(fout.writeFd(), STDERR_FILENO);
    fin.close();
    fout.close();

    execl(symbolizerPath.c_str(), symbolizerPath.c_str(), nullptr);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    abort();
  } else {
    // parent
    fin.closeRead();
    fout.closeWrite();

    write(fin.writeFd(), rawFramesText.data(), rawFramesText.size());
    fin.closeWrite();

    Buffer symbolizerOutput;
    char chunk[1024];
    for (;;) {
      int n = read(fout.readFd(), chunk, sizeof(chunk));
      if (n <= 0)
        break;
      symbolizerOutput.push_back(chunk, n);
    }

    int status = 0;
    waitpid(pid, &status, 0);

    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
      // symbolizer failed. return raw output.
      return output;

    if (symbolizerOutput.empty())
      // symbolizer returned nothing
      return output;

    output.clear();
    auto lines = Tokenizer<BufferRef>::tokenize(symbolizerOutput.ref(), "\n");
    for (size_t i = 0; i + 1 < lines.size(); i += 2) {
      Buffer buf;
      buf.push_back(lines[i]);
      buf.push_back(" in ");
      buf.push_back(lines[i + 1]);
      output.push_back(buf.str());
    }
    return output;
  }
#else
  return {};
#endif
}

} // namespace xzero
<|endoftext|>