<commit_before>#include "test.hpp"
#include <natus/require.hpp>

static bool freecalled = false;
void hook_free(void* misc) {
	assert(misc == (void*) 0x1234);
	freecalled = true;
}

Value hook(Value& ctx, Require::HookStep step, char* name, void* misc) {
	if (step == Require::HookStepLoad && !strcmp(name, "__internal__")) {
		assert(!ctx.setRecursive("exports.misc", (long) misc).isException());
		return ctx.newBool(true);
	}

	return NULL;
}

int doTest(Engine& engine, Value& global) {
	Value config = global.newObject();
	Value   path = global.newArrayBuilder(".");
	config.setRecursive("natus.require.path", path, Value::PropAttrNone, true);

	Require req(global);
	assert(req.initialize(config));

	assert(req.addHook("__internal__", hook, (void*) 0x1234, hook_free));
	Value module = req.require("__internal__");
	assert(!module.isException());
	assert(module.isObject());
	assert(module.get("misc").toLong() == 0x1234);

	// Cleanup
	return 0;
}
<commit_msg>add require identity test<commit_after>#include "test.hpp"
#include <natus/require.hpp>

static bool freecalled = false;
void hook_free(void* misc) {
	assert(misc == (void*) 0x1234);
	freecalled = true;
}

Value hook(Value& ctx, Require::HookStep step, char* name, void* misc) {
	if (step == Require::HookStepLoad && !strcmp(name, "__internal__")) {
		assert(!ctx.setRecursive("exports.misc", (long) misc).isException());
		return ctx.newBool(true);
	}

	return NULL;
}

int doTest(Engine& engine, Value& global) {
	Value config = global.newObject();
	Value   path = global.newArrayBuilder("./lib");
	config.setRecursive("natus.require.path", path, Value::PropAttrNone, true);

	// Initialize the require system
	Require req(global);
	assert(req.initialize(config));
	assert(req.addHook("__internal__", hook, (void*) 0x1234, hook_free));

	// Load the internal module
	Value modulea = req.require("__internal__");
	assert(!modulea.isException());
	assert(modulea.isObject());
	assert(modulea.get("misc").toLong() == 0x1234);

	// Load the internal module again
	Value moduleb = req.require("__internal__");
	assert(!modulea.isException());
	assert(modulea.isObject());
	assert(modulea.get("misc").toLong() == 0x1234);

	// Check to make sure that the underlying values refer to the same object
	assert(!modulea.set("test", 17L).isException());
	assert(moduleb.get("test").toLong() == 17);

	// Cleanup
	return 0;
}
<|endoftext|>


<commit_before>#include <tclap/CmdLine.h>

#include "util.hpp"
#include "lexer.hpp"
#include "parser.hpp"

void run(std::string code, bool printTokens, bool doNotParse) {
  auto lx = Lexer();
  lx.tokenize(code);
  if (printTokens) for (auto tok : lx.getTokens()) println(tok);
  if (doNotParse) return;
  auto px = Parser();
  px.parse(lx.getTokens());
  px.getTree().root.printTree(0);
}

int main(int argc, const char* argv[]) {
  try {
    TCLAP::CmdLine cmd("test-lang", ' ', "0.1.0");
    TCLAP::SwitchArg printTokens("t", "tokens", "Print token list", cmd);
    TCLAP::SwitchArg doNotParse("", "no-parse", "Don't parse the token list", cmd);
    TCLAP::ValueArg<std::string> code("e", "eval", "Code to evaluate", true, std::string(), "string", cmd);
    cmd.parse(argc, argv);
    run(code.getValue(), printTokens.getValue(), doNotParse.getValue());
  } catch (TCLAP::ArgException& arg) {
    std::cerr << "TCLAP error " << arg.error() << " for " << arg.argId() << std::endl;
  }
  return 0;
}
<commit_msg>Use AST::print<commit_after>#include <tclap/CmdLine.h>

#include "util.hpp"
#include "lexer.hpp"
#include "parser.hpp"

void run(std::string code, bool printTokens, bool doNotParse) {
  auto lx = Lexer();
  lx.tokenize(code);
  if (printTokens) for (auto tok : lx.getTokens()) println(tok);
  if (doNotParse) return;
  auto px = Parser();
  px.parse(lx.getTokens());
  px.getTree().print();
}

int main(int argc, const char* argv[]) {
  try {
    TCLAP::CmdLine cmd("test-lang", ' ', "0.1.0");
    TCLAP::SwitchArg printTokens("t", "tokens", "Print token list", cmd);
    TCLAP::SwitchArg doNotParse("", "no-parse", "Don't parse the token list", cmd);
    TCLAP::ValueArg<std::string> code("e", "eval", "Code to evaluate", true, std::string(), "string", cmd);
    cmd.parse(argc, argv);
    run(code.getValue(), printTokens.getValue(), doNotParse.getValue());
  } catch (TCLAP::ArgException& arg) {
    std::cerr << "TCLAP error " << arg.error() << " for " << arg.argId() << std::endl;
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <tuple>
#include <vector>
#include <typeinfo>

template <class Filter, class... Types>
struct filter;

template <class Filter, class... Types>
struct filter<Filter, std::tuple<Types...>>
{
	typedef filter<Filter, Types...> filter_;
	using type = typename filter_::type;
	using next = typename filter_::next;
	static constexpr size_t size = filter_::size;
};

template <class Filter, bool include_T0, class T0, class... Types>
struct filter_impl;

template <class Filter, class T0, class... Types>
struct filter_impl<Filter, true, T0, Types...>
{
	using type = T0;
	using next = filter<Filter, Types...>;
	static constexpr size_t size = next::size + 1;
};

template <class Filter, class T0, class... Types>
struct filter_impl<Filter, false, T0, Types...>
{
	typedef filter<Filter, Types...> next_;
	using type = typename next_::type;
	using next = typename next_::next;
	static constexpr size_t size = next_::size;
};

template <class Filter, class T0>
struct filter_impl<Filter, true, T0>
{
	using type = T0;
	using next = void;
	static constexpr size_t size = 1;
};

template <class Filter, class T0>
struct filter_impl<Filter, false, T0>
{
	using type = void;
	using next = void;
	static constexpr size_t size = 0;
};

template <class Filter, class T0, class... Types>
struct filter<Filter, T0, Types...>
{
	typedef filter_impl<Filter, Filter::template filter<T0>::result, T0, Types...> filtered;
	using type = typename filtered::type;
	using next = typename filtered::next;
	static constexpr size_t size = filtered::size;
};

template <size_t I, class Filter>
struct get_type
{
	using type = typename get_type<I-1, typename Filter::next>::type;
};

template <class Filter>
struct get_type<0, Filter>
{
	using type = typename Filter::type;
};

template <class Filter, class... T>
struct filter_to_tuple_impl;

template <class Filter, size_t... I>
struct filter_to_tuple_impl<Filter, std::index_sequence<I...>>
{
	using type = std::tuple<typename get_type<I, Filter>::type ...>;
};

template <class Filter>
using filter_to_tuple = typename filter_to_tuple_impl<Filter, std::make_index_sequence<Filter::size>>::type;

template <class Filter, class Tuple>
using filter_tuple = filter_to_tuple<filter<Filter, Tuple>>;

struct filter_is_integer
{
	template <class T>
	struct filter
	{
		static constexpr bool result = std::is_integral<T>::value;
	};
};

int main()
{
	using filtered_tuple = filter_tuple<filter_is_integer, std::tuple<std::string, int, std::string, short>>;
	static_assert(std::is_same<filtered_tuple, std::tuple<int, short>>::value, "not good!");
}
<commit_msg>Better version of filter_types by serge!<commit_after>#include <tuple>

namespace details {

template<class Pred, class...> struct filter;
template<class Pred, class Head, class... Tail>
struct filter<Pred, Head, Tail...> {
  using tail_type = typename filter<Pred, Tail...>::type;
  using type = typename std::conditional<Pred::template apply<Head>::value,
                                         decltype(std::tuple_cat(std::tuple<Head>(), tail_type())),
                                         tail_type
                                        >::type;
};
template<class Pred>
struct filter<Pred> {
  using type = std::tuple<>;
};

}

struct is_integral {
  template<class T>
  using apply = std::is_integral<T>;
};

template<class Pred, class Tuple> struct filter_tuple;
template<class Pred, class... Args>
struct filter_tuple<Pred, std::tuple<Args...>>
  : details::filter<Pred, Args...>
{
};

int main()
{
  using filtered_tuple = filter_tuple<is_integral, std::tuple<std::string, int, std::string, short>>::type;
  static_assert(std::is_same<filtered_tuple, std::tuple<int, short>>::value, "not good!");
}
<|endoftext|>


<commit_before>#include "blackmagicsdk_video_source.h"
#include "deck_link_display_mode_detector.h"
#include <chrono>

namespace gg
{

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK()
    : IVideoSource()
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(UYVY))
    , _running(false)
{
    // nop
}

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK(size_t deck_link_index,
                                                   ColourSpace colour)
    : IVideoSource(colour)
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(colour, false)) // TODO manage data?
    , _deck_link(nullptr)
    , _deck_link_input(nullptr)
    , _video_input_flags(bmdVideoInputFlagDefault | bmdVideoInputDualStream3D)
    , _12_bit_rgb_to_bgra_converter(nullptr)
    , _bgra_frame_buffers{nullptr, nullptr}
    , _running(false)
{
    // Pixel format, i.e. colour space
    BMDPixelFormat pixel_format;
    switch(_colour)
    {
    case UYVY:
        pixel_format = bmdFormat8BitYUV;
        break;
    case BGRA:
        // We currently only support BGRA with DeckLink 4K Extreme 12G,
        // and that card supports only this YUV format:
        pixel_format = bmdFormat10BitYUV;
        break;
    case I420:
    default:
        bail("BlackmagicSDK video source supports only UYVY and BGRA colour spaces");
    }

    // Get an iterator through the available DeckLink ports
    IDeckLinkIterator * deck_link_iterator = CreateDeckLinkIteratorInstance();
    if (deck_link_iterator == nullptr)
        bail("DeckLink drivers do not appear to be installed");

    HRESULT res;

    // Get the desired DeckLink index (port)
    int idx = deck_link_index;
    while ((res = deck_link_iterator->Next(&_deck_link)) == S_OK)
    {
        if (idx == 0)
            break;
        --idx;

        _deck_link->Release();
    }
    if (deck_link_iterator != nullptr)
        deck_link_iterator->Release();
    // No glory: release everything and throw exception
    if (res != S_OK or _deck_link == nullptr)
        bail(
            std::string("Could not get DeckLink device ").append(std::to_string(deck_link_index))
        );

    // Get the input interface of connected DeckLink port
    res = _deck_link->QueryInterface(IID_IDeckLinkInput, reinterpret_cast<void **>(&_deck_link_input));
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not get the Blackmagic DeckLink input interface");

    // Set the input format (i.e. display mode)
    BMDDisplayMode display_mode;
    BMDFrameFlags frame_flags;
    std::string error_msg = "";
    size_t cols = 0, rows = 0;
    if (not detect_input_format(pixel_format, _video_input_flags, display_mode,
                                _frame_rate, cols, rows, frame_flags, error_msg))
    {
        _video_input_flags ^= bmdVideoInputDualStream3D;
        if (not detect_input_format(pixel_format, _video_input_flags, display_mode,
                                    _frame_rate, cols, rows, frame_flags, error_msg))
            bail(error_msg);
    }

    // Get a post-capture converter if necessary
    if (_colour == BGRA)
    {
        _12_bit_rgb_to_bgra_converter = CreateVideoConversionInstance();
        if (_12_bit_rgb_to_bgra_converter == nullptr)
            bail("Could not create colour converter for Blackmagic source");
    }

    // Set this object (IDeckLinkInputCallback instance) as callback
    res = _deck_link_input->SetCallback(this);
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not set the callback of Blackmagic DeckLink device");

    // Enable video input
    res = _deck_link_input->EnableVideoInput(display_mode,
                                             pixel_format,
                                             _video_input_flags);
    // No glory
    if (res != S_OK)
        bail("Could not enable video input of Blackmagic DeckLink device");

    // Start streaming
    _running = true;
    res = _deck_link_input->StartStreams();
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        _running = false;
        bail("Could not start streaming from the Blackmagic DeckLink device");
    }
}

