<commit_before>#include "Halide.h"

using namespace Halide;

#include <image_io.h>

#include <iostream>
#include <limits>

#include <sys/time.h>

using std::vector;

double now() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    static bool first_call = true;
    static time_t first_sec = 0;
    if (first_call) {
        first_call = false;
        first_sec = tv.tv_sec;
    }
    assert(tv.tv_sec >= first_sec);
    return (tv.tv_sec - first_sec) + (tv.tv_usec / 1000000.0);
}

int main(int argc, char **argv) {
    if (argc < 3) {
        std::cerr << "Usage:\n\t./interpolate in.png out.png\n" << std::endl;
        return 1;
    }

    ImageParam input(Float(32), 3);

    const unsigned int levels = 10;

    Func downsampled[levels];
    Func downx[levels];
    Func interpolated[levels];
    Func upsampled[levels];
    Func upsampledx[levels];
    Var x("x"), y("y"), c("c");

    Func clamped;
    clamped(x, y, c) = input(clamp(x, 0, input.width()-1), clamp(y, 0, input.height()-1), c);

    // This triggers a bug in llvm 3.3 (3.2 and trunk are fine), so we
    // rewrite it in a way that doesn't trigger the bug. The rewritten
    // form assumes the input alpha is zero or one.
    // downsampled[0](x, y, c) = select(c < 3, clamped(x, y, c) * clamped(x, y, 3), clamped(x, y, 3));
    downsampled[0](x, y, c) = clamped(x, y, c) * clamped(x, y, 3);

    for (unsigned int l = 1; l < levels; ++l) {
        Func prev = downsampled[l-1];

        if (l == 4) {
            // Also add a boundary condition at a middle pyramid level
            // to prevent the footprint of the downsamplings to extend
            // too far off the base image. Otherwise we look 512
            // pixels off each edge.
            Expr w = input.width()/(1 << l);
            Expr h = input.height()/(1 << l);
            prev = lambda(x, y, c, prev(clamp(x, 0, w), clamp(y, 0, h), c));
        }

        downx[l](x, y, c) = (prev(x*2-1, y, c) +
                             2.0f * prev(x*2, y, c) +
                             prev(x*2+1, y, c)) * 0.25f;
        downsampled[l](x, y, c) = (downx[l](x, y*2-1, c) +
                                   2.0f * downx[l](x, y*2, c) +
                                   downx[l](x, y*2+1, c)) * 0.25f;
    }
    interpolated[levels-1](x, y, c) = downsampled[levels-1](x, y, c);
    for (unsigned int l = levels-2; l < levels; --l) {
        upsampledx[l](x, y, c) = (interpolated[l+1](x/2, y, c) +
                                  interpolated[l+1]((x+1)/2, y, c)) / 2.0f;
        upsampled[l](x, y, c) =  (upsampledx[l](x, y/2, c) +
                                  upsampledx[l](x, (y+1)/2, c)) / 2.0f;
        interpolated[l](x, y, c) = downsampled[l](x, y, c) + (1.0f - downsampled[l](x, y, 3)) * upsampled[l](x, y, c);
    }

    Func normalize("normalize");
    normalize(x, y, c) = interpolated[0](x, y, c) / interpolated[0](x, y, 3);

    Func final("final");
    final(x, y, c) = normalize(x, y, c);

    std::cout << "Finished function setup." << std::endl;

    int sched;
    Target target = get_target_from_environment();
    if (target.has_gpu_feature()) {
        sched = 4;
    } else {
        sched = 2;
    }

    switch (sched) {
    case 0:
    {
        std::cout << "Flat schedule." << std::endl;
        for (unsigned int l = 0; l < levels; ++l) {
            downsampled[l].compute_root();
            interpolated[l].compute_root();
        }
        final.compute_root();
        break;
    }
    case 1:
    {
        std::cout << "Flat schedule with vectorization." << std::endl;
        for (unsigned int l = 0; l < levels; ++l) {
            downsampled[l].compute_root().vectorize(x,4);
            interpolated[l].compute_root().vectorize(x,4);
        }
        final.compute_root();
        break;
    }
    case 2:
    {
        Var xi, yi;
        std::cout << "Flat schedule with parallelization + vectorization." << std::endl;
        clamped.compute_root().parallel(y).bound(c, 0, 4).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
        for (unsigned int l = 1; l < levels-1; ++l) {
            if (l > 0) downsampled[l].compute_root().parallel(y).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
            interpolated[l].compute_root().parallel(y).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
            interpolated[l].unroll(x, 2).unroll(y, 2);
        }
        final.reorder(c, x, y).bound(c, 0, 3).parallel(y);
        final.tile(x, y, xi, yi, 2, 2).unroll(xi).unroll(yi);
        final.bound(x, 0, input.width());
        final.bound(y, 0, input.height());
        break;
    }
    case 3:
    {
        std::cout << "Flat schedule with vectorization sometimes." << std::endl;
        for (unsigned int l = 0; l < levels; ++l) {
            if (l + 4 < levels) {
                Var yo,yi;
                downsampled[l].compute_root().vectorize(x,4);
                interpolated[l].compute_root().vectorize(x,4);
            } else {
                downsampled[l].compute_root();
                interpolated[l].compute_root();
            }
        }
        final.compute_root();
        break;
    }
    case 4:
    {
        std::cout << "GPU schedule." << std::endl;

        // Some gpus don't have enough memory to process the entire
        // image, so we process the image in tiles.
        Var yo, yi, xo, xi;
        final.reorder(c, x, y).bound(c, 0, 3).vectorize(x, 4);
        final.tile(x, y, xo, yo, xi, yi, input.width()/4, input.height()/4);
        normalize.compute_at(final, xo).reorder(c, x, y).gpu_tile(x, y, 16, 16, GPU_DEFAULT).unroll(c);

        // Start from level 1 to save memory - level zero will be computed on demand
        for (unsigned int l = 1; l < levels; ++l) {
            int tile_size = 32 >> l;
            if (tile_size < 1) tile_size = 1;
            if (tile_size > 16) tile_size = 16;
            downsampled[l].compute_root().gpu_tile(x, y, c, tile_size, tile_size, 4, GPU_DEFAULT);
            interpolated[l].compute_at(final, xo).gpu_tile(x, y, c, tile_size, tile_size, 4, GPU_DEFAULT);
        }
        break;
    }
    default:
        assert(0 && "No schedule with this number.");
    }

    // JIT compile the pipeline eagerly, so we don't interfere with timing
    final.compile_jit(target);

    Image<float> in_png = load<float>(argv[1]);
    Image<float> out(in_png.width(), in_png.height(), 3);
    assert(in_png.channels() == 4);
    input.set(in_png);

    std::cout << "Running... " << std::endl;
    double min = std::numeric_limits<double>::infinity();
    const unsigned int iters = 20;

    for (unsigned int x = 0; x < iters; ++x) {
        double before = now();
        final.realize(out);
        double after = now();
        double amt = after - before;

        std::cout << "   " << amt * 1000 << std::endl;
        if (amt < min) min = amt;

    }
    std::cout << " took " << min * 1000 << " msec." << std::endl;

    vector<Argument> args;
    args.push_back(input);
    final.compile_to_assembly("test.s", args, target);

    save(out, argv[2]);

}
<commit_msg>Standardize loop constructs in interpolate app<commit_after>#include "Halide.h"

using namespace Halide;

#include <image_io.h>

#include <iostream>
#include <limits>

#include <sys/time.h>

using std::vector;

double now() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    static bool first_call = true;
    static time_t first_sec = 0;
    if (first_call) {
        first_call = false;
        first_sec = tv.tv_sec;
    }
    assert(tv.tv_sec >= first_sec);
    return (tv.tv_sec - first_sec) + (tv.tv_usec / 1000000.0);
}

int main(int argc, char **argv) {
    if (argc < 3) {
        std::cerr << "Usage:\n\t./interpolate in.png out.png\n" << std::endl;
        return 1;
    }

    ImageParam input(Float(32), 3);

    const int levels = 10;

    Func downsampled[levels];
    Func downx[levels];
    Func interpolated[levels];
    Func upsampled[levels];
    Func upsampledx[levels];
    Var x("x"), y("y"), c("c");

    Func clamped;
    clamped(x, y, c) = input(clamp(x, 0, input.width()-1), clamp(y, 0, input.height()-1), c);

    // This triggers a bug in llvm 3.3 (3.2 and trunk are fine), so we
    // rewrite it in a way that doesn't trigger the bug. The rewritten
    // form assumes the input alpha is zero or one.
    // downsampled[0](x, y, c) = select(c < 3, clamped(x, y, c) * clamped(x, y, 3), clamped(x, y, 3));
    downsampled[0](x, y, c) = clamped(x, y, c) * clamped(x, y, 3);

    for (int l = 1; l < levels; ++l) {
        Func prev = downsampled[l-1];

        if (l == 4) {
            // Also add a boundary condition at a middle pyramid level
            // to prevent the footprint of the downsamplings to extend
            // too far off the base image. Otherwise we look 512
            // pixels off each edge.
            Expr w = input.width()/(1 << l);
            Expr h = input.height()/(1 << l);
            prev = lambda(x, y, c, prev(clamp(x, 0, w), clamp(y, 0, h), c));
        }

        downx[l](x, y, c) = (prev(x*2-1, y, c) +
                             2.0f * prev(x*2, y, c) +
                             prev(x*2+1, y, c)) * 0.25f;
        downsampled[l](x, y, c) = (downx[l](x, y*2-1, c) +
                                   2.0f * downx[l](x, y*2, c) +
                                   downx[l](x, y*2+1, c)) * 0.25f;
    }
    interpolated[levels-1](x, y, c) = downsampled[levels-1](x, y, c);
    for (int l = levels-2; l >= 0; --l) {
        upsampledx[l](x, y, c) = (interpolated[l+1](x/2, y, c) +
                                  interpolated[l+1]((x+1)/2, y, c)) / 2.0f;
        upsampled[l](x, y, c) =  (upsampledx[l](x, y/2, c) +
                                  upsampledx[l](x, (y+1)/2, c)) / 2.0f;
        interpolated[l](x, y, c) = downsampled[l](x, y, c) + (1.0f - downsampled[l](x, y, 3)) * upsampled[l](x, y, c);
    }

    Func normalize("normalize");
    normalize(x, y, c) = interpolated[0](x, y, c) / interpolated[0](x, y, 3);

    Func final("final");
    final(x, y, c) = normalize(x, y, c);

    std::cout << "Finished function setup." << std::endl;

    int sched;
    Target target = get_target_from_environment();
    if (target.has_gpu_feature()) {
        sched = 4;
    } else {
        sched = 2;
    }

    switch (sched) {
    case 0:
    {
        std::cout << "Flat schedule." << std::endl;
        for (int l = 0; l < levels; ++l) {
            downsampled[l].compute_root();
            interpolated[l].compute_root();
        }
        final.compute_root();
        break;
    }
    case 1:
    {
        std::cout << "Flat schedule with vectorization." << std::endl;
        for (int l = 0; l < levels; ++l) {
            downsampled[l].compute_root().vectorize(x,4);
            interpolated[l].compute_root().vectorize(x,4);
        }
        final.compute_root();
        break;
    }
    case 2:
    {
        Var xi, yi;
        std::cout << "Flat schedule with parallelization + vectorization." << std::endl;
        clamped.compute_root().parallel(y).bound(c, 0, 4).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
        for (int l = 1; l < levels-1; ++l) {
            if (l > 0) downsampled[l].compute_root().parallel(y).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
            interpolated[l].compute_root().parallel(y).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
            interpolated[l].unroll(x, 2).unroll(y, 2);
        }
        final.reorder(c, x, y).bound(c, 0, 3).parallel(y);
        final.tile(x, y, xi, yi, 2, 2).unroll(xi).unroll(yi);
        final.bound(x, 0, input.width());
        final.bound(y, 0, input.height());
        break;
    }
    case 3:
    {
        std::cout << "Flat schedule with vectorization sometimes." << std::endl;
        for (int l = 0; l < levels; ++l) {
            if (l + 4 < levels) {
                Var yo,yi;
                downsampled[l].compute_root().vectorize(x,4);
                interpolated[l].compute_root().vectorize(x,4);
            } else {
                downsampled[l].compute_root();
                interpolated[l].compute_root();
            }
        }
        final.compute_root();
        break;
    }
    case 4:
    {
        std::cout << "GPU schedule." << std::endl;

        // Some gpus don't have enough memory to process the entire
        // image, so we process the image in tiles.
        Var yo, yi, xo, xi;
        final.reorder(c, x, y).bound(c, 0, 3).vectorize(x, 4);
        final.tile(x, y, xo, yo, xi, yi, input.width()/4, input.height()/4);
        normalize.compute_at(final, xo).reorder(c, x, y).gpu_tile(x, y, 16, 16, GPU_DEFAULT).unroll(c);

        // Start from level 1 to save memory - level zero will be computed on demand
        for (int l = 1; l < levels; ++l) {
            int tile_size = 32 >> l;
            if (tile_size < 1) tile_size = 1;
            if (tile_size > 16) tile_size = 16;
            downsampled[l].compute_root().gpu_tile(x, y, c, tile_size, tile_size, 4, GPU_DEFAULT);
            interpolated[l].compute_at(final, xo).gpu_tile(x, y, c, tile_size, tile_size, 4, GPU_DEFAULT);
        }
        break;
    }
    default:
        assert(0 && "No schedule with this number.");
    }

    // JIT compile the pipeline eagerly, so we don't interfere with timing
    final.compile_jit(target);

    Image<float> in_png = load<float>(argv[1]);
    Image<float> out(in_png.width(), in_png.height(), 3);
    assert(in_png.channels() == 4);
    input.set(in_png);

    std::cout << "Running... " << std::endl;
    double min = std::numeric_limits<double>::infinity();
    const int iters = 20;

    for (int x = 0; x < iters; ++x) {
        double before = now();
        final.realize(out);
        double after = now();
        double amt = after - before;

        std::cout << "   " << amt * 1000 << std::endl;
        if (amt < min) min = amt;

    }
    std::cout << " took " << min * 1000 << " msec." << std::endl;

    vector<Argument> args;
    args.push_back(input);
    final.compile_to_assembly("test.s", args, target);

    save(out, argv[2]);

}
<|endoftext|>