VideoSourceBlackmagicSDK::~VideoSourceBlackmagicSDK()
{
    { // Artificial scope for data lock
        // Make sure streamer thread not trying to access buffer
        std::lock_guard<std::mutex> data_lock_guard(_data_lock);
        _running = false;
    }

    // Stop streaming and disable enabled inputs
    _deck_link_input->SetCallback(nullptr);
    _deck_link_input->StopStreams();
    _deck_link_input->DisableVideoInput();

    // Release DeckLink members
    release_deck_link();
}

bool VideoSourceBlackmagicSDK::get_frame_dimensions(int & width, int & height)
{
    // Make sure only this thread is accessing the cols and rows members now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    if (_cols <= 0 or _rows <= 0)
        return false;

    width = _cols;
    height = _rows;
    return true;
}

bool VideoSourceBlackmagicSDK::get_frame(VideoFrame & frame)
{
    if (frame.colour() != _colour)
        return false;

    // Make sure only this thread is accessing the video frame data now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    if (_video_buffer_length > 0 and _cols > 0 and _rows > 0)
    {
        frame.init_from_specs(_video_buffer, _video_buffer_length, _cols, _rows);
        return true;
    }
    else
        return false;
}

double VideoSourceBlackmagicSDK::get_frame_rate()
{
    return _frame_rate;
}

void VideoSourceBlackmagicSDK::set_sub_frame(int x, int y, int width, int height)
{
    // issue #147
    throw VideoSourceError("Blackmagic does not support cropping yet");
}

void VideoSourceBlackmagicSDK::get_full_frame()
{
    // nop: set_sub_frame currently not implemented
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::QueryInterface(REFIID iid, LPVOID * ppv)
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::AddRef(void)
{
    __sync_add_and_fetch(&_n_ref, 1);
    return _n_ref;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::Release(void)
{
    __sync_sub_and_fetch(&_n_ref, 1);
    return _n_ref;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFormatChanged(
    BMDVideoInputFormatChangedEvents events,
    IDeckLinkDisplayMode * display_mode,
    BMDDetectedVideoInputFormatFlags format_flags
)
{
    // not supported yet: see issue #149
    return S_OK;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame * video_frame,
    IDeckLinkAudioInputPacket * audio_packet
)
{
    if (not _running)
        // nop if not running!
        return S_OK;

    // Not processing the audio packet, but only the video
    // frame for the time being
    if (video_frame == nullptr)
        // nop if no data
        return S_OK;

    smart_allocate_buffers(
        video_frame->GetWidth(), video_frame->GetHeight(),
        video_frame->GetFlags()
    );

    { // Artificial scope for data lock
        // Make sure only this thread is accessing the buffer now
        std::lock_guard<std::mutex> data_lock_guard(_data_lock);

        if (_video_buffer == nullptr) // something's terribly wrong!
            // nop if something's terribly wrong!
            return S_OK;

        HRESULT res;

        if (need_conversion())
            // convert to BGRA from capture format
            res = _12_bit_rgb_to_bgra_converter->ConvertFrame(
                video_frame, _bgra_frame_buffers[0]
            );
        else
            // Get the new data into the buffer
            res = video_frame->GetBytes(
                reinterpret_cast<void **>(&_video_buffer)
            );

        // If the last operation failed, return
        if (FAILED(res))
            return res;

        if (is_stereo())
        {
            IDeckLinkVideoFrame *right_eye_frame = nullptr;
            IDeckLinkVideoFrame3DExtensions *three_d_extensions = nullptr;
            if ((video_frame->QueryInterface(
                    IID_IDeckLinkVideoFrame3DExtensions,
                    (void **) &three_d_extensions) != S_OK) ||
                (three_d_extensions->GetFrameForRightEye(
                    &right_eye_frame) != S_OK))
            {
                right_eye_frame = nullptr;
            }

            if (three_d_extensions != nullptr)
                three_d_extensions->Release();

            if (right_eye_frame != nullptr)
            {
                if (need_conversion())
                    // convert to BGRA from capture format
                    res = _12_bit_rgb_to_bgra_converter->ConvertFrame(
                        right_eye_frame, _bgra_frame_buffers[1]
                    );
                else
                    res = right_eye_frame->GetBytes(
                        reinterpret_cast<void **>(&_video_buffer[_video_buffer_length / 2])
                    );
                right_eye_frame->Release();
                // If data could not be read into the buffer, return
                if (FAILED(res))
                    return res;
            }
        }

        // Propagate new video frame to observers
        _buffer_video_frame.init_from_specs(
            _video_buffer, _video_buffer_length, _cols, _rows,
            is_stereo() ? 2 : 1
        );
    }

    this->notify(_buffer_video_frame);

    // Everything went fine, return success
    return S_OK;
}

void VideoSourceBlackmagicSDK::release_deck_link() noexcept
{
    if (_deck_link_input != nullptr)
    {
        _deck_link_input->Release();
        _deck_link_input = nullptr;
    }

    if (_deck_link != nullptr)
        _deck_link->Release();

    if (_12_bit_rgb_to_bgra_converter != nullptr)
    {
        _12_bit_rgb_to_bgra_converter->Release();
        _12_bit_rgb_to_bgra_converter = nullptr;
    }

    for (size_t i = 0; i < 2; i++)
        if (_bgra_frame_buffers[i] != nullptr)
        {
            _bgra_frame_buffers[i]->Release();
            delete _bgra_frame_buffers[i];
            _bgra_frame_buffers[i] = nullptr;
        }
}

inline void VideoSourceBlackmagicSDK::smart_allocate_buffers(
    size_t cols, size_t rows, BMDFrameFlags frame_flags
) noexcept
{
    if (cols <= 0 or rows <= 0)
        return;

    if (cols == _cols and rows == _rows)
        return;

    _cols = cols;
    _rows = rows;

    // Allocate pixel buffer
    _video_buffer_length = VideoFrame::required_data_length(_colour, _cols, _rows);
    if (is_stereo())
        _video_buffer_length *= 2;
    _video_buffer = reinterpret_cast<uint8_t *>(
        realloc(_video_buffer, _video_buffer_length * sizeof(uint8_t))
    );

    // Colour converter for post-capture colour conversion
    if (need_conversion())
    {
        for (size_t i = 0; i < (is_stereo() ? 2 : 1); i++)
        {
            if (_bgra_frame_buffers[i] != nullptr)
            {
                _bgra_frame_buffers[i]->Release();
                delete _bgra_frame_buffers[i];
                _bgra_frame_buffers[i] = nullptr;
            }
            _bgra_frame_buffers[i] = new DeckLinkBGRAVideoFrame(
                _cols, _rows,
                &_video_buffer[i * _video_buffer_length / 2], frame_flags
            );
        }
    }
}

bool VideoSourceBlackmagicSDK::detect_input_format(BMDPixelFormat pixel_format,
                                                   BMDVideoInputFlags & video_input_flags,
                                                   BMDDisplayMode & display_mode,
                                                   double & frame_rate,
                                                   size_t & cols, size_t & rows,
                                                   BMDFrameFlags & frame_flags,
                                                   std::string & error_msg) noexcept
{
    std::vector<BMDDisplayMode> display_modes =
    {
        bmdModeHD1080p6000, bmdModeHD1080p5994,
        bmdModeHD1080p50,
        bmdModeHD1080p30, bmdModeHD1080p2997,
        bmdModeHD1080p25, bmdModeHD1080p24, bmdModeHD1080p2398,
        bmdModeHD1080i6000, bmdModeHD1080i5994,
        bmdModeHD1080i50,
        bmdModeHD720p60, bmdModeHD720p5994,
        bmdModeHD720p50,
        bmdMode4K2160p60, bmdMode4K2160p5994,
        bmdMode4K2160p50,
        bmdMode4K2160p30, bmdMode4K2160p2997,
        bmdMode4K2160p25, bmdMode4K2160p24, bmdMode4K2160p2398,
        bmdMode2k25, bmdMode2k24, bmdMode2k2398,
    };

    DeckLinkDisplayModeDetector detector(
                _deck_link_input,
                display_modes, pixel_format, video_input_flags
    );
    BMDDisplayMode display_mode_ = detector.get_display_mode();
    if (display_mode_ != bmdModeUnknown)
    {
        frame_rate = detector.get_frame_rate();
        detector.get_frame_dimensions(cols, rows);
        frame_flags = detector.get_frame_flags();
        display_mode = display_mode_;
        video_input_flags = detector.get_video_input_flags();
        return true;
    }
    else
    {
        error_msg = detector.get_error_msg();
        return false;
    }
}

}
<commit_msg>Issue #30: doing smart buffer allocation within the mutex scope<commit_after>#include "blackmagicsdk_video_source.h"
#include "deck_link_display_mode_detector.h"
#include <chrono>

namespace gg
{

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK()
    : IVideoSource()
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(UYVY))
    , _running(false)
{
    // nop
}

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK(size_t deck_link_index,
                                                   ColourSpace colour)
    : IVideoSource(colour)
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(colour, false)) // TODO manage data?
    , _deck_link(nullptr)
    , _deck_link_input(nullptr)
    , _video_input_flags(bmdVideoInputFlagDefault | bmdVideoInputDualStream3D)
    , _12_bit_rgb_to_bgra_converter(nullptr)
    , _bgra_frame_buffers{nullptr, nullptr}
    , _running(false)
{
    // Pixel format, i.e. colour space
    BMDPixelFormat pixel_format;
    switch(_colour)
    {
    case UYVY:
        pixel_format = bmdFormat8BitYUV;
        break;
    case BGRA:
        // We currently only support BGRA with DeckLink 4K Extreme 12G,
        // and that card supports only this YUV format:
        pixel_format = bmdFormat10BitYUV;
        break;
    case I420:
    default:
        bail("BlackmagicSDK video source supports only UYVY and BGRA colour spaces");
    }

    // Get an iterator through the available DeckLink ports
    IDeckLinkIterator * deck_link_iterator = CreateDeckLinkIteratorInstance();
    if (deck_link_iterator == nullptr)
        bail("DeckLink drivers do not appear to be installed");

    HRESULT res;

    // Get the desired DeckLink index (port)
    int idx = deck_link_index;
    while ((res = deck_link_iterator->Next(&_deck_link)) == S_OK)
    {
        if (idx == 0)
            break;
        --idx;

        _deck_link->Release();
    }
    if (deck_link_iterator != nullptr)
        deck_link_iterator->Release();
    // No glory: release everything and throw exception
    if (res != S_OK or _deck_link == nullptr)
        bail(
            std::string("Could not get DeckLink device ").append(std::to_string(deck_link_index))
        );

    // Get the input interface of connected DeckLink port
    res = _deck_link->QueryInterface(IID_IDeckLinkInput, reinterpret_cast<void **>(&_deck_link_input));
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not get the Blackmagic DeckLink input interface");

    // Set the input format (i.e. display mode)
    BMDDisplayMode display_mode;
    BMDFrameFlags frame_flags;
    std::string error_msg = "";
    size_t cols = 0, rows = 0;
    if (not detect_input_format(pixel_format, _video_input_flags, display_mode,
                                _frame_rate, cols, rows, frame_flags, error_msg))
    {
        _video_input_flags ^= bmdVideoInputDualStream3D;
        if (not detect_input_format(pixel_format, _video_input_flags, display_mode,
                                    _frame_rate, cols, rows, frame_flags, error_msg))
            bail(error_msg);
    }

    // Get a post-capture converter if necessary
    if (_colour == BGRA)
    {
        _12_bit_rgb_to_bgra_converter = CreateVideoConversionInstance();
        if (_12_bit_rgb_to_bgra_converter == nullptr)
            bail("Could not create colour converter for Blackmagic source");
    }

    // Set this object (IDeckLinkInputCallback instance) as callback
    res = _deck_link_input->SetCallback(this);
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not set the callback of Blackmagic DeckLink device");

    // Enable video input
    res = _deck_link_input->EnableVideoInput(display_mode,
                                             pixel_format,
                                             _video_input_flags);
    // No glory
    if (res != S_OK)
        bail("Could not enable video input of Blackmagic DeckLink device");

    // Start streaming
    _running = true;
    res = _deck_link_input->StartStreams();
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        _running = false;
        bail("Could not start streaming from the Blackmagic DeckLink device");
    }
}

VideoSourceBlackmagicSDK::~VideoSourceBlackmagicSDK()
{
    { // Artificial scope for data lock
        // Make sure streamer thread not trying to access buffer
        std::lock_guard<std::mutex> data_lock_guard(_data_lock);
        _running = false;
    }

    // Stop streaming and disable enabled inputs
    _deck_link_input->SetCallback(nullptr);
    _deck_link_input->StopStreams();
    _deck_link_input->DisableVideoInput();

    // Release DeckLink members
    release_deck_link();
}

bool VideoSourceBlackmagicSDK::get_frame_dimensions(int & width, int & height)
{
    // Make sure only this thread is accessing the cols and rows members now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    if (_cols <= 0 or _rows <= 0)
        return false;

    width = _cols;
    height = _rows;
    return true;
}

bool VideoSourceBlackmagicSDK::get_frame(VideoFrame & frame)
{
    if (frame.colour() != _colour)
        return false;

    // Make sure only this thread is accessing the video frame data now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    if (_video_buffer_length > 0 and _cols > 0 and _rows > 0)
    {
        frame.init_from_specs(_video_buffer, _video_buffer_length, _cols, _rows);
        return true;
    }
    else
        return false;
}

double VideoSourceBlackmagicSDK::get_frame_rate()
{
    return _frame_rate;
}

void VideoSourceBlackmagicSDK::set_sub_frame(int x, int y, int width, int height)
{
    // issue #147
    throw VideoSourceError("Blackmagic does not support cropping yet");
}

void VideoSourceBlackmagicSDK::get_full_frame()
{
    // nop: set_sub_frame currently not implemented
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::QueryInterface(REFIID iid, LPVOID * ppv)
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::AddRef(void)
{
    __sync_add_and_fetch(&_n_ref, 1);
    return _n_ref;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::Release(void)
{
    __sync_sub_and_fetch(&_n_ref, 1);
    return _n_ref;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFormatChanged(
    BMDVideoInputFormatChangedEvents events,
    IDeckLinkDisplayMode * display_mode,
    BMDDetectedVideoInputFormatFlags format_flags
)
{
    // not supported yet: see issue #149
    return S_OK;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame * video_frame,
    IDeckLinkAudioInputPacket * audio_packet
)
{
    if (not _running)
        // nop if not running!
        return S_OK;

    // Not processing the audio packet, but only the video
    // frame for the time being
    if (video_frame == nullptr)
        // nop if no data
        return S_OK;

    { // Artificial scope for data lock
        smart_allocate_buffers(
            video_frame->GetWidth(), video_frame->GetHeight(),
            video_frame->GetFlags()
        );

        // Make sure only this thread is accessing the buffer now
        std::lock_guard<std::mutex> data_lock_guard(_data_lock);

        if (_video_buffer == nullptr) // something's terribly wrong!
            // nop if something's terribly wrong!
            return S_OK;

        HRESULT res;

        if (need_conversion())
            // convert to BGRA from capture format
            res = _12_bit_rgb_to_bgra_converter->ConvertFrame(
                video_frame, _bgra_frame_buffers[0]
            );
        else
            // Get the new data into the buffer
            res = video_frame->GetBytes(
                reinterpret_cast<void **>(&_video_buffer)
            );

        // If the last operation failed, return
        if (FAILED(res))
            return res;

        if (is_stereo())
        {
            IDeckLinkVideoFrame *right_eye_frame = nullptr;
            IDeckLinkVideoFrame3DExtensions *three_d_extensions = nullptr;
            if ((video_frame->QueryInterface(
                    IID_IDeckLinkVideoFrame3DExtensions,
                    (void **) &three_d_extensions) != S_OK) ||
                (three_d_extensions->GetFrameForRightEye(
                    &right_eye_frame) != S_OK))
            {
                right_eye_frame = nullptr;
            }

            if (three_d_extensions != nullptr)
                three_d_extensions->Release();

            if (right_eye_frame != nullptr)
            {
                if (need_conversion())
                    // convert to BGRA from capture format
                    res = _12_bit_rgb_to_bgra_converter->ConvertFrame(
                        right_eye_frame, _bgra_frame_buffers[1]
                    );
                else
                    res = right_eye_frame->GetBytes(
                        reinterpret_cast<void **>(&_video_buffer[_video_buffer_length / 2])
                    );
                right_eye_frame->Release();
                // If data could not be read into the buffer, return
                if (FAILED(res))
                    return res;
            }
        }

        // Propagate new video frame to observers
        _buffer_video_frame.init_from_specs(
            _video_buffer, _video_buffer_length, _cols, _rows,
            is_stereo() ? 2 : 1
        );
    }

    this->notify(_buffer_video_frame);

    // Everything went fine, return success
    return S_OK;
}

void VideoSourceBlackmagicSDK::release_deck_link() noexcept
{
    if (_deck_link_input != nullptr)
    {
        _deck_link_input->Release();
        _deck_link_input = nullptr;
    }

    if (_deck_link != nullptr)
        _deck_link->Release();

    if (_12_bit_rgb_to_bgra_converter != nullptr)
    {
        _12_bit_rgb_to_bgra_converter->Release();
        _12_bit_rgb_to_bgra_converter = nullptr;
    }

    for (size_t i = 0; i < 2; i++)
        if (_bgra_frame_buffers[i] != nullptr)
        {
            _bgra_frame_buffers[i]->Release();
            delete _bgra_frame_buffers[i];
            _bgra_frame_buffers[i] = nullptr;
        }
}

inline void VideoSourceBlackmagicSDK::smart_allocate_buffers(
    size_t cols, size_t rows, BMDFrameFlags frame_flags
) noexcept
{
    if (cols <= 0 or rows <= 0)
        return;

    if (cols == _cols and rows == _rows)
        return;

    _cols = cols;
    _rows = rows;

    // Allocate pixel buffer
    _video_buffer_length = VideoFrame::required_data_length(_colour, _cols, _rows);
    if (is_stereo())
        _video_buffer_length *= 2;
    _video_buffer = reinterpret_cast<uint8_t *>(
        realloc(_video_buffer, _video_buffer_length * sizeof(uint8_t))
    );

    // Colour converter for post-capture colour conversion
    if (need_conversion())
    {
        for (size_t i = 0; i < (is_stereo() ? 2 : 1); i++)
        {
            if (_bgra_frame_buffers[i] != nullptr)
            {
                _bgra_frame_buffers[i]->Release();
                delete _bgra_frame_buffers[i];
                _bgra_frame_buffers[i] = nullptr;
            }
            _bgra_frame_buffers[i] = new DeckLinkBGRAVideoFrame(
                _cols, _rows,
                &_video_buffer[i * _video_buffer_length / 2], frame_flags
            );
        }
    }
}

bool VideoSourceBlackmagicSDK::detect_input_format(BMDPixelFormat pixel_format,
                                                   BMDVideoInputFlags & video_input_flags,
                                                   BMDDisplayMode & display_mode,
                                                   double & frame_rate,
                                                   size_t & cols, size_t & rows,
                                                   BMDFrameFlags & frame_flags,
                                                   std::string & error_msg) noexcept
{
    std::vector<BMDDisplayMode> display_modes =
    {
        bmdModeHD1080p6000, bmdModeHD1080p5994,
        bmdModeHD1080p50,
        bmdModeHD1080p30, bmdModeHD1080p2997,
        bmdModeHD1080p25, bmdModeHD1080p24, bmdModeHD1080p2398,
        bmdModeHD1080i6000, bmdModeHD1080i5994,
        bmdModeHD1080i50,
        bmdModeHD720p60, bmdModeHD720p5994,
        bmdModeHD720p50,
        bmdMode4K2160p60, bmdMode4K2160p5994,
        bmdMode4K2160p50,
        bmdMode4K2160p30, bmdMode4K2160p2997,
        bmdMode4K2160p25, bmdMode4K2160p24, bmdMode4K2160p2398,
        bmdMode2k25, bmdMode2k24, bmdMode2k2398,
    };

    DeckLinkDisplayModeDetector detector(
                _deck_link_input,
                display_modes, pixel_format, video_input_flags
    );
    BMDDisplayMode display_mode_ = detector.get_display_mode();
    if (display_mode_ != bmdModeUnknown)
    {
        frame_rate = detector.get_frame_rate();
        detector.get_frame_dimensions(cols, rows);
        frame_flags = detector.get_frame_flags();
        display_mode = display_mode_;
        video_input_flags = detector.get_video_input_flags();
        return true;
    }
    else
    {
        error_msg = detector.get_error_msg();
        return false;
    }
}

}
<|endoftext|>


<commit_before>#include "clustering/administration/main/cache_size.hpp"

#include <inttypes.h>
#include <stddef.h>
#include <unistd.h>

#include <limits>
#include <string>

#include "arch/runtime/thread_pool.hpp"
#include "arch/types.hpp"
#include "logger.hpp"
#include "utils.hpp"

#if defined(__MACH__)
#include <availability.h>
#include <mach/mach.h>
#endif

#ifndef __MACH__

size_t skip_spaces(const std::string &s, size_t i) {
    while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) {
        ++i;
    }
    return i;
}

bool parse_meminfo_line(const std::string &contents, size_t *offset_ref,
                        std::string *name_out,
                        uint64_t *value_out,
                        std::string *unit_out) {
    const size_t line_begin = *offset_ref;
    size_t line_end = contents.find('\n', line_begin);
    if (line_end == std::string::npos) {
        line_end = contents.size();
        *offset_ref = line_end;
    } else {
        *offset_ref = line_end + 1;
    }

    const std::string line = contents.substr(line_begin, line_end - line_begin);

    const size_t colon = line.find(':');
    if (colon == std::string::npos) {
        return false;
    }
    size_t i = skip_spaces(line, colon + 1);

    const size_t number_begin = i;
    while (i < line.size() && '0' <= line[i] && '9' >= line[i]) {
        ++i;
    }
    const size_t number_end = i;

    if (number_begin == number_end) {
        return false;
    }

    const size_t unit_begin = skip_spaces(line, i);
    size_t unit_end = line.find_first_of(" \t", unit_begin);
    if (unit_end == std::string::npos) {
        unit_end = line.size();
    }

    const size_t end = skip_spaces(line, unit_end);
    if (end != line.size()) {
        return false;
    }

    *name_out = line.substr(0, colon);
    if (!strtou64_strict(line.substr(number_begin, number_end - number_begin),
                         10,
                         value_out)) {
        return false;
    }
    *unit_out = line.substr(unit_begin, unit_end - unit_begin);
    return true;
}

bool parse_meminfo_file(const std::string &contents, uint64_t *mem_avail_out) {
    uint64_t memfree = 0;
    uint64_t cached = 0;

    bool seen_memfree = false;
    bool seen_cached = false;

    size_t offset = 0;
    std::string name;
    uint64_t value;
    std::string unit;
    while (parse_meminfo_line(contents, &offset, &name, &value, &unit)) {
        if (name == "MemFree") {
            if (seen_memfree) {
                return false;
            }
            if (unit != "kB") {
                return false;
            }
            seen_memfree = true;
            memfree = value * KILOBYTE;
        } else if (name == "Cached") {
            if (seen_cached) {
                return false;
            }
            if (unit != "kB") {
                return false;
            }
            seen_cached = true;
            cached = value * KILOBYTE;
        }

        if (seen_memfree && seen_cached) {
            break;
        }
    }

    if (seen_memfree && seen_cached) {
        *mem_avail_out = memfree + cached;
        return true;
    } else {
        return false;
    }
}

bool get_proc_meminfo_available_memory_size(uint64_t *mem_avail_out) {
    std::string contents;
    bool ok;
    thread_pool_t::run_in_blocker_pool([&]() {
        ok = blocking_read_file("/proc/meminfo", &contents);
    });
    if (!ok) {
        return false;
    }
    return parse_meminfo_file(contents, mem_avail_out);
}

#endif  // __MACH_

uint64_t get_avail_mem_size() {
    uint64_t page_size = sysconf(_SC_PAGESIZE);

#if defined(__MACH__)
    mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
    vm_statistics64_data_t vmstat;
    // We memset this struct to zero because of zero-knowledge paranoia that some old
    // system might use a shorter version of the struct, where it would not set the
    // vmstat.external_page_count field (which is relatively new) that we use below.
    // (Probably, instead, the host_statistics64 call will fail, because count would
    // be wrong.)
    memset(&vmstat, 0, sizeof(vmstat));
    if (KERN_SUCCESS != host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count)) {
        logERR("Could not determine available RAM for the default cache size "
            "(errno=%d).\n", get_errno());
        return 1024 * MEGABYTE;
    }
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
    // We know the field we want showed up in 10.9.  It may have shown
    // up in 10.8, but is definitely not in 10.7.  Per availability.h,
    // we use a raw number rather than the corresponding #define.
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
    uint64_t ret = vmstat.free_count * page_size;
#else
    // external_page_count is the number of pages that are file-backed (non-swap) --
    // see /usr/include/mach/vm_statistics.h, see also vm_stat.c, the implementation
    // of vm_stat, in Darwin.
    uint64_t ret = (vmstat.free_count + vmstat.external_page_count) * page_size;
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
#else
#error "We don't support Mach kernels other than OS X, sorry."
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
    return ret;
#else
    {
        uint64_t memory;
        if (get_proc_meminfo_available_memory_size(&memory)) {
            return memory;
        } else {
            logERR("Could not parse /proc/meminfo, so we will treat cached file memory "
                "as if it were unavailable.");

            // This just returns what /proc/meminfo would report as "MemFree".
            uint64_t avail_mem_pages = sysconf(_SC_AVPHYS_PAGES);
            return avail_mem_pages * page_size;
        }
    }
#endif
}