<commit_before>//
// EditLineReader is a LineReader that uses the libedit library to read
// input from the user.
//
// Part of ccons, the interactive console for the C programming language.
//
// Copyright (c) 2009 Alexei Svitkine. This file is distributed under the
// terms of MIT Open Source License. See file LICENSE for details.
//

#include "EditLineReader.h"

#include <string.h>
#include <limits.h>

#include "complete.h"

namespace ccons {

namespace {

static EditLineReader * reader;

static const char *ccons_prompt(EditLine *e)
{
	return (reader ? reader->getPrompt() : "??? ");
}

static unsigned char ccons_autocomplete(EditLine *e, int ch)
{
	const LineInfo *line = el_line(e);
	char path[1024], insert[1024];
	const char *p = line->buffer;

	if (strncmp(p, ":load", 5))
		return CC_ERROR;

	p += 5;
	while (isspace(*p)) p++;

	int len = std::max(0, std::min<int>(sizeof(path) - 1, line->cursor - p));
	strncpy(path, p, len);
	path[len] = '\0';

	if (complete(path, insert, sizeof(insert)) > 0) {
		if (el_insertstr(e, insert) != -1) {
			return CC_REFRESH;
		}
	}

	return CC_ERROR;
}

} // anon namespace

EditLineReader::EditLineReader()
	: _history(history_init())
	, _editLine(el_init("ccons", stdin, stdout, stderr))
{
	reader = this;
	history(_history, &_event, H_SETSIZE, INT_MAX);
	el_set(_editLine, EL_PROMPT, ccons_prompt);
	el_set(_editLine, EL_EDITOR, "emacs");
	el_set(_editLine, EL_HIST, history, _history);
	el_set(_editLine, EL_ADDFN, "ccons-ac", "autocomplete", ccons_autocomplete);
	el_set(_editLine, EL_BIND, "^I", "ccons-ac", NULL);
}

EditLineReader::~EditLineReader()
{
	el_end(_editLine);
	history_end(_history);
}

const char * EditLineReader::readLine(const char *prompt, const char *input)
{
	_prompt = prompt;

	el_push(_editLine, input);

	const char *line = el_gets(_editLine, NULL);

	if (line)
		history(_history, &_event, H_ENTER, line);

	return line;
}

const char * EditLineReader::getPrompt() const
{
	return _prompt.c_str();
}

} // namespace ccons
<commit_msg>Don't pass NULL as 2nd param of el_gets(), since it results in a crash with certain versions of editline, such as the one that comes with FreeBSD.<commit_after>//
// EditLineReader is a LineReader that uses the libedit library to read
// input from the user.
//
// Part of ccons, the interactive console for the C programming language.
//
// Copyright (c) 2009 Alexei Svitkine. This file is distributed under the
// terms of MIT Open Source License. See file LICENSE for details.
//

#include "EditLineReader.h"

#include <string.h>
#include <limits.h>

#include "complete.h"

namespace ccons {

namespace {

static EditLineReader * reader;

static const char *ccons_prompt(EditLine *e)
{
	return (reader ? reader->getPrompt() : "??? ");
}

static unsigned char ccons_autocomplete(EditLine *e, int ch)
{
	const LineInfo *line = el_line(e);
	char path[1024], insert[1024];
	const char *p = line->buffer;

	if (strncmp(p, ":load", 5))
		return CC_ERROR;

	p += 5;
	while (isspace(*p)) p++;

	int len = std::max(0, std::min<int>(sizeof(path) - 1, line->cursor - p));
	strncpy(path, p, len);
	path[len] = '\0';

	if (complete(path, insert, sizeof(insert)) > 0) {
		if (el_insertstr(e, insert) != -1) {
			return CC_REFRESH;
		}
	}

	return CC_ERROR;
}

} // anon namespace

EditLineReader::EditLineReader()
	: _history(history_init())
	, _editLine(el_init("ccons", stdin, stdout, stderr))
{
	reader = this;
	history(_history, &_event, H_SETSIZE, INT_MAX);
	el_set(_editLine, EL_PROMPT, ccons_prompt);
	el_set(_editLine, EL_EDITOR, "emacs");
	el_set(_editLine, EL_HIST, history, _history);
	el_set(_editLine, EL_ADDFN, "ccons-ac", "autocomplete", ccons_autocomplete);
	el_set(_editLine, EL_BIND, "^I", "ccons-ac", NULL);
}

EditLineReader::~EditLineReader()
{
	el_end(_editLine);
	history_end(_history);
}

const char * EditLineReader::readLine(const char *prompt, const char *input)
{
	_prompt = prompt;

	el_push(_editLine, input);

	int n;
	const char *line = el_gets(_editLine, &n);

	if (line)
		history(_history, &_event, H_ENTER, line);

	return line;
}

const char * EditLineReader::getPrompt() const
{
	return _prompt.c_str();
}

} // namespace ccons
<|endoftext|>


<commit_before>//  Natron
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
//  Created by Frédéric Devernay on 03/09/13.
//
//

#include "OfxHost.h"

#include <cassert>
#include <fstream>
#include <QtCore/QDir>
#include <QtCore/QMutex>
#if QT_VERSION < 0x050000
#include <QtGui/QDesktopServices>
#else
#include <QStandardPaths>
#endif

#include <ofxhPluginAPICache.h>
#include <ofxhImageEffect.h>
#include <ofxhImageEffectAPI.h>
#include <ofxhHost.h>

#include "Global/AppManager.h"
#include "Global/LibraryBinary.h"

#include "Engine/OfxEffectInstance.h"
#include "Engine/OfxImageEffectInstance.h"
#include "Engine/KnobTypes.h"

using namespace Natron;

Natron::OfxHost::OfxHost()
:_imageEffectPluginCache(*this)
{
    _properties.setStringProperty(kOfxPropName,"uk.co.thefoundry.nuke");//NATRON_APPLICATION_NAME "Host");
    _properties.setStringProperty(kOfxPropLabel, NATRON_APPLICATION_NAME);
    _properties.setIntProperty(kOfxPropAPIVersion, 1 , 0); //API v1.0
    _properties.setIntProperty(kOfxPropAPIVersion, 0 , 1);
    _properties.setIntProperty(kOfxPropVersion, NATRON_VERSION_MAJOR , 0); //Software version v1.0
    _properties.setIntProperty(kOfxPropVersion, NATRON_VERSION_MINOR , 1);
    _properties.setStringProperty(kOfxPropVersionLabel, NATRON_VERSION_STRING);
    _properties.setIntProperty(kOfxImageEffectHostPropIsBackground, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsOverlays, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultiResolution, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsTiles, 1);
    _properties.setIntProperty(kOfxImageEffectPropTemporalClipAccess, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedComponents,  kOfxImageComponentRGBA, 0);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, 0 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, 2 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, 3 );

    _properties.setStringProperty(kOfxImageEffectPropSupportedPixelDepths,kOfxBitDepthFloat,0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipPARs, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFrameRate, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFielding, 0);
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomInteract, 1 );
    _properties.setIntProperty(kOfxParamHostPropSupportsStringAnimation, String_Knob::canAnimateStatic());
    _properties.setIntProperty(kOfxParamHostPropSupportsChoiceAnimation, Choice_Knob::canAnimateStatic());
    _properties.setIntProperty(kOfxParamHostPropSupportsBooleanAnimation, Bool_Knob::canAnimateStatic());
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomAnimation, 0 /*Custom_Knob::canAnimateStatic()*/);
    _properties.setIntProperty(kOfxParamHostPropMaxParameters, -1);
    _properties.setIntProperty(kOfxParamHostPropMaxPages, 0);
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 0 );
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 1 );
    _properties.setIntProperty(kOfxImageEffectInstancePropSequentialRender, 0);

}

Natron::OfxHost::~OfxHost()
{
    writeOFXCache();
}

OFX::Host::ImageEffect::Instance* Natron::OfxHost::newInstance(void* ,
                                                                OFX::Host::ImageEffect::ImageEffectPlugin* plugin,
                                                                OFX::Host::ImageEffect::Descriptor& desc,
                                                                const std::string& context)
{
    assert(plugin);

    return new Natron::OfxImageEffectInstance(plugin,desc,context,false);
}

/// Override this to create a descriptor, this makes the 'root' descriptor
OFX::Host::ImageEffect::Descriptor *Natron::OfxHost::makeDescriptor(OFX::Host::ImageEffect::ImageEffectPlugin* plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(plugin);
    return desc;
}

/// used to construct a context description, rootContext is the main context
OFX::Host::ImageEffect::Descriptor *Natron::OfxHost::makeDescriptor(const OFX::Host::ImageEffect::Descriptor &rootContext,
                                                                     OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(rootContext, plugin);
    return desc;
}

/// used to construct populate the cache
OFX::Host::ImageEffect::Descriptor *Natron::OfxHost::makeDescriptor(const std::string &bundlePath,
                                                                     OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(bundlePath, plugin);
    return desc;
}

/// message
OfxStatus Natron::OfxHost::vmessage(const char* type,
                                     const char* ,
                                     const char* format,
                                     va_list args)
{
    assert(type);
    assert(format);
    char buf[10000];
    sprintf(buf, format,args);
    std::string message(buf);

    if (strcmp(type, kOfxMessageLog) == 0) {

        std::cout << message << std::endl;

    }else if(strcmp(type, kOfxMessageFatal) == 0 ||
             strcmp(type, kOfxMessageError) == 0) {

        Natron::errorDialog(NATRON_APPLICATION_NAME, message);

    }else if(strcmp(type, kOfxMessageWarning)){

        Natron::warningDialog(NATRON_APPLICATION_NAME, message);

    }else if(strcmp(type, kOfxMessageMessage)){

        Natron::informationDialog(NATRON_APPLICATION_NAME, message);

    }else if(strcmp(type, kOfxMessageQuestion) == 0) {

        if(Natron::questionDialog(NATRON_APPLICATION_NAME, message) == Natron::Yes){
            return kOfxStatReplyYes;
        }else{
            return kOfxStatReplyNo;
        }

    }
    return kOfxStatReplyDefault;
}