uint64_t get_max_total_cache_size() {
    /* We're checking for two things here:
     1. That the cache size is not larger than the amount of RAM that a pointer can
        address. This is for 32-bit systems.
     2. That the cache size is not larger than a petabyte. This is partially to catch
        people who think the cache size is specified in bytes rather than megabytes. But
        it also serves the purpose of making it so that the max total cache size easily
        fits into a 64-bit integer, so that we can test the code path where
        `validate_total_cache_size()` fails even on a 64-bit system. When hardware
        advances to the point where a petabyte of RAM is plausible for a server, we'll
        increase the limit. */
    return std::min(
        static_cast<uint64_t>(std::numeric_limits<intptr_t>::max()),
        static_cast<uint64_t>(MEGABYTE) * static_cast<uint64_t>(GIGABYTE));
}

uint64_t get_default_total_cache_size() {
    const int64_t available_mem = get_avail_mem_size();

    // Default to half the available memory minus a gigabyte, to leave room for server
    // and query overhead, but never default to less than 100 megabytes
    const int64_t signed_res =
        std::min<int64_t>(available_mem - GIGABYTE, get_max_total_cache_size()) /
        DEFAULT_MAX_CACHE_RATIO;
    const uint64_t res = std::max<int64_t>(signed_res, 100 * MEGABYTE);
    return res;
}

void log_warnings_for_cache_size(uint64_t bytes) {
    const uint64_t available_memory = get_avail_mem_size();
    if (bytes > available_memory) {
        logWRN("Cache size is larger than available memory.");
    } else if (bytes + GIGABYTE > available_memory) {
        logWRN("Cache size does not leave much memory for server and query "
               "overhead (available memory: %" PRIu64 " MB).",
               available_memory / static_cast<uint64_t>(MEGABYTE));
    }
    if (bytes <= 100 * MEGABYTE) {
        logWRN("Cache size is very low and may impact performance.");
    }
}
<commit_msg>Move Mach headers up to system header section.<commit_after>#include "clustering/administration/main/cache_size.hpp"

#include <inttypes.h>
#include <stddef.h>
#include <unistd.h>

#if defined(__MACH__)
#include <availability.h>
#include <mach/mach.h>
#endif

#include <limits>
#include <string>

#include "arch/runtime/thread_pool.hpp"
#include "arch/types.hpp"
#include "logger.hpp"
#include "utils.hpp"

#ifndef __MACH__

size_t skip_spaces(const std::string &s, size_t i) {
    while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) {
        ++i;
    }
    return i;
}

bool parse_meminfo_line(const std::string &contents, size_t *offset_ref,
                        std::string *name_out,
                        uint64_t *value_out,
                        std::string *unit_out) {
    const size_t line_begin = *offset_ref;
    size_t line_end = contents.find('\n', line_begin);
    if (line_end == std::string::npos) {
        line_end = contents.size();
        *offset_ref = line_end;
    } else {
        *offset_ref = line_end + 1;
    }

    const std::string line = contents.substr(line_begin, line_end - line_begin);

    const size_t colon = line.find(':');
    if (colon == std::string::npos) {
        return false;
    }
    size_t i = skip_spaces(line, colon + 1);

    const size_t number_begin = i;
    while (i < line.size() && '0' <= line[i] && '9' >= line[i]) {
        ++i;
    }
    const size_t number_end = i;

    if (number_begin == number_end) {
        return false;
    }

    const size_t unit_begin = skip_spaces(line, i);
    size_t unit_end = line.find_first_of(" \t", unit_begin);
    if (unit_end == std::string::npos) {
        unit_end = line.size();
    }

    const size_t end = skip_spaces(line, unit_end);
    if (end != line.size()) {
        return false;
    }

    *name_out = line.substr(0, colon);
    if (!strtou64_strict(line.substr(number_begin, number_end - number_begin),
                         10,
                         value_out)) {
        return false;
    }
    *unit_out = line.substr(unit_begin, unit_end - unit_begin);
    return true;
}

bool parse_meminfo_file(const std::string &contents, uint64_t *mem_avail_out) {
    uint64_t memfree = 0;
    uint64_t cached = 0;

    bool seen_memfree = false;
    bool seen_cached = false;

    size_t offset = 0;
    std::string name;
    uint64_t value;
    std::string unit;
    while (parse_meminfo_line(contents, &offset, &name, &value, &unit)) {
        if (name == "MemFree") {
            if (seen_memfree) {
                return false;
            }
            if (unit != "kB") {
                return false;
            }
            seen_memfree = true;
            memfree = value * KILOBYTE;
        } else if (name == "Cached") {
            if (seen_cached) {
                return false;
            }
            if (unit != "kB") {
                return false;
            }
            seen_cached = true;
            cached = value * KILOBYTE;
        }

        if (seen_memfree && seen_cached) {
            break;
        }
    }

    if (seen_memfree && seen_cached) {
        *mem_avail_out = memfree + cached;
        return true;
    } else {
        return false;
    }
}

bool get_proc_meminfo_available_memory_size(uint64_t *mem_avail_out) {
    std::string contents;
    bool ok;
    thread_pool_t::run_in_blocker_pool([&]() {
        ok = blocking_read_file("/proc/meminfo", &contents);
    });
    if (!ok) {
        return false;
    }
    return parse_meminfo_file(contents, mem_avail_out);
}

#endif  // __MACH_

uint64_t get_avail_mem_size() {
    uint64_t page_size = sysconf(_SC_PAGESIZE);

#if defined(__MACH__)
    mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
    vm_statistics64_data_t vmstat;
    // We memset this struct to zero because of zero-knowledge paranoia that some old
    // system might use a shorter version of the struct, where it would not set the
    // vmstat.external_page_count field (which is relatively new) that we use below.
    // (Probably, instead, the host_statistics64 call will fail, because count would
    // be wrong.)
    memset(&vmstat, 0, sizeof(vmstat));
    if (KERN_SUCCESS != host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count)) {
        logERR("Could not determine available RAM for the default cache size "
            "(errno=%d).\n", get_errno());
        return 1024 * MEGABYTE;
    }
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
    // We know the field we want showed up in 10.9.  It may have shown
    // up in 10.8, but is definitely not in 10.7.  Per availability.h,
    // we use a raw number rather than the corresponding #define.
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
    uint64_t ret = vmstat.free_count * page_size;
#else
    // external_page_count is the number of pages that are file-backed (non-swap) --
    // see /usr/include/mach/vm_statistics.h, see also vm_stat.c, the implementation
    // of vm_stat, in Darwin.
    uint64_t ret = (vmstat.free_count + vmstat.external_page_count) * page_size;
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
#else
#error "We don't support Mach kernels other than OS X, sorry."
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
    return ret;
#else
    {
        uint64_t memory;
        if (get_proc_meminfo_available_memory_size(&memory)) {
            return memory;
        } else {
            logERR("Could not parse /proc/meminfo, so we will treat cached file memory "
                "as if it were unavailable.");

            // This just returns what /proc/meminfo would report as "MemFree".
            uint64_t avail_mem_pages = sysconf(_SC_AVPHYS_PAGES);
            return avail_mem_pages * page_size;
        }
    }
#endif
}

uint64_t get_max_total_cache_size() {
    /* We're checking for two things here:
     1. That the cache size is not larger than the amount of RAM that a pointer can
        address. This is for 32-bit systems.
     2. That the cache size is not larger than a petabyte. This is partially to catch
        people who think the cache size is specified in bytes rather than megabytes. But
        it also serves the purpose of making it so that the max total cache size easily
        fits into a 64-bit integer, so that we can test the code path where
        `validate_total_cache_size()` fails even on a 64-bit system. When hardware
        advances to the point where a petabyte of RAM is plausible for a server, we'll
        increase the limit. */
    return std::min(
        static_cast<uint64_t>(std::numeric_limits<intptr_t>::max()),
        static_cast<uint64_t>(MEGABYTE) * static_cast<uint64_t>(GIGABYTE));
}

uint64_t get_default_total_cache_size() {
    const int64_t available_mem = get_avail_mem_size();

    // Default to half the available memory minus a gigabyte, to leave room for server
    // and query overhead, but never default to less than 100 megabytes
    const int64_t signed_res =
        std::min<int64_t>(available_mem - GIGABYTE, get_max_total_cache_size()) /
        DEFAULT_MAX_CACHE_RATIO;
    const uint64_t res = std::max<int64_t>(signed_res, 100 * MEGABYTE);
    return res;
}