OfxStatus Natron::OfxHost::setPersistentMessage(const char* type,
                                                 const char* id,
                                                 const char* format,
                                                 va_list args){
    vmessage(type,id,format,args);
    return kOfxStatOK;
}

/// clearPersistentMessage
OfxStatus Natron::OfxHost::clearPersistentMessage(){
    return kOfxStatOK;
}

OfxEffectInstance* Natron::OfxHost::createOfxEffect(const std::string& name,Natron::Node* node) {
    OFXPluginsIterator ofxPlugin = _ofxPlugins.find(name);
    if (ofxPlugin == _ofxPlugins.end()) {
        return NULL;
    }
    OFX::Host::ImageEffect::ImageEffectPlugin* plugin = _imageEffectPluginCache.getPluginById(ofxPlugin->second.first);
    if (!plugin) {
        return NULL;
    }
    const std::set<std::string>& contexts = plugin->getContexts();
    std::string context;

    if (contexts.size() == 1) {
        context = (*contexts.begin());
    }else{
        std::set<std::string>::iterator found = contexts.find(kOfxImageEffectContextGeneral);
        if(found != contexts.end()){
            context = *found;
        }else{
            found = contexts.find(kOfxImageEffectContextFilter);
            if(found != contexts.end()){
                context = *found;
            }else{
                found = contexts.find(kOfxImageEffectContextGenerator);
                if(found != contexts.end()){
                    context = *found;
                }else{
                    found = contexts.find(kOfxImageEffectContextTransition);
                    if(found != contexts.end()){
                        context = *found;
                    }else{
                        context = kOfxImageEffectContextPaint;
                    }
                }
            }
        }

    }

    bool rval = false;
    try {
        rval = plugin->getPluginHandle();
    } catch (const std::exception& e) {
        throw std::runtime_error(std::string("Error: Could not get plugin handle for plugin") + ": " + e.what());
    } catch (...) {
        throw std::runtime_error(std::string("Error: Could not get plugin handle for plugin"));
    }

    if(!rval) {
        return NULL;
    }
    OfxEffectInstance* hostSideEffect = new OfxEffectInstance(node);

    hostSideEffect->createOfxImageEffectInstance(plugin, context);

    return hostSideEffect;
}

void Natron::OfxHost::loadOFXPlugins(std::vector<Natron::Plugin*>* plugins) {

    assert(OFX::Host::PluginCache::getPluginCache());
    /// set the version label in the global cache
    OFX::Host::PluginCache::getPluginCache()->setCacheVersion(NATRON_APPLICATION_NAME "OFXCachev1");

    /// make an image effect plugin cache

    /// register the image effect cache with the global plugin cache
    _imageEffectPluginCache.registerInCache(*OFX::Host::PluginCache::getPluginCache());

#if defined(WINDOWS)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("C:\\Program Files\\Common Files\\OFX\\Nuke");
#endif
#if defined(__linux__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/usr/OFX/Nuke");
#endif
#if defined(__APPLE__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/Library/OFX/Nuke");
#endif

    /// now read an old cache
    // The cache location depends on the OS.
    // On OSX, it will be ~/Library/Caches/<organization>/<application>/OFXCache.xml
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation) + QDir::separator() + "OFXCache.xml";
#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QDir::separator() + "OFXCache.xml";
#endif
    std::ifstream ifs(ofxcachename.toStdString().c_str());
    if (ifs.is_open()) {
        OFX::Host::PluginCache::getPluginCache()->readCache(ifs);
        ifs.close();
    }
    OFX::Host::PluginCache::getPluginCache()->scanPluginFiles();

    /*Filling node name list and plugin grouping*/
    const std::vector<OFX::Host::ImageEffect::ImageEffectPlugin *>& ofxPlugins = _imageEffectPluginCache.getPlugins();
    for (unsigned int i = 0 ; i < ofxPlugins.size(); ++i) {
        OFX::Host::ImageEffect::ImageEffectPlugin* p = ofxPlugins[i];
        assert(p);
        if(p->getContexts().size() == 0)
            continue;

        QString openfxId = p->getIdentifier().c_str();
        std::string grouping = p->getDescriptor().getPluginGrouping().c_str();

        std::string bundlePath = p->getBinary()->getBundlePath();
        std::string pluginLabel = OfxEffectInstance::getPluginLabel(p->getDescriptor().getShortLabel(),
                                                                    p->getDescriptor().getLabel(),
                                                                    p->getDescriptor().getLongLabel());

        std::string pluginId = OfxEffectInstance::generateImageEffectClassName(p->getDescriptor().getShortLabel(),
                                                                               p->getDescriptor().getLabel(),
                                                                               p->getDescriptor().getLongLabel(),
                                                                           grouping);

        QStringList groups = OfxEffectInstance::getPluginGrouping(pluginLabel, grouping);

        assert(p->getBinary());
        QString iconFilename = QString(bundlePath.c_str()) + "/Contents/Resources/";
        iconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
        iconFilename.append(openfxId);
        iconFilename.append(".png");
        QString groupIconFilename;
        if (groups.size() > 0) {
            groupIconFilename = QString(p->getBinary()->getBundlePath().c_str()) + "/Contents/Resources/";
            groupIconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
            groupIconFilename.append(groups[0]);
            groupIconFilename.append(".png");
        }
        emit toolButtonAdded(groups,pluginId.c_str(), pluginLabel.c_str(), iconFilename, groupIconFilename);
        _ofxPlugins.insert(make_pair(pluginId, make_pair(openfxId.toStdString(), grouping)));
        QMutex* pluginMutex = NULL;
        if(p->getDescriptor().getRenderThreadSafety() == kOfxImageEffectRenderUnsafe){
            pluginMutex = new QMutex;
        }
        Natron::Plugin* plugin = new Natron::Plugin(new Natron::LibraryBinary(Natron::LibraryBinary::BUILTIN),
                                                    pluginId.c_str(),pluginLabel.c_str(),pluginMutex);
        plugins->push_back(plugin);
    }
}

void Natron::OfxHost::writeOFXCache(){
    /// and write a new cache, long version with everything in there
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);

#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
#endif
    QDir().mkpath(ofxcachename);
    ofxcachename +=  QDir::separator();
    ofxcachename += "OFXCache.xml";
    std::ofstream of(ofxcachename.toStdString().c_str());
    assert(of.is_open());
    assert(OFX::Host::PluginCache::getPluginCache());
    OFX::Host::PluginCache::getPluginCache()->writePluginCache(of);
    of.close();
    //Clean up, to be polite.
    OFX::Host::PluginCache::clearPluginCache();
}

<commit_msg>bug fix: getPluginHandle() must be called befor getContexts(), because kOfxActionLoad may set properties<commit_after>//  Natron
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
//  Created by Frédéric Devernay on 03/09/13.
//
//

#include "OfxHost.h"

#include <cassert>
#include <fstream>
#include <QtCore/QDir>
#include <QtCore/QMutex>
#if QT_VERSION < 0x050000
#include <QtGui/QDesktopServices>
#else
#include <QStandardPaths>
#endif

#include <ofxhPluginAPICache.h>
#include <ofxhImageEffect.h>
#include <ofxhImageEffectAPI.h>
#include <ofxhHost.h>

#include "Global/AppManager.h"
#include "Global/LibraryBinary.h"

#include "Engine/OfxEffectInstance.h"
#include "Engine/OfxImageEffectInstance.h"
#include "Engine/KnobTypes.h"

using namespace Natron;

Natron::OfxHost::OfxHost()
:_imageEffectPluginCache(*this)
{
    _properties.setStringProperty(kOfxPropName,"uk.co.thefoundry.nuke");//NATRON_APPLICATION_NAME "Host");
    _properties.setStringProperty(kOfxPropLabel, NATRON_APPLICATION_NAME);
    _properties.setIntProperty(kOfxPropAPIVersion, 1 , 0); //API v1.0
    _properties.setIntProperty(kOfxPropAPIVersion, 0 , 1);
    _properties.setIntProperty(kOfxPropVersion, NATRON_VERSION_MAJOR , 0); //Software version v1.0
    _properties.setIntProperty(kOfxPropVersion, NATRON_VERSION_MINOR , 1);
    _properties.setStringProperty(kOfxPropVersionLabel, NATRON_VERSION_STRING);
    _properties.setIntProperty(kOfxImageEffectHostPropIsBackground, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsOverlays, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultiResolution, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsTiles, 1);
    _properties.setIntProperty(kOfxImageEffectPropTemporalClipAccess, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedComponents,  kOfxImageComponentRGBA, 0);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, 0 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, 2 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, 3 );

    _properties.setStringProperty(kOfxImageEffectPropSupportedPixelDepths,kOfxBitDepthFloat,0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipPARs, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFrameRate, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFielding, 0);
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomInteract, 1 );
    _properties.setIntProperty(kOfxParamHostPropSupportsStringAnimation, String_Knob::canAnimateStatic());
    _properties.setIntProperty(kOfxParamHostPropSupportsChoiceAnimation, Choice_Knob::canAnimateStatic());
    _properties.setIntProperty(kOfxParamHostPropSupportsBooleanAnimation, Bool_Knob::canAnimateStatic());
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomAnimation, 0 /*Custom_Knob::canAnimateStatic()*/);
    _properties.setIntProperty(kOfxParamHostPropMaxParameters, -1);
    _properties.setIntProperty(kOfxParamHostPropMaxPages, 0);
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 0 );
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 1 );
    _properties.setIntProperty(kOfxImageEffectInstancePropSequentialRender, 0);

}

Natron::OfxHost::~OfxHost()
{
    writeOFXCache();
}

OFX::Host::ImageEffect::Instance* Natron::OfxHost::newInstance(void* ,
                                                                OFX::Host::ImageEffect::ImageEffectPlugin* plugin,
                                                                OFX::Host::ImageEffect::Descriptor& desc,
                                                                const std::string& context)
{
    assert(plugin);

    return new Natron::OfxImageEffectInstance(plugin,desc,context,false);
}

/// Override this to create a descriptor, this makes the 'root' descriptor
OFX::Host::ImageEffect::Descriptor *Natron::OfxHost::makeDescriptor(OFX::Host::ImageEffect::ImageEffectPlugin* plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(plugin);
    return desc;
}

/// used to construct a context description, rootContext is the main context
OFX::Host::ImageEffect::Descriptor *Natron::OfxHost::makeDescriptor(const OFX::Host::ImageEffect::Descriptor &rootContext,
                                                                     OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(rootContext, plugin);
    return desc;
}

/// used to construct populate the cache
OFX::Host::ImageEffect::Descriptor *Natron::OfxHost::makeDescriptor(const std::string &bundlePath,
                                                                     OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(bundlePath, plugin);
    return desc;
}

/// message
OfxStatus Natron::OfxHost::vmessage(const char* type,
                                     const char* ,
                                     const char* format,
                                     va_list args)
{
    assert(type);
    assert(format);
    char buf[10000];
    sprintf(buf, format,args);
    std::string message(buf);

    if (strcmp(type, kOfxMessageLog) == 0) {

        std::cout << message << std::endl;

    }else if(strcmp(type, kOfxMessageFatal) == 0 ||
             strcmp(type, kOfxMessageError) == 0) {

        Natron::errorDialog(NATRON_APPLICATION_NAME, message);

    }else if(strcmp(type, kOfxMessageWarning)){

        Natron::warningDialog(NATRON_APPLICATION_NAME, message);

    }else if(strcmp(type, kOfxMessageMessage)){

        Natron::informationDialog(NATRON_APPLICATION_NAME, message);

    }else if(strcmp(type, kOfxMessageQuestion) == 0) {

        if(Natron::questionDialog(NATRON_APPLICATION_NAME, message) == Natron::Yes){
            return kOfxStatReplyYes;
        }else{
            return kOfxStatReplyNo;
        }

    }
    return kOfxStatReplyDefault;
}

OfxStatus Natron::OfxHost::setPersistentMessage(const char* type,
                                                 const char* id,
                                                 const char* format,
                                                 va_list args){
    vmessage(type,id,format,args);
    return kOfxStatOK;
}

/// clearPersistentMessage
OfxStatus Natron::OfxHost::clearPersistentMessage(){
    return kOfxStatOK;
}

OfxEffectInstance* Natron::OfxHost::createOfxEffect(const std::string& name,Natron::Node* node) {
    OFXPluginsIterator ofxPlugin = _ofxPlugins.find(name);
    if (ofxPlugin == _ofxPlugins.end()) {
        return NULL;
    }
    OFX::Host::ImageEffect::ImageEffectPlugin* plugin = _imageEffectPluginCache.getPluginById(ofxPlugin->second.first);
    if (!plugin) {
        return NULL;
    }

    // getPluginHandle() must be called befor getContexts():
    // it calls kOfxActionLoad on the plugin, which may set properties (including supported contexts)
    bool rval = false;
    try {
        rval = plugin->getPluginHandle();
    } catch (const std::exception& e) {
        throw std::runtime_error(std::string("Error: Could not get plugin handle for plugin") + ": " + e.what());
    } catch (...) {
        throw std::runtime_error(std::string("Error: Could not get plugin handle for plugin"));
    }

    const std::set<std::string>& contexts = plugin->getContexts();
    std::string context;

    if (contexts.size() == 0) {
        throw std::runtime_error(std::string("Error: Plugins supports no context"));
        //context = kOfxImageEffectContextGeneral;
        //plugin->addContext(kOfxImageEffectContextGeneral);
    } else if (contexts.size() == 1) {
        context = (*contexts.begin());
    } else {
        std::set<std::string>::iterator found = contexts.find(kOfxImageEffectContextGeneral);
        if(found != contexts.end()){
            context = *found;
        }else{
            found = contexts.find(kOfxImageEffectContextFilter);
            if(found != contexts.end()){
                context = *found;
            }else{
                found = contexts.find(kOfxImageEffectContextGenerator);
                if(found != contexts.end()){
                    context = *found;
                }else{
                    found = contexts.find(kOfxImageEffectContextTransition);
                    if(found != contexts.end()){
                        context = *found;
                    }else{
                        context = kOfxImageEffectContextPaint;
                    }
                }
            }
        }

    }

    if(!rval) {
        return NULL;
    }
    OfxEffectInstance* hostSideEffect = new OfxEffectInstance(node);

    hostSideEffect->createOfxImageEffectInstance(plugin, context);

    return hostSideEffect;
}

void Natron::OfxHost::loadOFXPlugins(std::vector<Natron::Plugin*>* plugins) {

    assert(OFX::Host::PluginCache::getPluginCache());
    /// set the version label in the global cache
    OFX::Host::PluginCache::getPluginCache()->setCacheVersion(NATRON_APPLICATION_NAME "OFXCachev1");

    /// make an image effect plugin cache

    /// register the image effect cache with the global plugin cache
    _imageEffectPluginCache.registerInCache(*OFX::Host::PluginCache::getPluginCache());

#if defined(WINDOWS)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("C:\\Program Files\\Common Files\\OFX\\Nuke");
#endif
#if defined(__linux__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/usr/OFX/Nuke");
#endif
#if defined(__APPLE__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/Library/OFX/Nuke");
#endif

    /// now read an old cache
    // The cache location depends on the OS.
    // On OSX, it will be ~/Library/Caches/<organization>/<application>/OFXCache.xml
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation) + QDir::separator() + "OFXCache.xml";
#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QDir::separator() + "OFXCache.xml";
#endif
    std::ifstream ifs(ofxcachename.toStdString().c_str());
    if (ifs.is_open()) {
        OFX::Host::PluginCache::getPluginCache()->readCache(ifs);
        ifs.close();
    }
    OFX::Host::PluginCache::getPluginCache()->scanPluginFiles();

    /*Filling node name list and plugin grouping*/
    const std::vector<OFX::Host::ImageEffect::ImageEffectPlugin *>& ofxPlugins = _imageEffectPluginCache.getPlugins();
    for (unsigned int i = 0 ; i < ofxPlugins.size(); ++i) {
        OFX::Host::ImageEffect::ImageEffectPlugin* p = ofxPlugins[i];
        assert(p);
        if(p->getContexts().size() == 0)
            continue;

        QString openfxId = p->getIdentifier().c_str();
        std::string grouping = p->getDescriptor().getPluginGrouping().c_str();

        std::string bundlePath = p->getBinary()->getBundlePath();
        std::string pluginLabel = OfxEffectInstance::getPluginLabel(p->getDescriptor().getShortLabel(),
                                                                    p->getDescriptor().getLabel(),
                                                                    p->getDescriptor().getLongLabel());

        std::string pluginId = OfxEffectInstance::generateImageEffectClassName(p->getDescriptor().getShortLabel(),
                                                                               p->getDescriptor().getLabel(),
                                                                               p->getDescriptor().getLongLabel(),
                                                                           grouping);

        QStringList groups = OfxEffectInstance::getPluginGrouping(pluginLabel, grouping);

        assert(p->getBinary());
        QString iconFilename = QString(bundlePath.c_str()) + "/Contents/Resources/";
        iconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
        iconFilename.append(openfxId);
        iconFilename.append(".png");
        QString groupIconFilename;
        if (groups.size() > 0) {
            groupIconFilename = QString(p->getBinary()->getBundlePath().c_str()) + "/Contents/Resources/";
            groupIconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
            groupIconFilename.append(groups[0]);
            groupIconFilename.append(".png");
        }
        emit toolButtonAdded(groups,pluginId.c_str(), pluginLabel.c_str(), iconFilename, groupIconFilename);
        _ofxPlugins.insert(make_pair(pluginId, make_pair(openfxId.toStdString(), grouping)));
        QMutex* pluginMutex = NULL;
        if(p->getDescriptor().getRenderThreadSafety() == kOfxImageEffectRenderUnsafe){
            pluginMutex = new QMutex;
        }
        Natron::Plugin* plugin = new Natron::Plugin(new Natron::LibraryBinary(Natron::LibraryBinary::BUILTIN),
                                                    pluginId.c_str(),pluginLabel.c_str(),pluginMutex);
        plugins->push_back(plugin);
    }
}

void Natron::OfxHost::writeOFXCache(){
    /// and write a new cache, long version with everything in there
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);

#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
#endif
    QDir().mkpath(ofxcachename);
    ofxcachename +=  QDir::separator();
    ofxcachename += "OFXCache.xml";
    std::ofstream of(ofxcachename.toStdString().c_str());
    assert(of.is_open());
    assert(OFX::Host::PluginCache::getPluginCache());
    OFX::Host::PluginCache::getPluginCache()->writePluginCache(of);
    of.close();
    //Clean up, to be polite.
    OFX::Host::PluginCache::clearPluginCache();
}

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "ParseColor.h"

#include <ctype.h>
#include <string.h>
#include <strings.h>

typedef struct {
  const char* name;
  const float value[4];
} ColorSet;

static const ColorSet colorSets[] = {
  { "red",	{1.0f, 0.0f, 0.0f, 1.0f}},
  { "blue",	{0.0f, 0.0f, 1.0f, 1.0f}},
  { "green",	{0.0f, 1.0f, 0.0f, 1.0f}},
  { "yellow",	{1.0f, 1.0f, 0.0f, 1.0f}},
  { "purple",	{1.0f, 0.0f, 1.0f, 1.0f}},
  { "purple",	{0.0f, 1.0f, 1.0f, 1.0f}},
  { "black",	{0.0f, 0.0f, 0.0f, 1.0f}},
  { "white",	{1.0f, 1.0f, 1.0f, 1.0f}},
  { "grey",	{0.5f, 0.5f, 0.5f, 1.0f}},
};
static const int colorCount = sizeof(colorSets) / sizeof(ColorSet);

bool parseColorStream(std::istream& input, float color[4])
{
  std::string line;
  std::getline(input, line);
  input.putback('\n');

  return parseColorString(line.c_str(), color);
}

bool parseColorString(const char* str, float color[4])
{
  int i;
  const float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };

  // set to opaque white
  memcpy (color, white, sizeof(float[4]));

  // strip leading space
  while ((*str != '\0') && isspace(*str)) {
    str++;
  }

  // no string
  if (*str == '\0') {
    return false;
  }

  // #FF2343A9 format
  if (*str == '#') {
    // FIXME - complete this ?
    return false;
  }

  // numeric format (either 3 or 4 floating point values)
  else if (((*str >= '0') && (*str <= '9'))
           || (*str == '.')
           || (*str == '+')
           || (*str == '-')) {
    int count;
    float tmp[4];
    count = sscanf(str, "%f %f %f %f", &tmp[0], &tmp[1], &tmp[2], &tmp[3]);
    if (count < 3) {
      return false;
    } else {
      memcpy (color, tmp, count * sizeof(float));
      return true;
    }
  }

  // text string format  ("red 0.2" format is accepted for alpha values)
  else {
    for (i = 0; i < colorCount; i++) {
      int len = strlen (colorSets[i].name);
      const char* end = str + len;
      if ((strncasecmp (colorSets[i].name, str, len) == 0)
          && ((*end == '\0') || isspace(*end))) {
        memcpy (color, colorSets[i].value, sizeof(float[3]));

        int count;
        float alpha;
        count = sscanf (str + len, "%f", &alpha);
        if (count > 0) {
          color[3] = alpha;
        }

        return true;
      }
    }
  }

  return false;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>compile\!<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "ParseColor.h"

#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <string>
#include <stdio.h>

typedef struct {
  const char* name;
  const float value[4];
} ColorSet;

static const ColorSet colorSets[] = {
  { "red",	{1.0f, 0.0f, 0.0f, 1.0f}},
  { "blue",	{0.0f, 0.0f, 1.0f, 1.0f}},
  { "green",	{0.0f, 1.0f, 0.0f, 1.0f}},
  { "yellow",	{1.0f, 1.0f, 0.0f, 1.0f}},
  { "purple",	{1.0f, 0.0f, 1.0f, 1.0f}},
  { "purple",	{0.0f, 1.0f, 1.0f, 1.0f}},
  { "black",	{0.0f, 0.0f, 0.0f, 1.0f}},
  { "white",	{1.0f, 1.0f, 1.0f, 1.0f}},
  { "grey",	{0.5f, 0.5f, 0.5f, 1.0f}},
};
static const int colorCount = sizeof(colorSets) / sizeof(ColorSet);

bool parseColorStream(std::istream& input, float color[4])
{
  std::string line;
  std::getline(input, line);
  input.putback('\n');

  return parseColorString(line.c_str(), color);
}

bool parseColorString(const char* str, float color[4])
{
  int i;
  const float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };

  // set to opaque white
  memcpy (color, white, sizeof(float[4]));

  // strip leading space
  while ((*str != '\0') && isspace(*str)) {
    str++;
  }

  // no string
  if (*str == '\0') {
    return false;
  }

  // #FF2343A9 format
  if (*str == '#') {
    // FIXME - complete this ?
    return false;
  }

  // numeric format (either 3 or 4 floating point values)
  else if (((*str >= '0') && (*str <= '9'))
           || (*str == '.')
           || (*str == '+')
           || (*str == '-')) {
    int count;
    float tmp[4];
    count = sscanf(str, "%f %f %f %f", &tmp[0], &tmp[1], &tmp[2], &tmp[3]);
    if (count < 3) {
      return false;
    } else {
      memcpy (color, tmp, count * sizeof(float));
      return true;
    }
  }

  // text string format  ("red 0.2" format is accepted for alpha values)
  else {
    for (i = 0; i < colorCount; i++) {
      int len = strlen (colorSets[i].name);
      const char* end = str + len;
      if ((strncasecmp (colorSets[i].name, str, len) == 0)
          && ((*end == '\0') || isspace(*end))) {
        memcpy (color, colorSets[i].value, sizeof(float[3]));

        int count;
        float alpha;
        count = sscanf (str + len, "%f", &alpha);
        if (count > 0) {
          color[3] = alpha;
        }

        return true;
      }
    }
  }

  return false;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2007 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "TimeKeeper.h"