void log_warnings_for_cache_size(uint64_t bytes) {
    const uint64_t available_memory = get_avail_mem_size();
    if (bytes > available_memory) {
        logWRN("Cache size is larger than available memory.");
    } else if (bytes + GIGABYTE > available_memory) {
        logWRN("Cache size does not leave much memory for server and query "
               "overhead (available memory: %" PRIu64 " MB).",
               available_memory / static_cast<uint64_t>(MEGABYTE));
    }
    if (bytes <= 100 * MEGABYTE) {
        logWRN("Cache size is very low and may impact performance.");
    }
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sstream>

#include "timing.h"
#include "converter.h"
#include "procs.h"
#include "config.h"

namespace Converter {

  Converter::Converter(){
    fillFFMpegEncoders();
  }

  void Converter::fillFFMpegEncoders(){
    std::vector<char*> cmd;
    cmd.reserve(3);
    cmd.push_back((char*)"ffmpeg");
    cmd.push_back((char*)"-encoders");
    cmd.push_back(NULL);
    int outFD = -1;
    Util::Procs::StartPiped("FFMpegInfo", &cmd[0], 0, &outFD, 0);
    while( Util::Procs::isActive("FFMpegInfo")){ Util::sleep(100); }
    FILE * outFile = fdopen( outFD, "r" );
    char * fileBuf = 0;
    size_t fileBufLen = 0;
    while ( !(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
      if (strstr(fileBuf, "aac") || strstr(fileBuf, "AAC")){
        strtok(fileBuf, " \t");
        allCodecs["ffmpeg"][strtok(NULL, " \t")] = "aac";
      }
      if (strstr(fileBuf, "h264") || strstr(fileBuf, "H264")){
        strtok(fileBuf, " \t");
        allCodecs["ffmpeg"][strtok(NULL, " \t")] = "h264";
      }
      if (strstr(fileBuf, "mp3") || strstr(fileBuf, "MP3")){
        strtok(fileBuf, " \t");
        allCodecs["ffmpeg"][strtok(NULL, " \t")] = "mp3";
      }
    }
    fclose( outFile );
  }

  converterInfo & Converter::getCodecs(){
    return allCodecs;
  }

  JSON::Value Converter::getEncoders(){
    JSON::Value result;
    for (converterInfo::iterator convIt = allCodecs.begin(); convIt != allCodecs.end(); convIt++){
      for (codecInfo::iterator codIt = convIt->second.begin(); codIt != convIt->second.end(); codIt++){
        result[convIt->first][codIt->first] = codIt->second;
      }
    }
    return result;
  }

  JSON::Value Converter::queryPath(std::string myPath){
    std::vector<char*> cmd;
    cmd.reserve(3);
    cmd.push_back((char*)"MistInfo");
    cmd.push_back(NULL);
    cmd.push_back(NULL);
    fprintf( stderr, "Querying %s\n", myPath.c_str());
    JSON::Value result;
    DIR * Dirp = opendir(myPath.c_str());
    struct stat StatBuf;
    if (Dirp){
      dirent * entry;
      while ((entry = readdir(Dirp))){
        if (stat(std::string(myPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
          continue;
        }
        if ((StatBuf.st_mode & S_IFREG) == 0){
          continue;
        }
        std::string fileName = entry->d_name;
        std::string myPath = std::string(myPath + (myPath[myPath.size()-1] == '/' ? "" : "/") +  entry->d_name);
        cmd[1] = (char*)myPath.c_str();
        int outFD = -1;
        Util::Procs::StartPiped("MistInfo", &cmd[0], 0, &outFD, 0);
        while( Util::Procs::isActive("MistInfo")){ Util::sleep(10); }
        FILE * outFile = fdopen( outFD, "r" );
        char * fileBuf = 0;
        size_t fileBufLen = 0;
        getline(&fileBuf, &fileBufLen, outFile);
        std::string line = fileBuf;
        result[fileName] = JSON::fromString(std::string(fileBuf));
        if ( !result[fileName]){
          result.removeMember(fileName);
        }
        fclose( outFile );
      }
    }
    return result;
  }

  void Converter::startConversion(std::string name, JSON::Value parameters) {
    if ( !parameters.isMember("input")){
      statusHistory[name] = "No input file supplied";
      return;
    }
    if ( !parameters.isMember("output")){
      statusHistory[name] = "No output file supplied";
      return;
    }
    if ( !parameters.isMember("encoder")){
      statusHistory[name] = "No encoder specified";
      return;
    }
    if (allCodecs.find(parameters["encoder"]) == allCodecs.end()){
      statusHistory[name] = "Can not find encoder " + parameters["encoder"];
      return;
    }
    std::stringstream encoderCommand;
    if (parameters["encoder"] == "ffmpeg"){
      encoderCommand << "ffmpeg -i ";
      encoderCommand << parameters["input"].asString() << " ";
      if (parameters.isMember("video")){
        if ( !parameters["video"].isMember("codec") || parameters["video"]["codec"] == "copy"){
          encoderCommand << "-vcodec copy ";
        }else{
          codecInfo::iterator vidCodec = allCodecs["ffmpeg"].find(parameters["video"]["codec"]);
          if (vidCodec == allCodecs["ffmpeg"].end()){
            statusHistory[name] = "Can not find video codec " + parameters["video"]["codec"].asString();
            return;
          }
          encoderCommand << "-vcodec " << vidCodec->first << " ";
          if (parameters["video"].isMember("kfps")){
            encoderCommand << "-r " << parameters["video"]["kfps"].asInt() / 1000 << " ";
          }
          ///\todo Keyframe interval (different in older and newer versions of ffmpeg?)
        }
      }else{
        encoderCommand << "-vn ";
      }
      if (parameters.isMember("audio")){
        if ( !parameters["audio"].isMember("codec")){
          encoderCommand << "-acodec copy ";
        }else{
          codecInfo::iterator audCodec = allCodecs["ffmpeg"].find(parameters["audio"]["codec"]);
          if (audCodec == allCodecs["ffmpeg"].end()){
            statusHistory[name] = "Can not find audio codec " + parameters["audio"]["codec"].asString();
            return;
          }
          if (audCodec->second == "aac"){
            encoderCommand << "-strict -2 ";
          }
          encoderCommand << "-acodec " << audCodec->first << " ";
          if (parameters["audio"].isMember("samplerate")){
            encoderCommand << "-ar " << parameters["audio"]["samplerate"].asInt() << " ";
          }
        }
      }else{
        encoderCommand << "-an ";
      }
      encoderCommand << "-f flv -";
    }
    int statusFD = -1;
    Util::Procs::StartPiped2(name,encoderCommand.str(),Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString(),0,0,&statusFD,0);
    parameters["statusFD"] = statusFD;
    allConversions[name] = parameters;
  }

  void Converter::updateStatus(){
    if (allConversions.size()){
      std::map<std::string,JSON::Value>::iterator cIt;
      bool hasChanged = true;
      while (hasChanged && allConversions.size()){
        hasChanged = false;
        for (cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){
          if (Util::Procs::isActive(cIt->first)){
            continue;
          }
          if (cIt->second["output"].asString().find(".dtsc") != std::string::npos){
            statusHistory[cIt->first] = "Conversion succesful, running DTSCFix";
            Util::Procs::Start(cIt->first+"DTSCFix",Util::getMyPath() + "MistDTSCFix " + cIt->second["output"].asString());
          }else{
            statusHistory[cIt->first] = "Conversion succesful";
          }
          allConversions.erase(cIt);
          hasChanged = true;
          break;
        }
      }
    }
    if(statusHistory.size()){
      std::map<std::string,std::string>::iterator sIt;
      for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++){
        if (statusHistory[sIt->first].find("DTSCFix") != std::string::npos){
          if (Util::Procs::isActive(sIt->first+"DTSCFIX")){
            continue;
          }
          statusHistory[sIt->first] = "Conversion succesful";
        }
      }
    }
  }

  JSON::Value parseFFMpegStatus(std::string statusLine){
    JSON::Value result;
    int curOffset = statusLine.find("frame=") + 6;
    result["frame"] = atoi(statusLine.substr(curOffset, statusLine.find("fps=") - curOffset).c_str() );
    curOffset = statusLine.find("time=") + 5;
    int myTime = 0;
    myTime += atoi(statusLine.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
    myTime += atoi(statusLine.substr(curOffset+3, 2).c_str()) * 60 * 1000;
    myTime += atoi(statusLine.substr(curOffset+6, 2).c_str()) *1000;
    myTime += atoi(statusLine.substr(curOffset+9, 2).c_str()) * 10;
    result["time"] = myTime;
    return result;
  }

  JSON::Value Converter::getStatus(){
    updateStatus();
    JSON::Value result;
    if (allConversions.size()){
      for (std::map<std::string,JSON::Value>::iterator cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){
        int statusFD = dup(cIt->second["statusFD"].asInt());
        fsync( statusFD );
        FILE* statusFile = fdopen( statusFD, "r" );
        char * fileBuf = 0;
        size_t fileBufLen = 0;
        fseek(statusFile,0,SEEK_END);
        std::string line;
        int totalTime = 0;
        do{
          getdelim(&fileBuf, &fileBufLen, '\r', statusFile);
          line = fileBuf;
          if (line.find("Duration") != std::string::npos){
            int curOffset = line.find("Duration: ") + 10;
            totalTime += atoi(line.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
            totalTime += atoi(line.substr(curOffset+3, 2).c_str()) * 60 * 1000;
            totalTime += atoi(line.substr(curOffset+6, 2).c_str()) *1000;
            totalTime += atoi(line.substr(curOffset+9, 2).c_str()) * 10;
            cIt->second["duration"] = totalTime;
          }
        }while(line.find("frame") != 0);//"frame" is the fist word on an actual status line of ffmpeg
        result[cIt->first] = parseFFMpegStatus( line );
        result[cIt->first]["duration"] = cIt->second["duration"];
        result[cIt->first]["progress"] = (result[cIt->first]["time"].asInt() * 100) / cIt->second["duration"].asInt();
        free(fileBuf);
        fclose(statusFile);
      }
    }
    if (statusHistory.size()){
      std::map<std::string,std::string>::iterator sIt;
      for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++){
        result[sIt->first] = sIt->second;
      }
    }
    return result;
  }

  void Converter::clearStatus(){
    statusHistory.clear();
  }
}
<commit_msg>Spelling corrections, FFMPEG-Error detection.<commit_after>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sstream>

#include "timing.h"
#include "converter.h"
#include "procs.h"
#include "config.h"

namespace Converter {

  Converter::Converter(){
    fillFFMpegEncoders();
  }

  void Converter::fillFFMpegEncoders(){
    std::vector<char*> cmd;
    cmd.reserve(3);
    cmd.push_back((char*)"ffmpeg");
    cmd.push_back((char*)"-encoders");
    cmd.push_back(NULL);
    int outFD = -1;
    Util::Procs::StartPiped("FFMpegInfo", &cmd[0], 0, &outFD, 0);
    while( Util::Procs::isActive("FFMpegInfo")){ Util::sleep(100); }
    FILE * outFile = fdopen( outFD, "r" );
    char * fileBuf = 0;
    size_t fileBufLen = 0;
    while ( !(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
      if (strstr(fileBuf, "aac") || strstr(fileBuf, "AAC")){
        strtok(fileBuf, " \t");
        allCodecs["ffmpeg"][strtok(NULL, " \t")] = "aac";
      }
      if (strstr(fileBuf, "h264") || strstr(fileBuf, "H264")){
        strtok(fileBuf, " \t");
        allCodecs["ffmpeg"][strtok(NULL, " \t")] = "h264";
      }
      if (strstr(fileBuf, "mp3") || strstr(fileBuf, "MP3")){
        strtok(fileBuf, " \t");
        allCodecs["ffmpeg"][strtok(NULL, " \t")] = "mp3";
      }
    }
    fclose( outFile );
  }

  converterInfo & Converter::getCodecs(){
    return allCodecs;
  }

  JSON::Value Converter::getEncoders(){
    JSON::Value result;
    for (converterInfo::iterator convIt = allCodecs.begin(); convIt != allCodecs.end(); convIt++){
      for (codecInfo::iterator codIt = convIt->second.begin(); codIt != convIt->second.end(); codIt++){
        result[convIt->first][codIt->first] = codIt->second;
      }
    }
    return result;
  }

  JSON::Value Converter::queryPath(std::string myPath){
    std::vector<char*> cmd;
    cmd.reserve(3);
    cmd.push_back((char*)"MistInfo");
    cmd.push_back(NULL);
    cmd.push_back(NULL);
    fprintf( stderr, "Querying %s\n", myPath.c_str());
    JSON::Value result;
    DIR * Dirp = opendir(myPath.c_str());
    struct stat StatBuf;
    if (Dirp){
      dirent * entry;
      while ((entry = readdir(Dirp))){
        if (stat(std::string(myPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
          continue;
        }
        if ((StatBuf.st_mode & S_IFREG) == 0){
          continue;
        }
        std::string fileName = entry->d_name;
        std::string myPath = std::string(myPath + (myPath[myPath.size()-1] == '/' ? "" : "/") +  entry->d_name);
        cmd[1] = (char*)myPath.c_str();
        int outFD = -1;
        Util::Procs::StartPiped("MistInfo", &cmd[0], 0, &outFD, 0);
        while( Util::Procs::isActive("MistInfo")){ Util::sleep(10); }
        FILE * outFile = fdopen( outFD, "r" );
        char * fileBuf = 0;
        size_t fileBufLen = 0;
        getline(&fileBuf, &fileBufLen, outFile);
        std::string line = fileBuf;
        result[fileName] = JSON::fromString(std::string(fileBuf));
        if ( !result[fileName]){
          result.removeMember(fileName);
        }
        fclose( outFile );
      }
    }
    return result;
  }

  void Converter::startConversion(std::string name, JSON::Value parameters) {
    if ( !parameters.isMember("input")){
      statusHistory[name] = "No input file supplied";
      return;
    }
    if ( !parameters.isMember("output")){
      statusHistory[name] = "No output file supplied";
      return;
    }
    if ( !parameters.isMember("encoder")){
      statusHistory[name] = "No encoder specified";
      return;
    }
    if (allCodecs.find(parameters["encoder"]) == allCodecs.end()){
      statusHistory[name] = "Can not find encoder " + parameters["encoder"];
      return;
    }
    std::stringstream encoderCommand;
    if (parameters["encoder"] == "ffmpeg"){
      encoderCommand << "ffmpeg -i ";
      encoderCommand << parameters["input"].asString() << " ";
      if (parameters.isMember("video")){
        if ( !parameters["video"].isMember("codec") || parameters["video"]["codec"] == "copy"){
          encoderCommand << "-vcodec copy ";
        }else{
          codecInfo::iterator vidCodec = allCodecs["ffmpeg"].find(parameters["video"]["codec"]);
          if (vidCodec == allCodecs["ffmpeg"].end()){
            statusHistory[name] = "Can not find video codec " + parameters["video"]["codec"].asString();
            return;
          }
          encoderCommand << "-vcodec " << vidCodec->first << " ";
          if (parameters["video"].isMember("kfps")){
            encoderCommand << "-r " << parameters["video"]["kfps"].asInt() / 1000 << " ";
          }
          ///\todo Keyframe interval (different in older and newer versions of ffmpeg?)
        }
      }else{
        encoderCommand << "-vn ";
      }
      if (parameters.isMember("audio")){
        if ( !parameters["audio"].isMember("codec")){
          encoderCommand << "-acodec copy ";
        }else{
          codecInfo::iterator audCodec = allCodecs["ffmpeg"].find(parameters["audio"]["codec"]);
          if (audCodec == allCodecs["ffmpeg"].end()){
            statusHistory[name] = "Can not find audio codec " + parameters["audio"]["codec"].asString();
            return;
          }
          if (audCodec->second == "aac"){
            encoderCommand << "-strict -2 ";
          }
          encoderCommand << "-acodec " << audCodec->first << " ";
          if (parameters["audio"].isMember("samplerate")){
            encoderCommand << "-ar " << parameters["audio"]["samplerate"].asInt() << " ";
          }
        }
      }else{
        encoderCommand << "-an ";
      }
      encoderCommand << "-f flv -";
    }
    int statusFD = -1;
    Util::Procs::StartPiped2(name,encoderCommand.str(),Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString(),0,0,&statusFD,0);
    parameters["statusFD"] = statusFD;
    allConversions[name] = parameters;
  }

  void Converter::updateStatus(){
    if (allConversions.size()){
      std::map<std::string,JSON::Value>::iterator cIt;
      bool hasChanged = true;
      while (hasChanged && allConversions.size()){
        hasChanged = false;
        for (cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){
          if (Util::Procs::isActive(cIt->first)){
            continue;
          }
          if (statusHistory.find( cIt->first ) == statusHistory.end()){
            statusHistory[cIt->first] = "Conversion successful, running DTSCFix";
            Util::Procs::Start(cIt->first+"DTSCFix",Util::getMyPath() + "MistDTSCFix " + cIt->second["output"].asString());
          }
          allConversions.erase(cIt);
          hasChanged = true;
          break;
        }
      }
    }
    if(statusHistory.size()){
      std::map<std::string,std::string>::iterator sIt;
      for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++){
        if (statusHistory[sIt->first].find("DTSCFix") != std::string::npos){
          if (Util::Procs::isActive(sIt->first+"DTSCFIX")){
            continue;
          }
          statusHistory[sIt->first] = "Conversion successful";
        }
      }
    }
  }

  JSON::Value parseFFMpegStatus(std::string statusLine){
    JSON::Value result;
    int curOffset = statusLine.find("frame=") + 6;
    result["frame"] = atoi(statusLine.substr(curOffset, statusLine.find("fps=") - curOffset).c_str() );
    curOffset = statusLine.find("time=") + 5;
    int myTime = 0;
    myTime += atoi(statusLine.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
    myTime += atoi(statusLine.substr(curOffset+3, 2).c_str()) * 60 * 1000;
    myTime += atoi(statusLine.substr(curOffset+6, 2).c_str()) *1000;
    myTime += atoi(statusLine.substr(curOffset+9, 2).c_str()) * 10;
    result["time"] = myTime;
    return result;
  }

  JSON::Value Converter::getStatus(){
    updateStatus();
    JSON::Value result;
    if (allConversions.size()){
      for (std::map<std::string,JSON::Value>::iterator cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){
        int statusFD = dup(cIt->second["statusFD"].asInt());
        fsync( statusFD );
        FILE* statusFile = fdopen( statusFD, "r" );
        char * fileBuf = 0;
        size_t fileBufLen = 0;
        fseek(statusFile,0,SEEK_END);
        std::string line;
        int totalTime = 0;
        do{
          getdelim(&fileBuf, &fileBufLen, '\r', statusFile);
          line = fileBuf;
          if (line.find("Duration") != std::string::npos){
            int curOffset = line.find("Duration: ") + 10;
            totalTime += atoi(line.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
            totalTime += atoi(line.substr(curOffset+3, 2).c_str()) * 60 * 1000;
            totalTime += atoi(line.substr(curOffset+6, 2).c_str()) *1000;
            totalTime += atoi(line.substr(curOffset+9, 2).c_str()) * 10;
            cIt->second["duration"] = totalTime;
          }
        }while ( !feof(statusFile) && line.find("frame") != 0);//"frame" is the fist word on an actual status line of ffmpeg
        if ( !feof(statusFile)){
          result[cIt->first] = parseFFMpegStatus( line );
          result[cIt->first]["duration"] = cIt->second["duration"];
          result[cIt->first]["progress"] = (result[cIt->first]["time"].asInt() * 100) / cIt->second["duration"].asInt();
        }else{
          line.erase(line.end()-1);
          line = line.substr( line.rfind("\n") + 1 );
          result[cIt->first] = line;
          statusHistory[cIt->first] = line;
        }
        free(fileBuf);
        fclose(statusFile);
      }
    }
    if (statusHistory.size()){
      std::map<std::string,std::string>::iterator sIt;
      for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++){
        result[sIt->first] = sIt->second;
      }
    }
    return result;
  }

  void Converter::clearStatus(){
    statusHistory.clear();
  }
}
<|endoftext|>


<commit_before>#pragma ident "$Id$"

#ifndef TCPSTREAMBUFF_HPP
#define TCPSTREAMBUFF_HPP

#include <sstream>
#include <errno.h>
#include <stdlib.h>

#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/file.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#include "FDStreamBuff.hpp"

namespace gpstk
{
   class SocketAddr;

   class IPaddress
   {
      friend class SocketAddr;

      unsigned long address;                // Address: 4 bytes in the network byte order
      IPaddress(const unsigned int netaddr) : address(netaddr) {}

   public:
      IPaddress() : address(INADDR_ANY) {}   // Wildcard address
      IPaddress(const std::string& name);         // Involves the name resolution
      unsigned long net_addr() const { return address; }

      friend std::ostream& operator <<(std::ostream& os, const IPaddress addr);
      friend std::ostream& operator <<(std::ostream& os, const SocketAddr& addr);
   };

   class SocketAddr : sockaddr_in
   {
      friend class StreamSocket;
      friend class UDPsocketIn;
      SocketAddr() {}

   public:
      SocketAddr(const IPaddress host, const short port_no);
      operator sockaddr * () const      { return (sockaddr *)this; }
      friend std::ostream& operator <<(std::ostream& os, const SocketAddr& addr);
   };

   class TCPStreamBuff : public FDStreamBuff
   {
   public:
      TCPStreamBuff() : FDStreamBuff(-1) {}

      ~TCPStreamBuff() {close();}

      int connect(const SocketAddr target_address);

      // Take a file handle (which is supposed to be a listening socket),
      // accept a connection if any,  and return the corresponding TCPbuf
      // for that connection. On exit, peeraddr would be an addr of the
      // connected peer
      int accept(int listening_socket, SocketAddr& peeraddr);

   };

} // end of namespace
#endif
<commit_msg>INADDR_ANY comes from <netinet/in.h><commit_after>#pragma ident "$Id$"

#ifndef TCPSTREAMBUFF_HPP
#define TCPSTREAMBUFF_HPP

#include <sstream>
#include <errno.h>
#include <stdlib.h>

#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#include "FDStreamBuff.hpp"

namespace gpstk
{
   class SocketAddr;

   class IPaddress
   {
      friend class SocketAddr;

      unsigned long address;                // Address: 4 bytes in the network byte order
      IPaddress(const unsigned int netaddr) : address(netaddr) {}

   public:
      IPaddress() : address(INADDR_ANY) {}   // Wildcard address
      IPaddress(const std::string& name);         // Involves the name resolution
      unsigned long net_addr() const { return address; }

      friend std::ostream& operator <<(std::ostream& os, const IPaddress addr);
      friend std::ostream& operator <<(std::ostream& os, const SocketAddr& addr);
   };

   class SocketAddr : sockaddr_in
   {
      friend class StreamSocket;
      friend class UDPsocketIn;
      SocketAddr() {}

   public:
      SocketAddr(const IPaddress host, const short port_no);
      operator sockaddr * () const      { return (sockaddr *)this; }
      friend std::ostream& operator <<(std::ostream& os, const SocketAddr& addr);
   };

   class TCPStreamBuff : public FDStreamBuff
   {
   public:
      TCPStreamBuff() : FDStreamBuff(-1) {}

      ~TCPStreamBuff() {close();}

      int connect(const SocketAddr target_address);

      // Take a file handle (which is supposed to be a listening socket),
      // accept a connection if any,  and return the corresponding TCPbuf
      // for that connection. On exit, peeraddr would be an addr of the
      // connected peer
      int accept(int listening_socket, SocketAddr& peeraddr);

   };

} // end of namespace
#endif
<|endoftext|>


<commit_before>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <cctype>
#include <fstream>
#include <stdio.h>
#include <sstream> // ostringstream
#include <regex> // regex parsing for temp flow graph
#include <string> // stod (string to double)
#include "../utils/logoutput.h"

#include "Settings.h"
#include "SettingRegistry.h"

namespace cura
{

void Settings::add(const std::string& key, const int value, Settings* limit_to_extruder)
{
    //TODO.
}

void Settings::add(const std::string& key, const double value, Settings* limit_to_extruder)
{
    //TODO.
}

template<> int Settings::get<int>(const std::string& key) const
{
    return 0;
}

template<> double Settings::get<double>(const std::string& key) const
{
    return 0.0;
}

////////////////////////////OLD IMPLEMENTATION BELOW////////////////////////////

//c++11 no longer defines M_PI, so add our own constant.
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

std::string toString(EGCodeFlavor flavor)
{
    switch (flavor)
    {
        case EGCodeFlavor::BFB:
            return "BFB";
        case EGCodeFlavor::MACH3:
            return "Mach3";
        case EGCodeFlavor::MAKERBOT:
            return "Makerbot";
        case EGCodeFlavor::ULTIGCODE:
            return "UltiGCode";
        case EGCodeFlavor::MARLIN_VOLUMATRIC:
            return "Marlin(Volumetric)";
        case EGCodeFlavor::GRIFFIN:
            return "Griffin";
        case EGCodeFlavor::REPETIER:
            return "Repetier";
        case EGCodeFlavor::REPRAP:
            return "RepRap";
        case EGCodeFlavor::MARLIN:
        default:
            return "Marlin";
    }
}

SettingsBase::SettingsBase()
: SettingsBaseVirtual(nullptr)
{
}

SettingsBase::SettingsBase(SettingsBaseVirtual* parent)
: SettingsBaseVirtual(parent)
{
}

SettingsMessenger::SettingsMessenger(SettingsBaseVirtual* parent)
: SettingsBaseVirtual(parent)
{
}

void SettingsBase::_setSetting(std::string key, std::string value)
{
    setting_values[key] = value;
}

void SettingsBase::setSetting(std::string key, std::string value)
{
    if (SettingRegistry::getInstance()->settingExists(key))
    {
        _setSetting(key, value);
    }
    else
    {
        cura::logWarning("Setting an unregistered setting %s to %s\n", key.c_str(), value.c_str());
        _setSetting(key, value); // Handy when programmers are in the process of introducing a new setting
    }
}

void SettingsBase::setSettingInheritBase(std::string key, const SettingsBaseVirtual& parent)
{
    setting_inherit_base.emplace(key, &parent);
}

const std::string& SettingsBase::getSettingString(const std::string& key) const
{
    auto value_it = setting_values.find(key);
    if (value_it != setting_values.end())
    {
        return value_it->second;
    }
    auto inherit_override_it = setting_inherit_base.find(key);
    if (inherit_override_it != setting_inherit_base.end())
    {
        return inherit_override_it->second->getSettingString(key);
    }
    if (parent)
    {
        return parent->getSettingString(key);
    }

    cura::logError("Trying to retrieve unregistered setting with no value given: '%s'\n", key.c_str());
    std::exit(-1);
    static std::string empty_string; // use static object rather than "" to avoid compilation warning
    return empty_string;
}

std::string SettingsBase::getAllLocalSettingsString() const
{
    std::stringstream sstream;
    for (auto pair : setting_values)
    {
        if (!pair.second.empty())
        {
            char buffer[4096];
            snprintf(buffer, 4096, " -s %s=\"%s\"", pair.first.c_str(), Escaped{pair.second.c_str()}.str);
            sstream << buffer;
        }
    }
    return sstream.str();
}

void SettingsMessenger::setSetting(std::string key, std::string value)
{
    parent->setSetting(key, value);
}

void SettingsMessenger::setSettingInheritBase(std::string key, const SettingsBaseVirtual& new_parent)
{
    parent->setSettingInheritBase(key, new_parent);
}

const std::string& SettingsMessenger::getSettingString(const std::string& key) const
{
    return parent->getSettingString(key);
}

}//namespace cura

<commit_msg>Add string specialisation<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <cctype>
#include <fstream>
#include <stdio.h>
#include <sstream> // ostringstream
#include <regex> // regex parsing for temp flow graph
#include <string> // stod (string to double)
#include "../utils/logoutput.h"

#include "Settings.h"
#include "SettingRegistry.h"

namespace cura
{

void Settings::add(const std::string& key, const int value, Settings* limit_to_extruder)
{
    //TODO.
}

void Settings::add(const std::string& key, const double value, Settings* limit_to_extruder)
{
    //TODO.
}

template<> std::string Settings::get<std::string>(const std::string& key) const
{
    return "";
}

template<> int Settings::get<int>(const std::string& key) const
{
    return 0;
}

template<> double Settings::get<double>(const std::string& key) const
{
    return 0.0;
}

////////////////////////////OLD IMPLEMENTATION BELOW////////////////////////////

//c++11 no longer defines M_PI, so add our own constant.
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

std::string toString(EGCodeFlavor flavor)
{
    switch (flavor)
    {
        case EGCodeFlavor::BFB:
            return "BFB";
        case EGCodeFlavor::MACH3:
            return "Mach3";
        case EGCodeFlavor::MAKERBOT:
            return "Makerbot";
        case EGCodeFlavor::ULTIGCODE:
            return "UltiGCode";
        case EGCodeFlavor::MARLIN_VOLUMATRIC:
            return "Marlin(Volumetric)";
        case EGCodeFlavor::GRIFFIN:
            return "Griffin";
        case EGCodeFlavor::REPETIER:
            return "Repetier";
        case EGCodeFlavor::REPRAP:
            return "RepRap";
        case EGCodeFlavor::MARLIN:
        default:
            return "Marlin";
    }
}

SettingsBase::SettingsBase()
: SettingsBaseVirtual(nullptr)
{
}

SettingsBase::SettingsBase(SettingsBaseVirtual* parent)
: SettingsBaseVirtual(parent)
{
}

SettingsMessenger::SettingsMessenger(SettingsBaseVirtual* parent)
: SettingsBaseVirtual(parent)
{
}

void SettingsBase::_setSetting(std::string key, std::string value)
{
    setting_values[key] = value;
}

void SettingsBase::setSetting(std::string key, std::string value)
{
    if (SettingRegistry::getInstance()->settingExists(key))
    {
        _setSetting(key, value);
    }
    else
    {
        cura::logWarning("Setting an unregistered setting %s to %s\n", key.c_str(), value.c_str());
        _setSetting(key, value); // Handy when programmers are in the process of introducing a new setting
    }
}

void SettingsBase::setSettingInheritBase(std::string key, const SettingsBaseVirtual& parent)
{
    setting_inherit_base.emplace(key, &parent);
}

const std::string& SettingsBase::getSettingString(const std::string& key) const
{
    auto value_it = setting_values.find(key);
    if (value_it != setting_values.end())
    {
        return value_it->second;
    }
    auto inherit_override_it = setting_inherit_base.find(key);
    if (inherit_override_it != setting_inherit_base.end())
    {
        return inherit_override_it->second->getSettingString(key);
    }
    if (parent)
    {
        return parent->getSettingString(key);
    }

    cura::logError("Trying to retrieve unregistered setting with no value given: '%s'\n", key.c_str());
    std::exit(-1);
    static std::string empty_string; // use static object rather than "" to avoid compilation warning
    return empty_string;
}

std::string SettingsBase::getAllLocalSettingsString() const
{
    std::stringstream sstream;
    for (auto pair : setting_values)
    {
        if (!pair.second.empty())
        {
            char buffer[4096];
            snprintf(buffer, 4096, " -s %s=\"%s\"", pair.first.c_str(), Escaped{pair.second.c_str()}.str);
            sstream << buffer;
        }
    }
    return sstream.str();
}

void SettingsMessenger::setSetting(std::string key, std::string value)
{
    parent->setSetting(key, value);
}

void SettingsMessenger::setSettingInheritBase(std::string key, const SettingsBaseVirtual& new_parent)
{
    parent->setSettingInheritBase(key, new_parent);
}

const std::string& SettingsMessenger::getSettingString(const std::string& key) const
{
    return parent->getSettingString(key);
}

}//namespace cura

<|endoftext|>


<commit_before>#include <prjxray/segbits_file_reader.h>

namespace prjxray {

std::unique_ptr<SegbitsFileReader> SegbitsFileReader::InitWithFile(
    const std::string& path) {
	auto mapped_file = MemoryMappedFile::InitWithFile(path);
	if (!mapped_file)
		return nullptr;

	return std::unique_ptr<SegbitsFileReader>(
	    new SegbitsFileReader(std::move(mapped_file)));
}

SegbitsFileReader::iterator SegbitsFileReader::begin() {
	return iterator(
	    absl::string_view(static_cast<const char*>(mapped_file_->data()),
	                      mapped_file_->size()));
}

SegbitsFileReader::iterator SegbitsFileReader::end() {
	return iterator(absl::string_view());
}

SegbitsFileReader::value_type::value_type(const absl::string_view& view) {
	size_t separator_start = view.find_first_of(" \t");
	if (separator_start == absl::string_view::npos) {
		tag_ = view;
		bit_ = absl::string_view();
		return;
	}

	size_t bit_start = view.find_first_not_of(" \t", separator_start);
	size_t newline = view.find('\n', bit_start);
	if (newline == absl::string_view::npos) {
		tag_ = view.substr(0, separator_start);
		bit_ = view.substr(bit_start);
		return;
	}

	size_t bit_len = newline - bit_start;
	tag_ = view.substr(0, separator_start);
	bit_ = view.substr(bit_start, bit_len);
	return;
}

SegbitsFileReader::iterator& SegbitsFileReader::iterator::operator++() {
	size_t newline = view_.find('\n');
	if (newline == absl::string_view::npos) {
		view_ = absl::string_view();
	}

	view_.remove_prefix(newline + 1);
	value_ = value_type(view_);
	return *this;
}

}  // namespace prjxray
<commit_msg>SEGBITS FILE READER - Handle Whitespace<commit_after>#include <prjxray/segbits_file_reader.h>

namespace prjxray {

std::unique_ptr<SegbitsFileReader> SegbitsFileReader::InitWithFile(
    const std::string& path) {
	auto mapped_file = MemoryMappedFile::InitWithFile(path);
	if (!mapped_file)
		return nullptr;

	return std::unique_ptr<SegbitsFileReader>(
	    new SegbitsFileReader(std::move(mapped_file)));
}

SegbitsFileReader::iterator SegbitsFileReader::begin() {
	return iterator(
	    absl::string_view(static_cast<const char*>(mapped_file_->data()),
	                      mapped_file_->size()));
}

SegbitsFileReader::iterator SegbitsFileReader::end() {
	return iterator(absl::string_view());
}

SegbitsFileReader::value_type::value_type(const absl::string_view& view) {
	size_t separator_start = view.find_first_of(" \t\n");
	if (separator_start == absl::string_view::npos) {
		tag_ = view;
		bit_ = absl::string_view();
		return;
	}

	size_t bit_start = view.find_first_not_of(" \t", separator_start);
	size_t newline = view.find('\n', bit_start);
	if (newline == absl::string_view::npos) {
		tag_ = view.substr(0, separator_start);
		bit_ = view.substr(bit_start);
		return;
	}

	size_t bit_len = newline - bit_start;
	tag_ = view.substr(0, separator_start);
	bit_ = view.substr(bit_start, bit_len);
	return;
}

SegbitsFileReader::iterator& SegbitsFileReader::iterator::operator++() {
	size_t newline = view_.find('\n');
	if (newline == absl::string_view::npos) {
		view_ = absl::string_view();
	}

	view_.remove_prefix(newline + 1);
	value_ = value_type(view_);
	return *this;
}

}  // namespace prjxray
<|endoftext|>


<commit_before>/*
 Print.cpp - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

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

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

 Modified 23 November 2006 by David A. Mellis
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Arduino.h"

#include "Print.h"

// Public Methods //////////////////////////////////////////////////////////////

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
  size_t n = 0;
  while (size--) {
    n += write(*buffer++);
  }
  return n;
}

size_t Print::print(const __FlashStringHelper *ifsh)
{
  const char PROGMEM *p = (const char PROGMEM *)ifsh;
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    n += write(c);
  }
  return n;
}

size_t Print::print(const String &s)
{
  size_t n = 0;
  for (uint16_t i = 0; i < s.length(); i++) {
    n += write(s[i]);
  }
  return n;
}

size_t Print::print(const char str[])
{
  return write(str);
}

size_t Print::print(char c)
{
  return write(c);
}

size_t Print::print(unsigned char b, int base)
{
  return print((unsigned long) b, base);
}

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

size_t Print::print(unsigned int n, int base)
{
  return print((unsigned long) n, base);
}

size_t Print::print(long n, int base)
{
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
    }
    return printNumber(n, 10);
  } else {
    return printNumber(n, base);
  }
}

size_t Print::print(unsigned long n, int base)
{
  if (base == 0) return write(n);
  else return printNumber(n, base);
}

size_t Print::print(double n, int digits)
{
  return printFloat(n, digits);
}

size_t Print::println(const __FlashStringHelper *ifsh)
{
  size_t n = print(ifsh);
  n += println();
  return n;
}

size_t Print::print(const Printable& x)
{
  return x.printTo(*this);
}

size_t Print::println(void)
{
  size_t n = print('\r');
  n += print('\n');
  return n;
}

size_t Print::println(const String &s)
{
  size_t n = print(s);
  n += println();
  return n;
}

size_t Print::println(const char c[])
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(char c)
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(unsigned char b, int base)
{
  size_t n = print(b, base);
  n += println();
  return n;
}

size_t Print::println(int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(double num, int digits)
{
  size_t n = print(num, digits);
  n += println();
  return n;
}

size_t Print::println(const Printable& x)
{
  size_t n = print(x);
  n += println();
  return n;
}

// Private Methods /////////////////////////////////////////////////////////////

size_t Print::printNumber(unsigned long n, uint8_t base) {
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    unsigned long m = n;
    n /= base;
    char c = m - base * n;
    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

size_t Print::printFloat(double number, uint8_t digits)
{
  size_t n = 0;

  if (isnan(number)) return print("nan");

  // Handle negative numbers
  if (number < 0.0)
  {
     n += print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;

  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  n += print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0) {
    n += print(".");
  }

  // Extract digits from the remainder one at a time
  while (digits-- > 0)
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    n += print(toPrint);
    remainder -= toPrint;
  }

  return n;
}
<commit_msg>Print "inf" for infinite floating point numbers (using isinf()).<commit_after>/*
 Print.cpp - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

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

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

 Modified 23 November 2006 by David A. Mellis
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Arduino.h"

#include "Print.h"

// Public Methods //////////////////////////////////////////////////////////////

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
  size_t n = 0;
  while (size--) {
    n += write(*buffer++);
  }
  return n;
}

size_t Print::print(const __FlashStringHelper *ifsh)
{
  const char PROGMEM *p = (const char PROGMEM *)ifsh;
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    n += write(c);
  }
  return n;
}

size_t Print::print(const String &s)
{
  size_t n = 0;
  for (uint16_t i = 0; i < s.length(); i++) {
    n += write(s[i]);
  }
  return n;
}

size_t Print::print(const char str[])
{
  return write(str);
}

size_t Print::print(char c)
{
  return write(c);
}

size_t Print::print(unsigned char b, int base)
{
  return print((unsigned long) b, base);
}

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

size_t Print::print(unsigned int n, int base)
{
  return print((unsigned long) n, base);
}

size_t Print::print(long n, int base)
{
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
    }
    return printNumber(n, 10);
  } else {
    return printNumber(n, base);
  }
}

size_t Print::print(unsigned long n, int base)
{
  if (base == 0) return write(n);
  else return printNumber(n, base);
}

size_t Print::print(double n, int digits)
{
  return printFloat(n, digits);
}

size_t Print::println(const __FlashStringHelper *ifsh)
{
  size_t n = print(ifsh);
  n += println();
  return n;
}

size_t Print::print(const Printable& x)
{
  return x.printTo(*this);
}

size_t Print::println(void)
{
  size_t n = print('\r');
  n += print('\n');
  return n;
}

size_t Print::println(const String &s)
{
  size_t n = print(s);
  n += println();
  return n;
}

size_t Print::println(const char c[])
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(char c)
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(unsigned char b, int base)
{
  size_t n = print(b, base);
  n += println();
  return n;
}

size_t Print::println(int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(double num, int digits)
{
  size_t n = print(num, digits);
  n += println();
  return n;
}

size_t Print::println(const Printable& x)
{
  size_t n = print(x);
  n += println();
  return n;
}

// Private Methods /////////////////////////////////////////////////////////////

size_t Print::printNumber(unsigned long n, uint8_t base) {
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    unsigned long m = n;
    n /= base;
    char c = m - base * n;
    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

size_t Print::printFloat(double number, uint8_t digits)
{
  size_t n = 0;

  if (isnan(number)) return print("nan");
  if (isinf(number)) return print("inf");

  // Handle negative numbers
  if (number < 0.0)
  {
     n += print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;

  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  n += print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0) {
    n += print(".");
  }

  // Extract digits from the remainder one at a time
  while (digits-- > 0)
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    n += print(toPrint);
    remainder -= toPrint;
  }

  return n;
}
<|endoftext|>


<commit_before><commit_msg>Fixed first and last button highlights.<commit_after><|endoftext|>