/* system implementation headers */
#include <time.h>
#include <string>
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
#ifdef __BEOS__
#  include <OS.h>
#endif
#if !defined(_WIN32)
#  include <sys/time.h>
#  include <sys/types.h>
static struct timeval	lastTime = { 0, 0 };
#  ifdef HAVE_SCHED_H
#    include <sched.h>
#  endif
#else /* !defined(_WIN32) */
#  include <mmsystem.h>
static unsigned long int	lastTime = 0;
static LARGE_INTEGER	qpcLastTime;
static LONGLONG		qpcFrequency = 0;
static LONGLONG	 qpcLastCalibration;
static DWORD	    timeLastCalibration;
#endif /* !defined(_WIN32) */

/* common implementation headers */
#include "TextUtils.h"
#include "bzfio.h"

static TimeKeeper	currentTime;
static TimeKeeper	tickTime;
static TimeKeeper	sunExplodeTime;
static TimeKeeper	sunGenesisTime;
static TimeKeeper	nullTime;
static TimeKeeper	startTime = TimeKeeper::getCurrent();

const TimeKeeper&	TimeKeeper::getCurrent(void)
{
  // if not first call then update current time, else use default initial time
#if !defined(_WIN32)
  if (lastTime.tv_sec != 0) {
    double curr;
    double last;
    double diff;
    struct timeval now;

    gettimeofday(&now, NULL);

    curr = double(now.tv_sec) + (1.0e-6 * double(now.tv_usec));
    last = double(lastTime.tv_sec) + (1.0e-6 * double(lastTime.tv_usec));

    if (curr <= last) {
      // eh, how'd we go back in time?
      diff = 0.0;
    } else {
      diff = curr - last;
    }

    currentTime += diff;
    lastTime = now;
  } else {
    gettimeofday(&lastTime, NULL);
  }
#else /* !defined(_WIN32) */
  if (qpcFrequency != 0) {

    // main timer is qpc
    LARGE_INTEGER now;
    QueryPerformanceCounter(&now);

    LONGLONG diff     = now.QuadPart - qpcLastTime.QuadPart;
    LONGLONG clkSpent = now.QuadPart - qpcLastCalibration;

    if (clkSpent > qpcFrequency) {
      // Recalibrate Frequency
      DWORD tgt	   = timeGetTime();
      DWORD deltaTgt      = tgt - timeLastCalibration;
      timeLastCalibration = tgt;
      qpcLastCalibration  = now.QuadPart;
      if (deltaTgt > 0) {
	LONGLONG oldqpcfreq = qpcFrequency;
	qpcFrequency	= (clkSpent * 1000) / deltaTgt;
	if (qpcFrequency != oldqpcfreq)
	  logDebugMessage(4,"Recalibrated QPC frequency.  Old: %f ; New: %f\n",
			  (double)oldqpcfreq, (double)qpcFrequency);
      }
    }

    currentTime += (double) diff / (double) qpcFrequency;
    qpcLastTime = now;
  } else if (lastTime != 0) {
    unsigned long int now = (unsigned long int)timeGetTime();
    unsigned long int diff;
    if (now < lastTime) {
      // eh, how'd we go back in time?
      diff = 0;
    } else {
      diff = now - lastTime;
    }
    currentTime += 1.0e-3 * (double)diff;
    lastTime = now;
  } else {
    static bool sane = true;

    // should only get into here once on app start
    if (!sane) {
      logDebugMessage(1,"Sanity check failure in TimeKeeper::getCurrent()\n");
    }
    sane = false;

    LARGE_INTEGER freq;
    if (QueryPerformanceFrequency(&freq)) {
      QueryPerformanceCounter(&qpcLastTime);
      qpcFrequency	= freq.QuadPart;
      logDebugMessage(4,"Actual reported QPC Frequency: %f\n", (double)qpcFrequency);
      qpcLastCalibration  = qpcLastTime.QuadPart;
      timeLastCalibration = timeGetTime();
    } else {
      logDebugMessage(1,"QueryPerformanceFrequency failed with error %d\n", GetLastError());

      // make sure we're at our best timer resolution possible
      timeBeginPeriod(1);

      lastTime = (unsigned long int)timeGetTime();
    }
  }
#endif /* !defined(_WIN32) */
  return currentTime;
}

const TimeKeeper&	TimeKeeper::getStartTime(void) // const
{
  return startTime;
}

const TimeKeeper&	TimeKeeper::getTick(void) // const
{
  return tickTime;
}

void			TimeKeeper::setTick(void)
{
  tickTime = getCurrent();
}

const TimeKeeper& TimeKeeper::getSunExplodeTime(void)
{
  sunExplodeTime.seconds = 10000.0 * 365 * 24 * 60 * 60;
  return sunExplodeTime;
}

const TimeKeeper& TimeKeeper::getSunGenesisTime(void)
{
  sunGenesisTime.seconds = -10000.0 * 365 * 24 * 60 * 60;
  return sunGenesisTime;
}

const TimeKeeper& TimeKeeper::getNullTime(void)
{
  nullTime.seconds = 0;
  return nullTime;
}

const char *TimeKeeper::timestamp(void) // const
{
  static char buffer[256]; // static, so that it doesn't vanish
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);
  now->tm_year += 1900;
  ++now->tm_mon;

  strncpy (buffer, TextUtils::format("%04d-%02d-%02d %02d:%02d:%02d",
				     now->tm_year, now->tm_mon, now->tm_mday,
				     now->tm_hour, now->tm_min, now->tm_sec).c_str(), 256);
  buffer[255] = '\0'; // safety

  return buffer;
}

/** returns a short string of the local time */
//static
std::string
TimeKeeper::shortTimeStamp(void) {
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);

  std::string result( TextUtils::format("%02d:%02d", now->tm_hour, now->tm_min, 10) );
  return result;
}

void TimeKeeper::localTime(int *year, int *month, int* day, int* hour, int* min, int* sec, bool* dst) // const
{
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);
  now->tm_year += 1900;
  ++now->tm_mon;

  if ( year )
    *year = now->tm_year;
  if ( month )
    *month = now->tm_mon;
  if ( day )
    *day = now->tm_mday;
  if ( hour )
    *hour = now->tm_hour;
  if ( min )
    *min = now->tm_min;
  if ( sec )
    *sec = now->tm_sec;
  if ( dst )
    *dst = now->tm_isdst != 0;
}

// function for converting a float time (e.g. difference of two TimeKeepers)
// into an array of ints
void TimeKeeper::convertTime(double raw, long int convertedTimes[]) // const
{
  long int day, hour, min, sec, remainder;
  static const int secondsInDay = 86400;

  sec = (long int)raw;
  day = sec / secondsInDay;
  remainder = sec - (day * secondsInDay);
  hour = remainder / 3600;
  remainder = sec - ((hour * 3600) + (day * secondsInDay));
  min = remainder / 60;
  remainder = sec - ((hour * 3600) + (day * secondsInDay) + (min * 60));
  sec = remainder;

  convertedTimes[0] = day;
  convertedTimes[1] = hour;
  convertedTimes[2] = min;
  convertedTimes[3] = sec;

  return;
}

// function for printing an array of ints representing a time
// as a human-readable string
const std::string TimeKeeper::printTime(long int timeValue[])
{
  std::string valueNames;
  char temp[20];

  if (timeValue[0] > 0) {
    snprintf(temp, 20, "%ld day%s", timeValue[0], timeValue[0] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[1] > 0) {
    if (timeValue[0] > 0) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld hour%s", timeValue[1], timeValue[1] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[2] > 0) {
    if ((timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld min%s", timeValue[2], timeValue[2] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[3] > 0) {
    if ((timeValue[2] > 0) || (timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld sec%s", timeValue[3], timeValue[3] == 1 ? "" : "s");
    valueNames.append(temp);
  }

  return valueNames;
}

// function for printing a float time difference as a human-readable string
const std::string TimeKeeper::printTime(double diff)
{
  long int temp[4];
  convertTime(diff, temp);
  return printTime(temp);
}

void TimeKeeper::sleep(double seconds)
{
  if (seconds <= 0.0) {
    return;
  }

#ifdef HAVE_USLEEP
  usleep((unsigned int)(1.0e6 * seconds));
  return;
#endif
#if defined(HAVE_SLEEP) && !defined(__APPLE__)
  // equivalent to _sleep() on win32 (not sleep(3))
  Sleep((DWORD)(seconds * 1000.0));
  return;
#endif
#ifdef HAVE_SNOOZE
  snooze((bigtime_t)(1.0e6 * seconds));
  return;
#endif
#ifdef HAVE_SELECT
  struct timeval tv;
  tv.tv_sec = (long)seconds;
  tv.tv_usec = (long)(1.0e6 * (seconds - tv.tv_sec));
  select(0, NULL, NULL, NULL, &tv);
  return;
#endif
#ifdef HAVE_WAITFORSINGLEOBJECT
  HANDLE dummyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  WaitForSingleObject(dummyEvent, (DWORD)(1000.0 * seconds));
  CloseHandle(dummyEvent);
  return;
#endif

  // fall-back case is fugly manual timekeeping
  TimeKeeper now = TimeKeeper::getCurrent();
  while ((TimeKeeper::getCurrent() - now) < seconds) {
    continue;
  }
  return;
}

void TimeKeeper::setProcessorAffinity(int processor)
{
#ifdef HAVE_SCHED_SETAFFINITY
  /* linuxy fix for time travel */
  cpu_set_t mask;
  CPU_ZERO(&mask);
  CPU_SET(processor, &mask);
  sched_setaffinity(0, sizeof(mask), &mask);
#else if defined(WIN32)
  /* windowsy fix for time travel */
  HANDLE hPrc = GetCurrentProcess();
  DWORD dwMask = 1 << processor;
  DWORD dwProcs = 0;
  GetProcessAffinityMask(NULL, NULL, &dwProcs);
  if (dwMask < dwProcs) {
    logDebugMessage(1, "Unable to set process affinity mask (specified processor does not exist).");
    return;
  }
  SetProcessAffinityMask(hPrc, dwMask);
#endif
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Preprocessor fix<commit_after>/* bzflag
 * Copyright (c) 1993 - 2007 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "TimeKeeper.h"

/* system implementation headers */
#include <time.h>
#include <string>
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
#ifdef __BEOS__
#  include <OS.h>
#endif
#if !defined(_WIN32)
#  include <sys/time.h>
#  include <sys/types.h>
static struct timeval	lastTime = { 0, 0 };
#  ifdef HAVE_SCHED_H
#    include <sched.h>
#  endif
#else /* !defined(_WIN32) */
#  include <mmsystem.h>
static unsigned long int	lastTime = 0;
static LARGE_INTEGER	qpcLastTime;
static LONGLONG		qpcFrequency = 0;
static LONGLONG	 qpcLastCalibration;
static DWORD	    timeLastCalibration;
#endif /* !defined(_WIN32) */

/* common implementation headers */
#include "TextUtils.h"
#include "bzfio.h"

static TimeKeeper	currentTime;
static TimeKeeper	tickTime;
static TimeKeeper	sunExplodeTime;
static TimeKeeper	sunGenesisTime;
static TimeKeeper	nullTime;
static TimeKeeper	startTime = TimeKeeper::getCurrent();

const TimeKeeper&	TimeKeeper::getCurrent(void)
{
  // if not first call then update current time, else use default initial time
#if !defined(_WIN32)
  if (lastTime.tv_sec != 0) {
    double curr;
    double last;
    double diff;
    struct timeval now;

    gettimeofday(&now, NULL);

    curr = double(now.tv_sec) + (1.0e-6 * double(now.tv_usec));
    last = double(lastTime.tv_sec) + (1.0e-6 * double(lastTime.tv_usec));

    if (curr <= last) {
      // eh, how'd we go back in time?
      diff = 0.0;
    } else {
      diff = curr - last;
    }

    currentTime += diff;
    lastTime = now;
  } else {
    gettimeofday(&lastTime, NULL);
  }
#else /* !defined(_WIN32) */
  if (qpcFrequency != 0) {

    // main timer is qpc
    LARGE_INTEGER now;
    QueryPerformanceCounter(&now);

    LONGLONG diff     = now.QuadPart - qpcLastTime.QuadPart;
    LONGLONG clkSpent = now.QuadPart - qpcLastCalibration;

    if (clkSpent > qpcFrequency) {
      // Recalibrate Frequency
      DWORD tgt	   = timeGetTime();
      DWORD deltaTgt      = tgt - timeLastCalibration;
      timeLastCalibration = tgt;
      qpcLastCalibration  = now.QuadPart;
      if (deltaTgt > 0) {
	LONGLONG oldqpcfreq = qpcFrequency;
	qpcFrequency	= (clkSpent * 1000) / deltaTgt;
	if (qpcFrequency != oldqpcfreq)
	  logDebugMessage(4,"Recalibrated QPC frequency.  Old: %f ; New: %f\n",
			  (double)oldqpcfreq, (double)qpcFrequency);
      }
    }

    currentTime += (double) diff / (double) qpcFrequency;
    qpcLastTime = now;
  } else if (lastTime != 0) {
    unsigned long int now = (unsigned long int)timeGetTime();
    unsigned long int diff;
    if (now < lastTime) {
      // eh, how'd we go back in time?
      diff = 0;
    } else {
      diff = now - lastTime;
    }
    currentTime += 1.0e-3 * (double)diff;
    lastTime = now;
  } else {
    static bool sane = true;

    // should only get into here once on app start
    if (!sane) {
      logDebugMessage(1,"Sanity check failure in TimeKeeper::getCurrent()\n");
    }
    sane = false;

    LARGE_INTEGER freq;
    if (QueryPerformanceFrequency(&freq)) {
      QueryPerformanceCounter(&qpcLastTime);
      qpcFrequency	= freq.QuadPart;
      logDebugMessage(4,"Actual reported QPC Frequency: %f\n", (double)qpcFrequency);
      qpcLastCalibration  = qpcLastTime.QuadPart;
      timeLastCalibration = timeGetTime();
    } else {
      logDebugMessage(1,"QueryPerformanceFrequency failed with error %d\n", GetLastError());

      // make sure we're at our best timer resolution possible
      timeBeginPeriod(1);

      lastTime = (unsigned long int)timeGetTime();
    }
  }
#endif /* !defined(_WIN32) */
  return currentTime;
}

const TimeKeeper&	TimeKeeper::getStartTime(void) // const
{
  return startTime;
}

const TimeKeeper&	TimeKeeper::getTick(void) // const
{
  return tickTime;
}

void			TimeKeeper::setTick(void)
{
  tickTime = getCurrent();
}

const TimeKeeper& TimeKeeper::getSunExplodeTime(void)
{
  sunExplodeTime.seconds = 10000.0 * 365 * 24 * 60 * 60;
  return sunExplodeTime;
}

const TimeKeeper& TimeKeeper::getSunGenesisTime(void)
{
  sunGenesisTime.seconds = -10000.0 * 365 * 24 * 60 * 60;
  return sunGenesisTime;
}

const TimeKeeper& TimeKeeper::getNullTime(void)
{
  nullTime.seconds = 0;
  return nullTime;
}

const char *TimeKeeper::timestamp(void) // const
{
  static char buffer[256]; // static, so that it doesn't vanish
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);
  now->tm_year += 1900;
  ++now->tm_mon;

  strncpy (buffer, TextUtils::format("%04d-%02d-%02d %02d:%02d:%02d",
				     now->tm_year, now->tm_mon, now->tm_mday,
				     now->tm_hour, now->tm_min, now->tm_sec).c_str(), 256);
  buffer[255] = '\0'; // safety

  return buffer;
}

/** returns a short string of the local time */
//static
std::string
TimeKeeper::shortTimeStamp(void) {
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);

  std::string result( TextUtils::format("%02d:%02d", now->tm_hour, now->tm_min, 10) );
  return result;
}

void TimeKeeper::localTime(int *year, int *month, int* day, int* hour, int* min, int* sec, bool* dst) // const
{
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);
  now->tm_year += 1900;
  ++now->tm_mon;

  if ( year )
    *year = now->tm_year;
  if ( month )
    *month = now->tm_mon;
  if ( day )
    *day = now->tm_mday;
  if ( hour )
    *hour = now->tm_hour;
  if ( min )
    *min = now->tm_min;
  if ( sec )
    *sec = now->tm_sec;
  if ( dst )
    *dst = now->tm_isdst != 0;
}

// function for converting a float time (e.g. difference of two TimeKeepers)
// into an array of ints
void TimeKeeper::convertTime(double raw, long int convertedTimes[]) // const
{
  long int day, hour, min, sec, remainder;
  static const int secondsInDay = 86400;

  sec = (long int)raw;
  day = sec / secondsInDay;
  remainder = sec - (day * secondsInDay);
  hour = remainder / 3600;
  remainder = sec - ((hour * 3600) + (day * secondsInDay));
  min = remainder / 60;
  remainder = sec - ((hour * 3600) + (day * secondsInDay) + (min * 60));
  sec = remainder;

  convertedTimes[0] = day;
  convertedTimes[1] = hour;
  convertedTimes[2] = min;
  convertedTimes[3] = sec;

  return;
}

// function for printing an array of ints representing a time
// as a human-readable string
const std::string TimeKeeper::printTime(long int timeValue[])
{
  std::string valueNames;
  char temp[20];

  if (timeValue[0] > 0) {
    snprintf(temp, 20, "%ld day%s", timeValue[0], timeValue[0] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[1] > 0) {
    if (timeValue[0] > 0) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld hour%s", timeValue[1], timeValue[1] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[2] > 0) {
    if ((timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld min%s", timeValue[2], timeValue[2] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[3] > 0) {
    if ((timeValue[2] > 0) || (timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld sec%s", timeValue[3], timeValue[3] == 1 ? "" : "s");
    valueNames.append(temp);
  }

  return valueNames;
}

// function for printing a float time difference as a human-readable string
const std::string TimeKeeper::printTime(double diff)
{
  long int temp[4];
  convertTime(diff, temp);
  return printTime(temp);
}

void TimeKeeper::sleep(double seconds)
{
  if (seconds <= 0.0) {
    return;
  }

#ifdef HAVE_USLEEP
  usleep((unsigned int)(1.0e6 * seconds));
  return;
#endif
#if defined(HAVE_SLEEP) && !defined(__APPLE__)
  // equivalent to _sleep() on win32 (not sleep(3))
  Sleep((DWORD)(seconds * 1000.0));
  return;
#endif
#ifdef HAVE_SNOOZE
  snooze((bigtime_t)(1.0e6 * seconds));
  return;
#endif
#ifdef HAVE_SELECT
  struct timeval tv;
  tv.tv_sec = (long)seconds;
  tv.tv_usec = (long)(1.0e6 * (seconds - tv.tv_sec));
  select(0, NULL, NULL, NULL, &tv);
  return;
#endif
#ifdef HAVE_WAITFORSINGLEOBJECT
  HANDLE dummyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  WaitForSingleObject(dummyEvent, (DWORD)(1000.0 * seconds));
  CloseHandle(dummyEvent);
  return;
#endif

  // fall-back case is fugly manual timekeeping
  TimeKeeper now = TimeKeeper::getCurrent();
  while ((TimeKeeper::getCurrent() - now) < seconds) {
    continue;
  }
  return;
}

void TimeKeeper::setProcessorAffinity(int processor)
{
#ifdef HAVE_SCHED_SETAFFINITY
  /* linuxy fix for time travel */
  cpu_set_t mask;
  CPU_ZERO(&mask);
  CPU_SET(processor, &mask);
  sched_setaffinity(0, sizeof(mask), &mask);
#elif defined(WIN32)
  /* windowsy fix for time travel */
  HANDLE hPrc = GetCurrentProcess();
  DWORD dwMask = 1 << processor;
  DWORD dwProcs = 0;
  GetProcessAffinityMask(NULL, NULL, &dwProcs);
  if (dwMask < dwProcs) {
    logDebugMessage(1, "Unable to set process affinity mask (specified processor does not exist).");
    return;
  }
  SetProcessAffinityMask(hPrc, dwMask);
#endif
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "TimeKeeper.h"

/* system implementation headers */
#include <time.h>
#include <string>
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
#ifdef __BEOS__
#  include <OS.h>
#endif
#if !defined(_WIN32)
#  include <sys/time.h>
#  include <sys/types.h>
static struct timeval	lastTime = { 0, 0 };
#else /* !defined(_WIN32) */
#  include <mmsystem.h>
static unsigned long int	lastTime = 0;
static LARGE_INTEGER	qpcLastTime;
static LONGLONG	        qpcFrequency = 0;
static LONGLONG         qpcLastCalibration;
static DWORD            timeLastCalibration;
#endif /* !defined(_WIN32) */

/* common implementation headers */
#include "TextUtils.h"
#include "bzfio.h"

TimeKeeper TimeKeeper::currentTime;
TimeKeeper TimeKeeper::tickTime;
TimeKeeper TimeKeeper::sunExplodeTime;
TimeKeeper TimeKeeper::sunGenesisTime;
TimeKeeper TimeKeeper::nullTime;
TimeKeeper TimeKeeper::startTime = TimeKeeper::getCurrent();

const TimeKeeper&	TimeKeeper::getCurrent(void)
{
  // if not first call then update current time, else use default initial time
#if !defined(_WIN32)
  if (lastTime.tv_sec != 0) {
    struct timeval now;
    gettimeofday(&now, NULL);
    currentTime += double(now.tv_sec - lastTime.tv_sec) +
		1.0e-6 * double(now.tv_usec - lastTime.tv_usec);
    lastTime = now;
  }
  else {
    gettimeofday(&lastTime, NULL);
  }
#else /* !defined(_WIN32) */
  if (qpcFrequency != 0) {

    // main timer is qpc
    LARGE_INTEGER now;
    QueryPerformanceCounter(&now);

    LONGLONG diff     = now.QuadPart - qpcLastTime.QuadPart;
    LONGLONG clkSpent = now.QuadPart - qpcLastCalibration;
    double   qpcdiff  = (double) diff / (double) qpcFrequency;

    if (clkSpent > qpcFrequency) {
      // Recalibrate Frequency
      DWORD tgt           = timeGetTime();
      DWORD deltaTgt      = tgt - timeLastCalibration;
      LONGLONG oldqpcfreq = qpcFrequency;
      if (deltaTgt > 0) {
	qpcFrequency        = (clkSpent * 1000) / deltaTgt;
	timeLastCalibration = tgt;
	qpcLastCalibration  = now.QuadPart;
	if (qpcFrequency != oldqpcfreq)
	  DEBUG4("Recalibrated QPC frequency.  Old: %f ; New: %f\n",
		 (double)oldqpcfreq, (double)qpcFrequency);
      }
    }

    currentTime += qpcdiff;
    qpcLastTime = now;
  } else if (lastTime != 0) {
    unsigned long int now = (unsigned long int)timeGetTime();
    unsigned long int diff;
    if (now <= lastTime) {
      // eh, how'd we go back in time?
      diff = 0;
    } else {
      diff = now - lastTime;
    }
    currentTime += 1.0e-3 * (double)diff;
    lastTime = now;
  } else {
    static bool sane = true;

    // should only get into here once on app start
    if (!sane) {
      DEBUG1("Sanity check failure in TimeKeeper::getCurrent()\n");
    }
    sane = false;

    LARGE_INTEGER freq;
    if (QueryPerformanceFrequency(&freq)) {
      QueryPerformanceCounter(&qpcLastTime);
      qpcFrequency        = freq.QuadPart;
      DEBUG4("Actual reported QPC Frequency: %f\n", (double)qpcFrequency);
      qpcLastCalibration  = qpcLastTime.QuadPart;
      timeLastCalibration = timeGetTime();
    } else {
      DEBUG1("QueryPerformanceFrequency failed with error %d\n", GetLastError());

      // make sure we're at our best timer resolution possible
      timeBeginPeriod(1);

      lastTime = (unsigned long int)timeGetTime();
    }
  }
#endif /* !defined(_WIN32) */
  return currentTime;
}

const TimeKeeper&	TimeKeeper::getStartTime(void) // const
{
  return startTime;
}

const TimeKeeper&	TimeKeeper::getTick(void) // const
{
  return tickTime;
}

void			TimeKeeper::setTick(void)
{
  tickTime = getCurrent();
}

const TimeKeeper& TimeKeeper::getSunExplodeTime(void)
{
  sunExplodeTime.seconds = 10000.0 * 365 * 24 * 60 * 60;
  return sunExplodeTime;
}

const TimeKeeper& TimeKeeper::getSunGenesisTime(void)
{
  sunGenesisTime.seconds = -10000.0 * 365 * 24 * 60 * 60;
  return sunGenesisTime;
}

const TimeKeeper& TimeKeeper::getNullTime(void)
{
  nullTime.seconds = 0;
  return nullTime;
}

const char *TimeKeeper::timestamp(void) // const
{
  static char buffer[256]; // static, so that it doesn't vanish
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);
  now->tm_year += 1900;
  ++now->tm_mon;

  strncpy (buffer, TextUtils::format("%04d-%02d-%02d %02d:%02d:%02d",
		     now->tm_year, now->tm_mon, now->tm_mday,
		     now->tm_hour, now->tm_min, now->tm_sec).c_str(), 256);
  buffer[255] = '\0'; // safety

  return buffer;
}

// function for converting a float time (e.g. difference of two TimeKeepers)
// into an array of ints
const void TimeKeeper::convertTime(double raw, long int convertedTimes[])
{
  long int day, hour, min, sec, remainder;
  static const int secondsInDay = 86400;

  sec = (long int)raw;
  day = sec / secondsInDay;
  remainder = sec - (day * secondsInDay);
  hour = remainder / 3600;
  remainder = sec - ((hour * 3600) + (day * secondsInDay));
  min = remainder / 60;
  remainder = sec - ((hour * 3600) + (day * secondsInDay) + (min * 60));
  sec = remainder;

  convertedTimes[0] = day;
  convertedTimes[1] = hour;
  convertedTimes[2] = min;
  convertedTimes[3] = sec;

  return;
}

// function for printing an array of ints representing a time
// as a human-readable string
const std::string TimeKeeper::printTime(long int timeValue[])
{
  std::string valueNames;
  char temp[20];

  if (timeValue[0] > 0) {
    snprintf(temp, 20, "%ld day%s", timeValue[0], timeValue[0] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[1] > 0) {
    if (timeValue[0] > 0) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld hour%s", timeValue[1], timeValue[1] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[2] > 0) {
    if ((timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld min%s", timeValue[2], timeValue[2] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[3] > 0) {
    if ((timeValue[2] > 0) || (timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld sec%s", timeValue[3], timeValue[3] == 1 ? "" : "s");
    valueNames.append(temp);
  }

  return valueNames;
}

// function for printing a float time difference as a human-readable string
const std::string TimeKeeper::printTime(double diff)
{
  long int temp[4];
  convertTime(diff, temp);
  return printTime(temp);
}

void TimeKeeper::sleep(double seconds)
{
  if (seconds <= 0.0) {
    return;
  }

#ifdef HAVE_USLEEP
  usleep((unsigned int)(1.0e6 * seconds));
  return;
#endif
#if defined(HAVE_SLEEP) && !defined(__APPLE__)
  // equivalent to _sleep() on win32 (not sleep(3))
  Sleep((DWORD)(seconds * 1000.0));
  return;
#endif
#ifdef HAVE_SNOOZE
  snooze((bigtime_t)(1.0e6 * seconds));
  return;
#endif
#ifdef HAVE_SELECT
  struct timeval tv;
  tv.tv_sec = (long)seconds;
  tv.tv_usec = (long)(1.0e6 * (seconds - tv.tv_sec));
  select(0, NULL, NULL, NULL, &tv);
  return;
#endif
#ifdef HAVE_WAITFORSINGLEOBJECT
  HANDLE dummyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  WaitForSingleObject(dummyEvent, (DWORD)(1000.0 * seconds));
  CloseHandle(dummyEvent);
  return;
#endif

  // fall-back case is fugly manual timekeeping
  TimeKeeper now = TimeKeeper::getCurrent();
  while ((TimeKeeper::getCurrent() - now) < seconds) {
    continue;
  }
  return;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Don't forget data from recalibration when error, just don't change frequency<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "TimeKeeper.h"

/* system implementation headers */
#include <time.h>
#include <string>
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
#ifdef __BEOS__
#  include <OS.h>
#endif
#if !defined(_WIN32)
#  include <sys/time.h>
#  include <sys/types.h>
static struct timeval	lastTime = { 0, 0 };
#else /* !defined(_WIN32) */
#  include <mmsystem.h>
static unsigned long int	lastTime = 0;
static LARGE_INTEGER	qpcLastTime;
static LONGLONG	        qpcFrequency = 0;
static LONGLONG         qpcLastCalibration;
static DWORD            timeLastCalibration;
#endif /* !defined(_WIN32) */

/* common implementation headers */
#include "TextUtils.h"
#include "bzfio.h"

TimeKeeper TimeKeeper::currentTime;
TimeKeeper TimeKeeper::tickTime;
TimeKeeper TimeKeeper::sunExplodeTime;
TimeKeeper TimeKeeper::sunGenesisTime;
TimeKeeper TimeKeeper::nullTime;
TimeKeeper TimeKeeper::startTime = TimeKeeper::getCurrent();

const TimeKeeper&	TimeKeeper::getCurrent(void)
{
  // if not first call then update current time, else use default initial time
#if !defined(_WIN32)
  if (lastTime.tv_sec != 0) {
    struct timeval now;
    gettimeofday(&now, NULL);
    currentTime += double(now.tv_sec - lastTime.tv_sec) +
		1.0e-6 * double(now.tv_usec - lastTime.tv_usec);
    lastTime = now;
  }
  else {
    gettimeofday(&lastTime, NULL);
  }
#else /* !defined(_WIN32) */
  if (qpcFrequency != 0) {

    // main timer is qpc
    LARGE_INTEGER now;
    QueryPerformanceCounter(&now);

    LONGLONG diff     = now.QuadPart - qpcLastTime.QuadPart;
    LONGLONG clkSpent = now.QuadPart - qpcLastCalibration;

    if (clkSpent > qpcFrequency) {
      // Recalibrate Frequency
      DWORD tgt           = timeGetTime();
      DWORD deltaTgt      = tgt - timeLastCalibration;
      timeLastCalibration = tgt;
      qpcLastCalibration  = now.QuadPart;
      if (deltaTgt > 0) {
	LONGLONG oldqpcfreq = qpcFrequency;
	qpcFrequency        = (clkSpent * 1000) / deltaTgt;
	if (qpcFrequency != oldqpcfreq)
	  DEBUG4("Recalibrated QPC frequency.  Old: %f ; New: %f\n",
		 (double)oldqpcfreq, (double)qpcFrequency);
      }
    }

    currentTime += (double) diff / (double) qpcFrequency;
    qpcLastTime = now;
  } else if (lastTime != 0) {
    unsigned long int now = (unsigned long int)timeGetTime();
    unsigned long int diff;
    if (now <= lastTime) {
      // eh, how'd we go back in time?
      diff = 0;
    } else {
      diff = now - lastTime;
    }
    currentTime += 1.0e-3 * (double)diff;
    lastTime = now;
  } else {
    static bool sane = true;

    // should only get into here once on app start
    if (!sane) {
      DEBUG1("Sanity check failure in TimeKeeper::getCurrent()\n");
    }
    sane = false;

    LARGE_INTEGER freq;
    if (QueryPerformanceFrequency(&freq)) {
      QueryPerformanceCounter(&qpcLastTime);
      qpcFrequency        = freq.QuadPart;
      DEBUG4("Actual reported QPC Frequency: %f\n", (double)qpcFrequency);
      qpcLastCalibration  = qpcLastTime.QuadPart;
      timeLastCalibration = timeGetTime();
    } else {
      DEBUG1("QueryPerformanceFrequency failed with error %d\n", GetLastError());

      // make sure we're at our best timer resolution possible
      timeBeginPeriod(1);

      lastTime = (unsigned long int)timeGetTime();
    }
  }
#endif /* !defined(_WIN32) */
  return currentTime;
}

const TimeKeeper&	TimeKeeper::getStartTime(void) // const
{
  return startTime;
}

const TimeKeeper&	TimeKeeper::getTick(void) // const
{
  return tickTime;
}

void			TimeKeeper::setTick(void)
{
  tickTime = getCurrent();
}

const TimeKeeper& TimeKeeper::getSunExplodeTime(void)
{
  sunExplodeTime.seconds = 10000.0 * 365 * 24 * 60 * 60;
  return sunExplodeTime;
}

const TimeKeeper& TimeKeeper::getSunGenesisTime(void)
{
  sunGenesisTime.seconds = -10000.0 * 365 * 24 * 60 * 60;
  return sunGenesisTime;
}

const TimeKeeper& TimeKeeper::getNullTime(void)
{
  nullTime.seconds = 0;
  return nullTime;
}

const char *TimeKeeper::timestamp(void) // const
{
  static char buffer[256]; // static, so that it doesn't vanish
  time_t tnow = time(0);
  struct tm *now = localtime(&tnow);
  now->tm_year += 1900;
  ++now->tm_mon;

  strncpy (buffer, TextUtils::format("%04d-%02d-%02d %02d:%02d:%02d",
		     now->tm_year, now->tm_mon, now->tm_mday,
		     now->tm_hour, now->tm_min, now->tm_sec).c_str(), 256);
  buffer[255] = '\0'; // safety

  return buffer;
}

// function for converting a float time (e.g. difference of two TimeKeepers)
// into an array of ints
const void TimeKeeper::convertTime(double raw, long int convertedTimes[])
{
  long int day, hour, min, sec, remainder;
  static const int secondsInDay = 86400;

  sec = (long int)raw;
  day = sec / secondsInDay;
  remainder = sec - (day * secondsInDay);
  hour = remainder / 3600;
  remainder = sec - ((hour * 3600) + (day * secondsInDay));
  min = remainder / 60;
  remainder = sec - ((hour * 3600) + (day * secondsInDay) + (min * 60));
  sec = remainder;

  convertedTimes[0] = day;
  convertedTimes[1] = hour;
  convertedTimes[2] = min;
  convertedTimes[3] = sec;

  return;
}

// function for printing an array of ints representing a time
// as a human-readable string
const std::string TimeKeeper::printTime(long int timeValue[])
{
  std::string valueNames;
  char temp[20];

  if (timeValue[0] > 0) {
    snprintf(temp, 20, "%ld day%s", timeValue[0], timeValue[0] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[1] > 0) {
    if (timeValue[0] > 0) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld hour%s", timeValue[1], timeValue[1] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[2] > 0) {
    if ((timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld min%s", timeValue[2], timeValue[2] == 1 ? "" : "s");
    valueNames.append(temp);
  }
  if (timeValue[3] > 0) {
    if ((timeValue[2] > 0) || (timeValue[1] > 0) || (timeValue[0] > 0)) {
      valueNames.append(", ");
    }
    snprintf(temp, 20, "%ld sec%s", timeValue[3], timeValue[3] == 1 ? "" : "s");
    valueNames.append(temp);
  }

  return valueNames;
}

// function for printing a float time difference as a human-readable string
const std::string TimeKeeper::printTime(double diff)
{
  long int temp[4];
  convertTime(diff, temp);
  return printTime(temp);
}

void TimeKeeper::sleep(double seconds)
{
  if (seconds <= 0.0) {
    return;
  }

#ifdef HAVE_USLEEP
  usleep((unsigned int)(1.0e6 * seconds));
  return;
#endif
#if defined(HAVE_SLEEP) && !defined(__APPLE__)
  // equivalent to _sleep() on win32 (not sleep(3))
  Sleep((DWORD)(seconds * 1000.0));
  return;
#endif
#ifdef HAVE_SNOOZE
  snooze((bigtime_t)(1.0e6 * seconds));
  return;
#endif
#ifdef HAVE_SELECT
  struct timeval tv;
  tv.tv_sec = (long)seconds;
  tv.tv_usec = (long)(1.0e6 * (seconds - tv.tv_sec));
  select(0, NULL, NULL, NULL, &tv);
  return;
#endif
#ifdef HAVE_WAITFORSINGLEOBJECT
  HANDLE dummyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  WaitForSingleObject(dummyEvent, (DWORD)(1000.0 * seconds));
  CloseHandle(dummyEvent);
  return;
#endif

  // fall-back case is fugly manual timekeeping
  TimeKeeper now = TimeKeeper::getCurrent();
  while ((TimeKeeper::getCurrent() - now) < seconds) {
    continue;
  }
  return;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#if !defined(OMR_OM_SLOTDESCRIPTOR_HPP_)
#define OMR_OM_SLOTDESCRIPTOR_HPP_

#include <OMR/Infra/HashUtilities.hpp>
#include <OMR/Infra/Span.hpp>
#include <OMR/Om/Id.hpp>
#include <OMR/Om/Value.hpp>

#include <cstddef>
#include <functional>

namespace OMR {
namespace Om {

/// TODO: Move Ref somewhere else.
using Ref = std::uintptr_t;

/// Fundamental, built in types.
/// At it's core, every SlotType is represented by one of these values.
/// Om only really cares about 3 categories of slots values
///   1. Naked GC pointer (REF)
///   2. Boxed GC pointer (VALUE)
///   3. Non-pointer
/// Beyond those 3 categories, we just need to know the width, so we can iterate
/// the object.
enum class CoreType {
  /// Binary data slots, of various sizes.
  INT8,
  INT16,
  INT32,
  INT64,
  FLOAT32,
  FLOAT64,
  VALUE,  //< A polymorphic `Value`.
  REF     //< A GC pointer.
};

/// Calculate the size of a CoreType. Fundamental types have a fixed size.
constexpr std::size_t width(CoreType t) noexcept {
  switch (t) {
    case CoreType::INT8:
      return 1;
    case CoreType::INT16:
      return 2;
    case CoreType::INT32:
      return 4;
    case CoreType::INT64:
      return 8;
    case CoreType::FLOAT32:
      return 4;
    case CoreType::FLOAT64:
      return 8;
    case CoreType::VALUE:
      return sizeof(Value);
    case CoreType::REF:
      return sizeof(Ref);
  }
}

class SlotType {
 public:
  constexpr SlotType(const SlotType&) = default;

  constexpr SlotType(Id id, CoreType coreType) noexcept
      : id_(id), coreType_(coreType) {}

  constexpr CoreType coreType() const noexcept { return coreType_; }

  constexpr Id id() const noexcept { return id_; }

  SlotType& id(Id id) noexcept {
    id_ = id;
    return *this;
  }

  constexpr std::size_t hash() const noexcept {
    return Infra::Hash::mix(id_.hash(), std::size_t(coreType()));
  }

  constexpr bool operator==(const SlotType& rhs) const noexcept {
    return id_ == rhs.id_;
  }

  constexpr bool operator!=(const SlotType& rhs) const noexcept {
    return id_ != rhs.id_;
  }

  constexpr std::size_t width() const noexcept {
    return ::OMR::Om::width(coreType());
  }

 private:
  Id id_;
  CoreType coreType_;
};

class SlotAttr {
 public:
  /// Allocate a SlotAttr, where the type is {id: 0, coreType: VALUE}
  constexpr explicit SlotAttr(Id id) noexcept
      : type_(Id(0), CoreType::VALUE), id_(id) {}

  constexpr SlotAttr(const SlotAttr&) noexcept = default;

  constexpr SlotAttr(const SlotType& type, const Id& id) noexcept
      : type_(type), id_(id) {}

  constexpr Id id() const noexcept { return id_; }

  SlotAttr& id(Id id) {
    id_ = id;
    return *this;
  }

  SlotType& type() noexcept { return type_; }

  constexpr const SlotType& type() const noexcept { return type_; }

  SlotAttr& type(const SlotType& type) noexcept {
    type_ = type;
    return *this;
  }

  constexpr std::size_t hash() const noexcept {
    return Infra::Hash::mix(id().hash(), type().hash());
  }

  constexpr bool operator==(const SlotAttr& rhs) const noexcept {
    return (id_ == rhs.id_) && (type_ == rhs.type_);
  }

  constexpr bool operator!=(const SlotAttr& rhs) const noexcept {
    return (id_ != rhs.id_) || (type_ != rhs.type_);
  }

  /// Width of the slot's value.
  constexpr std::size_t width() const noexcept { return type_.width(); }

  /// The fundamental type of the slot.
  constexpr CoreType coreType() const noexcept { return type_.coreType(); }

 private:
  SlotType type_;
  Id id_;
};

static_assert(sizeof(SlotAttr) == sizeof(SlotType) + sizeof(Id),
              "SlotAttr must have no padding--needed for memcmp.");

static_assert(
    std::is_standard_layout<SlotAttr>::value,
    "Slot Descriptors are heap allocated, so must be StandardLayoutType.");

/// @group Span operations
/// @{

/// Deep hash of a Span of SlotAttrs.
inline std::size_t hash(const Infra::Span<const SlotAttr>& ds) {
  std::size_t h = 7;
  for (const SlotAttr& d : ds) {
    Infra::Hash::mix(h, d.hash());
  }
  return h;
}

/// Deep compare of two spans of SlotAttrs.
/// The two spans must have the same length and data.
inline bool operator==(const Infra::Span<const SlotAttr>& lhs,
                       const Infra::Span<const SlotAttr>& rhs) {
  if (lhs.length() != rhs.length()) {
    return true;
  }

  if (lhs.value() == rhs.value()) {
    return true;
  }

  // TODO: if SlotAttr padding is zero, this could be memcmp'd.
  for (std::size_t i = 0; i < lhs.length(); i++) {
    if (lhs[i] != rhs[i]) {
      return false;
    }
  }

  return true;
}

inline bool operator!=(const Infra::Span<const SlotAttr>& lhs,
                       const Infra::Span<const SlotAttr>& rhs) {
  return !(lhs == rhs);
}

}  // namespace Om
}  // namespace OMR

#endif  // OMR_OM_SLOTDESCRIPTOR_HPP_
<commit_msg>Return a width of -1 by default for CoreTypes<commit_after>#if !defined(OMR_OM_SLOTDESCRIPTOR_HPP_)
#define OMR_OM_SLOTDESCRIPTOR_HPP_

#include <OMR/Infra/HashUtilities.hpp>
#include <OMR/Infra/Span.hpp>
#include <OMR/Om/Id.hpp>
#include <OMR/Om/Value.hpp>

#include <cstddef>
#include <functional>

namespace OMR {
namespace Om {

/// TODO: Move Ref somewhere else.
using Ref = std::uintptr_t;

/// Fundamental, built in types.
/// At it's core, every SlotType is represented by one of these values.
/// Om only really cares about 3 categories of slots values
///   1. Naked GC pointer (REF)
///   2. Boxed GC pointer (VALUE)
///   3. Non-pointer
/// Beyond those 3 categories, we just need to know the width, so we can iterate
/// the object.
enum class CoreType {
  /// Binary data slots, of various sizes.
  INT8,
  INT16,
  INT32,
  INT64,
  FLOAT32,
  FLOAT64,
  VALUE,  //< A polymorphic `Value`.
  REF     //< A GC pointer.
};

/// Calculate the size of a CoreType. Fundamental types have a fixed size.
constexpr std::size_t width(CoreType t) noexcept {
  switch (t) {
    case CoreType::INT8:
      return 1;
    case CoreType::INT16:
      return 2;
    case CoreType::INT32:
      return 4;
    case CoreType::INT64:
      return 8;
    case CoreType::FLOAT32:
      return 4;
    case CoreType::FLOAT64:
      return 8;
    case CoreType::VALUE:
      return sizeof(Value);
    case CoreType::REF:
      return sizeof(Ref);
    default:
      break;
  }
  return -1;
}

class SlotType {
 public:
  constexpr SlotType(const SlotType&) = default;

  constexpr SlotType(Id id, CoreType coreType) noexcept
      : id_(id), coreType_(coreType) {}

  constexpr CoreType coreType() const noexcept { return coreType_; }

  constexpr Id id() const noexcept { return id_; }

  SlotType& id(Id id) noexcept {
    id_ = id;
    return *this;
  }

  constexpr std::size_t hash() const noexcept {
    return Infra::Hash::mix(id_.hash(), std::size_t(coreType()));
  }

  constexpr bool operator==(const SlotType& rhs) const noexcept {
    return id_ == rhs.id_;
  }

  constexpr bool operator!=(const SlotType& rhs) const noexcept {
    return id_ != rhs.id_;
  }

  constexpr std::size_t width() const noexcept {
    return ::OMR::Om::width(coreType());
  }

 private:
  Id id_;
  CoreType coreType_;
};

class SlotAttr {
 public:
  /// Allocate a SlotAttr, where the type is {id: 0, coreType: VALUE}
  constexpr explicit SlotAttr(Id id) noexcept
      : type_(Id(0), CoreType::VALUE), id_(id) {}

  constexpr SlotAttr(const SlotAttr&) noexcept = default;

  constexpr SlotAttr(const SlotType& type, const Id& id) noexcept
      : type_(type), id_(id) {}

  constexpr Id id() const noexcept { return id_; }

  SlotAttr& id(Id id) {
    id_ = id;
    return *this;
  }

  SlotType& type() noexcept { return type_; }

  constexpr const SlotType& type() const noexcept { return type_; }

  SlotAttr& type(const SlotType& type) noexcept {
    type_ = type;
    return *this;
  }

  constexpr std::size_t hash() const noexcept {
    return Infra::Hash::mix(id().hash(), type().hash());
  }

  constexpr bool operator==(const SlotAttr& rhs) const noexcept {
    return (id_ == rhs.id_) && (type_ == rhs.type_);
  }

  constexpr bool operator!=(const SlotAttr& rhs) const noexcept {
    return (id_ != rhs.id_) || (type_ != rhs.type_);
  }

  /// Width of the slot's value.
  constexpr std::size_t width() const noexcept { return type_.width(); }

  /// The fundamental type of the slot.
  constexpr CoreType coreType() const noexcept { return type_.coreType(); }

 private:
  SlotType type_;
  Id id_;
};

static_assert(sizeof(SlotAttr) == sizeof(SlotType) + sizeof(Id),
              "SlotAttr must have no padding--needed for memcmp.");

static_assert(
    std::is_standard_layout<SlotAttr>::value,
    "Slot Descriptors are heap allocated, so must be StandardLayoutType.");

/// @group Span operations
/// @{

/// Deep hash of a Span of SlotAttrs.
inline std::size_t hash(const Infra::Span<const SlotAttr>& ds) {
  std::size_t h = 7;
  for (const SlotAttr& d : ds) {
    Infra::Hash::mix(h, d.hash());
  }
  return h;
}

/// Deep compare of two spans of SlotAttrs.
/// The two spans must have the same length and data.
inline bool operator==(const Infra::Span<const SlotAttr>& lhs,
                       const Infra::Span<const SlotAttr>& rhs) {
  if (lhs.length() != rhs.length()) {
    return true;
  }

  if (lhs.value() == rhs.value()) {
    return true;
  }

  // TODO: if SlotAttr padding is zero, this could be memcmp'd.
  for (std::size_t i = 0; i < lhs.length(); i++) {
    if (lhs[i] != rhs[i]) {
      return false;
    }
  }

  return true;
}

inline bool operator!=(const Infra::Span<const SlotAttr>& lhs,
                       const Infra::Span<const SlotAttr>& rhs) {
  return !(lhs == rhs);
}

}  // namespace Om
}  // namespace OMR

#endif  // OMR_OM_SLOTDESCRIPTOR_HPP_
<|endoftext|>