<commit_before>/*
 *  Copyright (C) 2014 Hugh Bailey <obs.jim@gmail.com>
 *
 *  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 Street, Fifth Floor, Boston, MA  02110-1301
 *  USA
 */

#pragma once

#include <vector>
#include <string>
#include <functional>

#ifdef DSHOWCAPTURE_EXPORTS
	#define DSHOWCAPTURE_EXPORT __declspec(dllexport)
#else
	#define DSHOWCAPTURE_EXPORT
#endif

#define DSHOWCAPTURE_VERSION_MAJOR 0
#define DSHOWCAPTURE_VERSION_MINOR 4
#define DSHOWCAPTURE_VERSION_PATCH 2

#define MAKE_DSHOWCAPTURE_VERSION(major, minor, patch) \
		( (major << 24) | \
		  (minor << 16) | \
		  (patch)       )

#define DSHOWCAPTURE_VERSION MAKE_DSHOWCAPTURE_VERSION( \
		DSHOWCAPTURE_VERSION_MAJOR, \
		DSHOWCAPTURE_VERSION_MINOR, \
		DSHOWCAPTURE_VERSION_PATCH)

#define DSHOW_MAX_PLANES 8

namespace DShow {
	/* internal forward */
	struct HDevice;
	struct HVideoEncoder;
	struct VideoConfig;
	struct AudioConfig;

	typedef std::function<
		void (const VideoConfig &config,
			unsigned char *data, size_t size,
			long long startTime, long long stopTime)
		> VideoProc;

	typedef std::function<
		void (const AudioConfig &config,
			unsigned char *data, size_t size,
			long long startTime, long long stopTime)
		> AudioProc;

	enum class InitGraph {
		False,
		True
	};

	/** DirectShow configuration dialog type */
	enum class DialogType {
		ConfigVideo,
		ConfigAudio,
		ConfigCrossbar,
		ConfigCrossbar2
	};

	enum class VideoFormat {
		Any,
		Unknown,

		/* raw formats */
		ARGB = 100,
		XRGB,

		/* planar YUV formats */
		I420 = 200,
		NV12,
		YV12,

		/* packed YUV formats */
		YVYU = 300,
		YUY2,
		UYVY,
		HDYC,

		/* encoded formats */
		MJPEG = 400,
		H264
	};

	enum class AudioFormat {
		Any,
		Unknown,

		/* raw formats */
		Wave16bit = 100,
		WaveFloat,

		/* encoded formats */
		AAC = 200,
		AC3,
		MPGA /* MPEG 1 */
	};

	enum class AudioMode {
		Capture,
		DirectSound,
		WaveOut
	};

	enum class Result {
		Success,
		InUse,
		Error
	};

	struct VideoInfo {
		int         minCX, minCY;
		int         maxCX, maxCY;
		int         granularityCX, granularityCY;
		long long   minInterval, maxInterval;
		VideoFormat format;
	};

	struct AudioInfo {
		int         minChannels, maxChannels;
		int         channelsGranularity;
		int         minSampleRate, maxSampleRate;
		int         sampleRateGranularity;
		AudioFormat format;
	};

	struct DeviceId {
		std::wstring name;
		std::wstring path;
	};

	struct VideoDevice : DeviceId {
		bool audioAttached = false;
		std::vector<VideoInfo> caps;
	};

	struct AudioDevice : DeviceId {
		std::vector<AudioInfo> caps;
	};

	struct Config : DeviceId {
		/** Use the device's desired default config */
		bool        useDefaultConfig = true;
	};

	struct VideoConfig : Config {
		VideoProc   callback;

		/** Desired width/height of video.  */
		int         cx = 0, cy = 0;

		/** Desired frame interval (in 100-nanosecond units) */
		long long   frameInterval = 0;

		/** Internal video format. */
		VideoFormat internalFormat = VideoFormat::Any;

		/** Desired video format. */
		VideoFormat format = VideoFormat::Any;
	};

	struct AudioConfig : Config {
		AudioProc   callback;

		/**
		 * Use the audio attached to the video device
		 *
		 * (name/path memeber variables will be ignored)
		 */
		bool        useVideoDevice = false;

		/** Desired sample rate */
		int         sampleRate = 0;

		/** Desired channels */
		int         channels = 0;

		/** Desired audio format */
		AudioFormat format = AudioFormat::Any;

		/** Audio playback mode */
		AudioMode   mode = AudioMode::Capture;
	};

	class DSHOWCAPTURE_EXPORT Device {
		HDevice *context;

	public:
		Device(InitGraph initialize = InitGraph::False);
		~Device();

		bool        Valid() const;

		bool        ResetGraph();
		void        ShutdownGraph();

		bool        SetVideoConfig(VideoConfig *config);
		bool        SetAudioConfig(AudioConfig *config);

		/**
		 * Connects all the configured filters together.
		 *
		 * Call SetVideoConfig and/or SetAudioConfig before using.
		 */
		bool        ConnectFilters();

		Result      Start();
		void        Stop();

		bool        GetVideoConfig(VideoConfig &config) const;
		bool        GetAudioConfig(AudioConfig &config) const;
		bool        GetVideoDeviceId(DeviceId &id) const;
		bool        GetAudioDeviceId(DeviceId &id) const;

		/**
		 * Opens a DirectShow dialog associated with this device
		 *
		 * @param  type  The dialog type
		 */
		void        OpenDialog(void *hwnd, DialogType type) const;

		static bool EnumVideoDevices(std::vector<VideoDevice> &devices);
		static bool EnumAudioDevices(std::vector<AudioDevice> &devices);
	};

	struct VideoEncoderConfig : DeviceId {
		int fpsNumerator;
		int fpsDenominator;
		int bitrate;
		int keyframeInterval;
		int cx;
		int cy;
	};

	struct EncoderPacket {
		unsigned char  *data;
		size_t         size;
		long long      pts;
		long long      dts;
	};

	class VideoEncoder {
		HVideoEncoder *context;

	public:
		VideoEncoder();
		~VideoEncoder();

		bool Valid() const;
		bool Active() const;

		bool ResetGraph();

		bool SetConfig(VideoEncoderConfig &config);
		bool GetConfig(VideoEncoderConfig &config) const;

		bool Encode(unsigned char *data[DSHOW_MAX_PLANES],
				size_t linesize[DSHOW_MAX_PLANES],
				long long timestampStart,
				long long timestampEnd,
				EncoderPacket &packet,
				bool &new_packet);

		static bool EnumEncoders(std::vector<DeviceId> &encoders);
	};

	enum class LogType {
		Error,
		Warning,
		Info,
		Debug
	};

	typedef void (*LogCallback)(LogType type, const wchar_t *msg,
			void *param);

	DSHOWCAPTURE_EXPORT void SetLogCallback(LogCallback callback,
			void *param);
};
<commit_msg>Update version to 0.4.3<commit_after>/*
 *  Copyright (C) 2014 Hugh Bailey <obs.jim@gmail.com>
 *
 *  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 Street, Fifth Floor, Boston, MA  02110-1301
 *  USA
 */

#pragma once

#include <vector>
#include <string>
#include <functional>

#ifdef DSHOWCAPTURE_EXPORTS
	#define DSHOWCAPTURE_EXPORT __declspec(dllexport)
#else
	#define DSHOWCAPTURE_EXPORT
#endif

#define DSHOWCAPTURE_VERSION_MAJOR 0
#define DSHOWCAPTURE_VERSION_MINOR 4
#define DSHOWCAPTURE_VERSION_PATCH 3

#define MAKE_DSHOWCAPTURE_VERSION(major, minor, patch) \
		( (major << 24) | \
		  (minor << 16) | \
		  (patch)       )

#define DSHOWCAPTURE_VERSION MAKE_DSHOWCAPTURE_VERSION( \
		DSHOWCAPTURE_VERSION_MAJOR, \
		DSHOWCAPTURE_VERSION_MINOR, \
		DSHOWCAPTURE_VERSION_PATCH)

#define DSHOW_MAX_PLANES 8

namespace DShow {
	/* internal forward */
	struct HDevice;
	struct HVideoEncoder;
	struct VideoConfig;
	struct AudioConfig;

	typedef std::function<
		void (const VideoConfig &config,
			unsigned char *data, size_t size,
			long long startTime, long long stopTime)
		> VideoProc;

	typedef std::function<
		void (const AudioConfig &config,
			unsigned char *data, size_t size,
			long long startTime, long long stopTime)
		> AudioProc;

	enum class InitGraph {
		False,
		True
	};

	/** DirectShow configuration dialog type */
	enum class DialogType {
		ConfigVideo,
		ConfigAudio,
		ConfigCrossbar,
		ConfigCrossbar2
	};

	enum class VideoFormat {
		Any,
		Unknown,

		/* raw formats */
		ARGB = 100,
		XRGB,

		/* planar YUV formats */
		I420 = 200,
		NV12,
		YV12,

		/* packed YUV formats */
		YVYU = 300,
		YUY2,
		UYVY,
		HDYC,

		/* encoded formats */
		MJPEG = 400,
		H264
	};

	enum class AudioFormat {
		Any,
		Unknown,

		/* raw formats */
		Wave16bit = 100,
		WaveFloat,

		/* encoded formats */
		AAC = 200,
		AC3,
		MPGA /* MPEG 1 */
	};

	enum class AudioMode {
		Capture,
		DirectSound,
		WaveOut
	};

	enum class Result {
		Success,
		InUse,
		Error
	};

	struct VideoInfo {
		int         minCX, minCY;
		int         maxCX, maxCY;
		int         granularityCX, granularityCY;
		long long   minInterval, maxInterval;
		VideoFormat format;
	};

	struct AudioInfo {
		int         minChannels, maxChannels;
		int         channelsGranularity;
		int         minSampleRate, maxSampleRate;
		int         sampleRateGranularity;
		AudioFormat format;
	};

	struct DeviceId {
		std::wstring name;
		std::wstring path;
	};

	struct VideoDevice : DeviceId {
		bool audioAttached = false;
		std::vector<VideoInfo> caps;
	};

	struct AudioDevice : DeviceId {
		std::vector<AudioInfo> caps;
	};

	struct Config : DeviceId {
		/** Use the device's desired default config */
		bool        useDefaultConfig = true;
	};

	struct VideoConfig : Config {
		VideoProc   callback;

		/** Desired width/height of video.  */
		int         cx = 0, cy = 0;

		/** Desired frame interval (in 100-nanosecond units) */
		long long   frameInterval = 0;

		/** Internal video format. */
		VideoFormat internalFormat = VideoFormat::Any;

		/** Desired video format. */
		VideoFormat format = VideoFormat::Any;
	};

	struct AudioConfig : Config {
		AudioProc   callback;

		/**
		 * Use the audio attached to the video device
		 *
		 * (name/path memeber variables will be ignored)
		 */
		bool        useVideoDevice = false;

		/** Desired sample rate */
		int         sampleRate = 0;

		/** Desired channels */
		int         channels = 0;

		/** Desired audio format */
		AudioFormat format = AudioFormat::Any;

		/** Audio playback mode */
		AudioMode   mode = AudioMode::Capture;
	};

	class DSHOWCAPTURE_EXPORT Device {
		HDevice *context;

	public:
		Device(InitGraph initialize = InitGraph::False);
		~Device();

		bool        Valid() const;

		bool        ResetGraph();
		void        ShutdownGraph();

		bool        SetVideoConfig(VideoConfig *config);
		bool        SetAudioConfig(AudioConfig *config);

		/**
		 * Connects all the configured filters together.
		 *
		 * Call SetVideoConfig and/or SetAudioConfig before using.
		 */
		bool        ConnectFilters();

		Result      Start();
		void        Stop();

		bool        GetVideoConfig(VideoConfig &config) const;
		bool        GetAudioConfig(AudioConfig &config) const;
		bool        GetVideoDeviceId(DeviceId &id) const;
		bool        GetAudioDeviceId(DeviceId &id) const;

		/**
		 * Opens a DirectShow dialog associated with this device
		 *
		 * @param  type  The dialog type
		 */
		void        OpenDialog(void *hwnd, DialogType type) const;

		static bool EnumVideoDevices(std::vector<VideoDevice> &devices);
		static bool EnumAudioDevices(std::vector<AudioDevice> &devices);
	};

	struct VideoEncoderConfig : DeviceId {
		int fpsNumerator;
		int fpsDenominator;
		int bitrate;
		int keyframeInterval;
		int cx;
		int cy;
	};

	struct EncoderPacket {
		unsigned char  *data;
		size_t         size;
		long long      pts;
		long long      dts;
	};

	class VideoEncoder {
		HVideoEncoder *context;

	public:
		VideoEncoder();
		~VideoEncoder();

		bool Valid() const;
		bool Active() const;

		bool ResetGraph();

		bool SetConfig(VideoEncoderConfig &config);
		bool GetConfig(VideoEncoderConfig &config) const;

		bool Encode(unsigned char *data[DSHOW_MAX_PLANES],
				size_t linesize[DSHOW_MAX_PLANES],
				long long timestampStart,
				long long timestampEnd,
				EncoderPacket &packet,
				bool &new_packet);

		static bool EnumEncoders(std::vector<DeviceId> &encoders);
	};

	enum class LogType {
		Error,
		Warning,
		Info,
		Debug
	};

	typedef void (*LogCallback)(LogType type, const wchar_t *msg,
			void *param);

	DSHOWCAPTURE_EXPORT void SetLogCallback(LogCallback callback,
			void *param);
};
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2012 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>

#include "serve.h"
#include "html.h"

//FIXME:
#define DBG_SERVE 1

unsigned int dbg_serve = DBG_SERVE;

#define __printf(fd, fmt, arg...) fprintf(fd, fmt, ##arg)

#define __dprintf(lvl, fmt, arg...) do {			  \
    if (dbg_serve & lvl)						  \
      __printf(stderr, "%s: " fmt "\n", __func__, ##arg);	  \
  } while (0)

#define dprintf(fmt, arg...) __dprintf(DBG_SERVE, fmt, ##arg)

serve::serve()
  : f_kill_thread(false)
  , sock_fd(-1)
  , port(0)
{
	dprintf("()");
	tuners.clear();
}

serve::~serve()
{
	dprintf("()");
	tuners.clear();

	close_socket();
}

void serve::close_socket()
{
	dprintf("()");

	stop();

	if (sock_fd >= 0) {
		close(sock_fd);
		sock_fd = -1;
	}
	port = 0;
}

#if 0
serve::serve(const serve&)
{
	dprintf("(copy)");
}

serve& serve::operator= (const serve& cSource)
{
	dprintf("(operator=)");

	if (this == &cSource)
		return *this;

	return *this;
}
#endif

//static
void serve::streamback(void *p_this, const char *str)
{
	return static_cast<serve*>(p_this)->streamback(str);
}

void serve::streamback(const char *str)
{
//	fprintf(stdout, "%s --> %d\n", str, streamback_socket);
	fprintf(stdout, "%s\n", str);
}

//static
void* serve::serve_thread(void *p_this)
{
	return static_cast<serve*>(p_this)->serve_thread();
}

#define MAX_SOCKETS 4

#define CRLF "\r\n"

static char http_response[] =
	 "HTTP/1.1 200 OK"
	 CRLF
	 "Content-type: text/plain"
	 CRLF
	 "Content-length: 0"
	 CRLF
	 "Cache-Control: no-cache,no-store,private"
	 CRLF
	 "Expires: -1"
	 CRLF
	 "Connection: close"
	 CRLF
	 CRLF;

const char * serve::epg_header_footer_callback(void *context, bool header, bool channel)
{
	return static_cast<serve*>(context)->do_epg_header_footer_callback(context, header, channel);
}

const char * serve::do_epg_header_footer_callback(void * context, bool header, bool channel)
{
	if ((header) && (!channel)) streamback_started = true;
	if (!streamback_started) return NULL;
	if ((header) && (channel)) streamback_newchannel = true;
	const char * ret = html_dump_epg_header_footer_callback(context, header, channel);
	if ((!header) && (!channel)) fflush(stdout);
	return ret;
}

const char * serve::epg_event_callback(void * context,
				const char * channel_name,
				uint16_t chan_major,
				uint16_t chan_minor,
				//
				uint16_t event_id,
				time_t start_time,
				uint32_t length_sec,
				const char * name,
				const char * text)
{
	return static_cast<serve*>(context)->do_epg_event_callback(context, channel_name, chan_major, chan_minor, event_id, start_time, length_sec, name, text);
}

const char * serve::do_epg_event_callback(void * context,
				const char * channel_name,
				uint16_t chan_major,
				uint16_t chan_minor,
				//
				uint16_t event_id,
				time_t start_time,
				uint32_t length_sec,
				const char * name,
				const char * text)
{
	if (!streamback_started) return NULL;
#if 1
	if (streamback_newchannel) {
		streamback(html_dump_epg_event_callback(context, channel_name, chan_major, chan_minor, 0, 0, 0, NULL, NULL));
		streamback_newchannel = false;
		fflush(stdout);
	}
#endif
	return html_dump_epg_event_callback(context, NULL, 0, 0, event_id, start_time, length_sec, name, text);
}

void* serve::serve_thread()
{
	struct sockaddr_in tcpsa;
	socklen_t salen = sizeof(tcpsa);
	int i, rxlen = 0;
	int sock[MAX_SOCKETS];

	dprintf("(sock_fd=%d)", sock_fd);

	for (i = 0; i < MAX_SOCKETS; i++)
		sock[i] = -1;

	while (!f_kill_thread) {
		int d = accept(sock_fd, (struct sockaddr*)&tcpsa, &salen);
		if (d != -1) {
			for (i = 0; i < MAX_SOCKETS; i++)
				if (sock[i] == -1) {
					sock[i] = d;
					break;
				}
			if (sock[i] != d)
				perror("couldn't attach to socket");
		}
		for (i = 0; i < MAX_SOCKETS; i++)
			if (sock[i] != -1) {
				char buf[256] = { 0 };
				rxlen = recv(sock[i], buf, sizeof(buf), MSG_DONTWAIT);
				if (rxlen > 0) {
					bool send_http;
					getpeername(sock[i], (struct sockaddr*)&tcpsa, &salen);
					fprintf(stderr, "%s: %s\n", __func__, buf);
					send_http = ((strstr(buf, "HTTP")) && (strstr(buf, "GET"))) ? true : false;
#if 1
					//if (send_http)
						streamback_socket = sock[i];
						streamback_newchannel = false;
						streamback_started = false;
						set_dump_epg_cb(this,
								epg_header_footer_callback,
								epg_event_callback,
								streamback);
#endif
					command(buf); /* process */
					if (send_http) send(sock[i], http_response, strlen(http_response), 0 );
				} else if ( (rxlen == 0) || ( (rxlen == -1) && (errno != EAGAIN) ) ) {
					close(sock[i]);
					sock[i] = -1;
				}
			}
	}

	close_socket();
	pthread_exit(NULL);
}

int serve::start(uint16_t port_requested)
{
	struct sockaddr_in tcp_sock;

	dprintf("()");

	memset(&tcp_sock, 0, sizeof(tcp_sock));

	f_kill_thread = false;

	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_fd < 0) {
		perror("open socket failed");
		return sock_fd;
	}

	int reuse = 1;
	if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
		perror("setting reuse failed");
		return -1;
	}

	tcp_sock.sin_family = AF_INET;
	tcp_sock.sin_port = htons(port_requested);
	tcp_sock.sin_addr.s_addr = INADDR_ANY;

	if (bind(sock_fd, (struct sockaddr*)&tcp_sock, sizeof(tcp_sock)) < 0) {
		perror("bind to local interface failed");
		return -1;
	}
	port = port_requested;

	int fl = fcntl(sock_fd, F_GETFL, 0);
	if (fcntl(sock_fd, F_SETFL, fl | O_NONBLOCK) < 0) {
		perror("set non-blocking failed");
		return -1;
	}
	listen(sock_fd, 4);

	int ret = pthread_create(&h_thread, NULL, serve_thread, this);

	if (0 != ret)
		perror("pthread_create() failed");

	return ret;
}

void serve::stop()
{
	dprintf("()");

	stop_without_wait();

	while (-1 != sock_fd) {
		usleep(20*1000);
	}
	return;
}

#if 0
int serve::push(uint8_t* p_data)
{
	return 0;
}
#endif

#ifdef PRETTY_URLS
#define CHAR_CMD_SEP "&"
#define CHAR_CMD_SET "="
#else
#define CHAR_CMD_SEP ";"
#define CHAR_CMD_SET "/"
#endif

bool serve::command(char* cmdline)
{
	char *save;
	bool ret = false;
	char *item = strtok_r(cmdline, CHAR_CMD_SEP, &save);

	if (item) while (item) {
		if (!item)
			item = cmdline;

		ret = __command(item);
		if (!ret)
			return ret;

		item = strtok_r(NULL, CHAR_CMD_SEP, &save);
	} else
		ret = __command(cmdline);

	return ret;
}

static void chandump(void *context,
		     uint16_t lcn, uint16_t major, uint16_t minor,
		     uint16_t physical_channel, uint32_t freq, const char *modulation,
		     unsigned char *service_name, uint16_t vpid, uint16_t apid, uint16_t program_number)
{
	char channelno[7]; /* XXX.XXX */
	if (major + minor > 1)
		sprintf(channelno, "%d.%d", major, minor);
	else if (lcn)
		sprintf(channelno, "%d", lcn);
	else
		sprintf(channelno, "%d", physical_channel);
#if 0
	fprintf(stdout, "%s-%s:%d:%s:%d:%d:%d\n",
		channelno,
		service_name,
		freq,//iter_vct->second.carrier_freq,
		modulation,
		vpid, apid, program_number);
#else
	fprintf(stdout, "%s-%s: service/%d;channel/%d\n",
		channelno,
		service_name,
		program_number,
		physical_channel);
#endif
}

bool serve::__command(char* cmdline)
{
	char *arg, *save;
	char *cmd = strtok_r(cmdline, CHAR_CMD_SET, &save);

	if (!cmd)
		cmd = cmdline;
	arg = strtok_r(NULL, CHAR_CMD_SET, &save);

	unsigned int tuner_id, scan_flags = 0; // FIXME

	if (strstr(cmd, "tuner")) {
		tuner_id = atoi(arg);
		cmd = strtok_r(NULL, CHAR_CMD_SET, &save);
		arg = strtok_r(NULL, CHAR_CMD_SET, &save);
	} else
		tuner_id = 0;

	tune* tuner = (tuners.count(tuner_id)) ? tuners[tuner_id] : NULL;
	if (!tuner) {
		fprintf(stderr, "NO TUNER!\n");
		return false;
	}
//	if (strstr(cmd, "channels")) {
//		fprintf(stderr, "dumping channel list...\n");
	if (strstr(cmd, "scan")) {
		fprintf(stderr, "scanning for services...\n");

		if (!scan_flags)
			scan_flags = SCAN_VSB;

		tuner->feeder.parser.set_chandump_callback(chandump);
		tuner->scan_for_services(scan_flags, 0, 0, false);

	} else if (strstr(cmd, "channel")) {
		int channel = atoi(arg);
		fprintf(stderr, "TUNE to channel %d...(%s)\n", channel, arg);
		if (tuner->open_fe() < 0) {
			fprintf(stderr, "open_fe() failed!\n");
			return false;
		}
		if (!scan_flags)
			scan_flags = SCAN_VSB;

		if (tuner->tune_channel((scan_flags == SCAN_VSB) ? VSB_8 : QAM_256, channel)) {

			if (!tuner->wait_for_lock_or_timeout(2000)) {
				tuner->close_fe();
				fprintf(stderr, "no lock!\n");
				return false; /* NO LOCK! */
			}
			tuner->feeder.parser.set_channel_info(channel,
							     (scan_flags == SCAN_VSB) ? atsc_vsb_chan_to_freq(channel) : atsc_qam_chan_to_freq(channel),
							     (scan_flags == SCAN_VSB) ? "8VSB" : "QAM_256");
			tuner->start_feed();
		}

	} else if (strstr(cmd, "service")) {
		fprintf(stderr, "selecting service id...\n");
		tuner->feeder.parser.set_service_ids(arg);
	} else if (strstr(cmd, "stream")) {
		fprintf(stderr, "adding stream target...\n");
		tuner->feeder.parser.add_output(arg);
	} else if (strstr(cmd, "epg")) {
		fprintf(stderr, "dumping epg...\n");
		fprintf(stderr, "%s\n", tuner->feeder.parser.epg_dump());
	} else if (strstr(cmd, "stop")) {
		fprintf(stderr, "stopping...\n");
		tuner->stop_feed();
		tuner->close_fe();
	}

	return true;
}
<commit_msg>serve: use MAX_SOCKETS macro instead of hard-coded integer<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2012 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>

#include "serve.h"
#include "html.h"

//FIXME:
#define DBG_SERVE 1

unsigned int dbg_serve = DBG_SERVE;

#define __printf(fd, fmt, arg...) fprintf(fd, fmt, ##arg)

#define __dprintf(lvl, fmt, arg...) do {			  \
    if (dbg_serve & lvl)						  \
      __printf(stderr, "%s: " fmt "\n", __func__, ##arg);	  \
  } while (0)

#define dprintf(fmt, arg...) __dprintf(DBG_SERVE, fmt, ##arg)

serve::serve()
  : f_kill_thread(false)
  , sock_fd(-1)
  , port(0)
{
	dprintf("()");
	tuners.clear();
}

serve::~serve()
{
	dprintf("()");
	tuners.clear();

	close_socket();
}

void serve::close_socket()
{
	dprintf("()");

	stop();

	if (sock_fd >= 0) {
		close(sock_fd);
		sock_fd = -1;
	}
	port = 0;
}

#if 0
serve::serve(const serve&)
{
	dprintf("(copy)");
}

serve& serve::operator= (const serve& cSource)
{
	dprintf("(operator=)");

	if (this == &cSource)
		return *this;

	return *this;
}
#endif

//static
void serve::streamback(void *p_this, const char *str)
{
	return static_cast<serve*>(p_this)->streamback(str);
}

void serve::streamback(const char *str)
{
//	fprintf(stdout, "%s --> %d\n", str, streamback_socket);
	fprintf(stdout, "%s\n", str);
}

//static
void* serve::serve_thread(void *p_this)
{
	return static_cast<serve*>(p_this)->serve_thread();
}

#define MAX_SOCKETS 4

#define CRLF "\r\n"

static char http_response[] =
	 "HTTP/1.1 200 OK"
	 CRLF
	 "Content-type: text/plain"
	 CRLF
	 "Content-length: 0"
	 CRLF
	 "Cache-Control: no-cache,no-store,private"
	 CRLF
	 "Expires: -1"
	 CRLF
	 "Connection: close"
	 CRLF
	 CRLF;

const char * serve::epg_header_footer_callback(void *context, bool header, bool channel)
{
	return static_cast<serve*>(context)->do_epg_header_footer_callback(context, header, channel);
}

const char * serve::do_epg_header_footer_callback(void * context, bool header, bool channel)
{
	if ((header) && (!channel)) streamback_started = true;
	if (!streamback_started) return NULL;
	if ((header) && (channel)) streamback_newchannel = true;
	const char * ret = html_dump_epg_header_footer_callback(context, header, channel);
	if ((!header) && (!channel)) fflush(stdout);
	return ret;
}

const char * serve::epg_event_callback(void * context,
				const char * channel_name,
				uint16_t chan_major,
				uint16_t chan_minor,
				//
				uint16_t event_id,
				time_t start_time,
				uint32_t length_sec,
				const char * name,
				const char * text)
{
	return static_cast<serve*>(context)->do_epg_event_callback(context, channel_name, chan_major, chan_minor, event_id, start_time, length_sec, name, text);
}

const char * serve::do_epg_event_callback(void * context,
				const char * channel_name,
				uint16_t chan_major,
				uint16_t chan_minor,
				//
				uint16_t event_id,
				time_t start_time,
				uint32_t length_sec,
				const char * name,
				const char * text)
{
	if (!streamback_started) return NULL;
#if 1
	if (streamback_newchannel) {
		streamback(html_dump_epg_event_callback(context, channel_name, chan_major, chan_minor, 0, 0, 0, NULL, NULL));
		streamback_newchannel = false;
		fflush(stdout);
	}
#endif
	return html_dump_epg_event_callback(context, NULL, 0, 0, event_id, start_time, length_sec, name, text);
}

void* serve::serve_thread()
{
	struct sockaddr_in tcpsa;
	socklen_t salen = sizeof(tcpsa);
	int i, rxlen = 0;
	int sock[MAX_SOCKETS];

	dprintf("(sock_fd=%d)", sock_fd);

	for (i = 0; i < MAX_SOCKETS; i++)
		sock[i] = -1;

	while (!f_kill_thread) {
		int d = accept(sock_fd, (struct sockaddr*)&tcpsa, &salen);
		if (d != -1) {
			for (i = 0; i < MAX_SOCKETS; i++)
				if (sock[i] == -1) {
					sock[i] = d;
					break;
				}
			if (sock[i] != d)
				perror("couldn't attach to socket");
		}
		for (i = 0; i < MAX_SOCKETS; i++)
			if (sock[i] != -1) {
				char buf[256] = { 0 };
				rxlen = recv(sock[i], buf, sizeof(buf), MSG_DONTWAIT);
				if (rxlen > 0) {
					bool send_http;
					getpeername(sock[i], (struct sockaddr*)&tcpsa, &salen);
					fprintf(stderr, "%s: %s\n", __func__, buf);
					send_http = ((strstr(buf, "HTTP")) && (strstr(buf, "GET"))) ? true : false;
#if 1
					//if (send_http)
						streamback_socket = sock[i];
						streamback_newchannel = false;
						streamback_started = false;
						set_dump_epg_cb(this,
								epg_header_footer_callback,
								epg_event_callback,
								streamback);
#endif
					command(buf); /* process */
					if (send_http) send(sock[i], http_response, strlen(http_response), 0 );
				} else if ( (rxlen == 0) || ( (rxlen == -1) && (errno != EAGAIN) ) ) {
					close(sock[i]);
					sock[i] = -1;
				}
			}
	}

	close_socket();
	pthread_exit(NULL);
}

int serve::start(uint16_t port_requested)
{
	struct sockaddr_in tcp_sock;

	dprintf("()");

	memset(&tcp_sock, 0, sizeof(tcp_sock));

	f_kill_thread = false;

	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_fd < 0) {
		perror("open socket failed");
		return sock_fd;
	}

	int reuse = 1;
	if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
		perror("setting reuse failed");
		return -1;
	}

	tcp_sock.sin_family = AF_INET;
	tcp_sock.sin_port = htons(port_requested);
	tcp_sock.sin_addr.s_addr = INADDR_ANY;

	if (bind(sock_fd, (struct sockaddr*)&tcp_sock, sizeof(tcp_sock)) < 0) {
		perror("bind to local interface failed");
		return -1;
	}
	port = port_requested;

	int fl = fcntl(sock_fd, F_GETFL, 0);
	if (fcntl(sock_fd, F_SETFL, fl | O_NONBLOCK) < 0) {
		perror("set non-blocking failed");
		return -1;
	}
	listen(sock_fd, MAX_SOCKETS);

	int ret = pthread_create(&h_thread, NULL, serve_thread, this);

	if (0 != ret)
		perror("pthread_create() failed");

	return ret;
}

void serve::stop()
{
	dprintf("()");

	stop_without_wait();

	while (-1 != sock_fd) {
		usleep(20*1000);
	}
	return;
}

#if 0
int serve::push(uint8_t* p_data)
{
	return 0;
}
#endif

#ifdef PRETTY_URLS
#define CHAR_CMD_SEP "&"
#define CHAR_CMD_SET "="
#else
#define CHAR_CMD_SEP ";"
#define CHAR_CMD_SET "/"
#endif

bool serve::command(char* cmdline)
{
	char *save;
	bool ret = false;
	char *item = strtok_r(cmdline, CHAR_CMD_SEP, &save);

	if (item) while (item) {
		if (!item)
			item = cmdline;

		ret = __command(item);
		if (!ret)
			return ret;

		item = strtok_r(NULL, CHAR_CMD_SEP, &save);
	} else
		ret = __command(cmdline);

	return ret;
}

static void chandump(void *context,
		     uint16_t lcn, uint16_t major, uint16_t minor,
		     uint16_t physical_channel, uint32_t freq, const char *modulation,
		     unsigned char *service_name, uint16_t vpid, uint16_t apid, uint16_t program_number)
{
	char channelno[7]; /* XXX.XXX */
	if (major + minor > 1)
		sprintf(channelno, "%d.%d", major, minor);
	else if (lcn)
		sprintf(channelno, "%d", lcn);
	else
		sprintf(channelno, "%d", physical_channel);
#if 0
	fprintf(stdout, "%s-%s:%d:%s:%d:%d:%d\n",
		channelno,
		service_name,
		freq,//iter_vct->second.carrier_freq,
		modulation,
		vpid, apid, program_number);
#else
	fprintf(stdout, "%s-%s: service/%d;channel/%d\n",
		channelno,
		service_name,
		program_number,
		physical_channel);
#endif
}

bool serve::__command(char* cmdline)
{
	char *arg, *save;
	char *cmd = strtok_r(cmdline, CHAR_CMD_SET, &save);

	if (!cmd)
		cmd = cmdline;
	arg = strtok_r(NULL, CHAR_CMD_SET, &save);

	unsigned int tuner_id, scan_flags = 0; // FIXME

	if (strstr(cmd, "tuner")) {
		tuner_id = atoi(arg);
		cmd = strtok_r(NULL, CHAR_CMD_SET, &save);
		arg = strtok_r(NULL, CHAR_CMD_SET, &save);
	} else
		tuner_id = 0;

	tune* tuner = (tuners.count(tuner_id)) ? tuners[tuner_id] : NULL;
	if (!tuner) {
		fprintf(stderr, "NO TUNER!\n");
		return false;
	}
//	if (strstr(cmd, "channels")) {
//		fprintf(stderr, "dumping channel list...\n");
	if (strstr(cmd, "scan")) {
		fprintf(stderr, "scanning for services...\n");

		if (!scan_flags)
			scan_flags = SCAN_VSB;

		tuner->feeder.parser.set_chandump_callback(chandump);
		tuner->scan_for_services(scan_flags, 0, 0, false);

	} else if (strstr(cmd, "channel")) {
		int channel = atoi(arg);
		fprintf(stderr, "TUNE to channel %d...(%s)\n", channel, arg);
		if (tuner->open_fe() < 0) {
			fprintf(stderr, "open_fe() failed!\n");
			return false;
		}
		if (!scan_flags)
			scan_flags = SCAN_VSB;

		if (tuner->tune_channel((scan_flags == SCAN_VSB) ? VSB_8 : QAM_256, channel)) {

			if (!tuner->wait_for_lock_or_timeout(2000)) {
				tuner->close_fe();
				fprintf(stderr, "no lock!\n");
				return false; /* NO LOCK! */
			}
			tuner->feeder.parser.set_channel_info(channel,
							     (scan_flags == SCAN_VSB) ? atsc_vsb_chan_to_freq(channel) : atsc_qam_chan_to_freq(channel),
							     (scan_flags == SCAN_VSB) ? "8VSB" : "QAM_256");
			tuner->start_feed();
		}

	} else if (strstr(cmd, "service")) {
		fprintf(stderr, "selecting service id...\n");
		tuner->feeder.parser.set_service_ids(arg);
	} else if (strstr(cmd, "stream")) {
		fprintf(stderr, "adding stream target...\n");
		tuner->feeder.parser.add_output(arg);
	} else if (strstr(cmd, "epg")) {
		fprintf(stderr, "dumping epg...\n");
		fprintf(stderr, "%s\n", tuner->feeder.parser.epg_dump());
	} else if (strstr(cmd, "stop")) {
		fprintf(stderr, "stopping...\n");
		tuner->stop_feed();
		tuner->close_fe();
	}

	return true;
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "MaxQpsThread.h"
#include "FEProblem.h"

#include "libmesh/fe_base.h"
#include "libmesh/threads.h"
#include LIBMESH_INCLUDE_UNORDERED_SET
LIBMESH_DEFINE_HASH_POINTERS
#include "libmesh/quadrature.h"

MaxQpsThread::MaxQpsThread(FEProblemBase & fe_problem,
                           QuadratureType qtype,
                           Order order,
                           Order face_order)
  : _fe_problem(fe_problem),
    _qtype(qtype),
    _order(order),
    _face_order(face_order),
    _max(0),
    _max_shape_funcs(0)
{
}

// Splitting Constructor
MaxQpsThread::MaxQpsThread(MaxQpsThread & x, Threads::split /*split*/)
  : _fe_problem(x._fe_problem),
    _qtype(x._qtype),
    _order(x._order),
    _face_order(x._face_order),
    _max(x._max),
    _max_shape_funcs(x._max_shape_funcs)
{
}

void
MaxQpsThread::operator()(const ConstElemRange & range)
{
  ParallelUniqueId puid;
  _tid = puid.id;

  // For short circuiting reinit
  std::set<ElemType> seen_it;
  for (const auto & elem : range)
  {
    // Only reinit if the element type has not previously been seen
    if (seen_it.insert(elem->type()).second)
    {
      FEType fe_type(FIRST, LAGRANGE);
      unsigned int dim = elem->dim();
      unsigned int side = 0; // we assume that any element will have at least one side ;)

      // We cannot mess with the FE objects in Assembly, because we might need to request second
      // derivatives
      // later on. If we used them, we'd call reinit on them, thus making the call to request second
      // derivatives harmful (i.e. leading to segfaults/asserts). Thus, we have to use a locally
      // allocated object here.
      std::unique_ptr<FEBase> fe(FEBase::build(dim, fe_type));

      // figure out the number of qps for volume
      std::unique_ptr<QBase> qrule(QBase::build(_qtype, dim, _order));
      fe->attach_quadrature_rule(qrule.get());
      fe->reinit(elem);
      if (qrule->n_points() > _max)
        _max = qrule->n_points();

      unsigned int n_shape_funcs = fe->n_shape_functions();
      if (n_shape_funcs > _max_shape_funcs)
        _max_shape_funcs = n_shape_funcs;

      // figure out the number of qps for the face
      // NOTE: user might specify higher order rule for faces, thus possibly ending up with more qps
      // than in the volume
      std::unique_ptr<QBase> qrule_face(QBase::build(_qtype, dim - 1, _face_order));
      fe->attach_quadrature_rule(qrule_face.get());
      fe->reinit(elem, side);
      if (qrule_face->n_points() > _max)
        _max = qrule_face->n_points();

      // In initial conditions nodes are enumerated as pretend quadrature points
      // using the _qp index to access coupled variables. In order to be able to
      // use _zero (resized according to _max_qps) with _qp, we need to count nodes.
      if (elem->n_nodes() > _max)
        _max = elem->n_nodes();
    }
  }
}

void
MaxQpsThread::join(const MaxQpsThread & y)
{
  if (y._max > _max)
    _max = y._max;

  if (y._max_shape_funcs > _max_shape_funcs)
    _max_shape_funcs = y._max_shape_funcs;
}
<commit_msg>Prerequest properly in MaxQpsThread<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "MaxQpsThread.h"
#include "FEProblem.h"

#include "libmesh/fe_base.h"
#include "libmesh/threads.h"
#include LIBMESH_INCLUDE_UNORDERED_SET
LIBMESH_DEFINE_HASH_POINTERS
#include "libmesh/quadrature.h"

MaxQpsThread::MaxQpsThread(FEProblemBase & fe_problem,
                           QuadratureType qtype,
                           Order order,
                           Order face_order)
  : _fe_problem(fe_problem),
    _qtype(qtype),
    _order(order),
    _face_order(face_order),
    _max(0),
    _max_shape_funcs(0)
{
}

// Splitting Constructor
MaxQpsThread::MaxQpsThread(MaxQpsThread & x, Threads::split /*split*/)
  : _fe_problem(x._fe_problem),
    _qtype(x._qtype),
    _order(x._order),
    _face_order(x._face_order),
    _max(x._max),
    _max_shape_funcs(x._max_shape_funcs)
{
}

void
MaxQpsThread::operator()(const ConstElemRange & range)
{
  ParallelUniqueId puid;
  _tid = puid.id;

  // For short circuiting reinit
  std::set<ElemType> seen_it;
  for (const auto & elem : range)
  {
    // Only reinit if the element type has not previously been seen
    if (seen_it.insert(elem->type()).second)
    {
      FEType fe_type(FIRST, LAGRANGE);
      unsigned int dim = elem->dim();
      unsigned int side = 0; // we assume that any element will have at least one side ;)

      // We cannot mess with the FE objects in Assembly, because we might need to request second
      // derivatives
      // later on. If we used them, we'd call reinit on them, thus making the call to request second
      // derivatives harmful (i.e. leading to segfaults/asserts). Thus, we have to use a locally
      // allocated object here.
      //
      // We'll use one for element interiors, which calculates nothing
      std::unique_ptr<FEBase> fe(FEBase::build(dim, fe_type));
      fe->get_nothing();

      // And another for element sides, which calculates the minimum
      // libMesh currently allows for that
      std::unique_ptr<FEBase> side_fe(FEBase::build(dim, fe_type));
      side_fe->get_xyz();

      // figure out the number of qps for volume
      std::unique_ptr<QBase> qrule(QBase::build(_qtype, dim, _order));
      fe->attach_quadrature_rule(qrule.get());
      fe->reinit(elem);
      if (qrule->n_points() > _max)
        _max = qrule->n_points();

      unsigned int n_shape_funcs = fe->n_shape_functions();
      if (n_shape_funcs > _max_shape_funcs)
        _max_shape_funcs = n_shape_funcs;

      // figure out the number of qps for the face
      // NOTE: user might specify higher order rule for faces, thus possibly ending up with more qps
      // than in the volume
      std::unique_ptr<QBase> qrule_face(QBase::build(_qtype, dim - 1, _face_order));
      side_fe->attach_quadrature_rule(qrule_face.get());
      side_fe->reinit(elem, side);
      if (qrule_face->n_points() > _max)
        _max = qrule_face->n_points();

      // In initial conditions nodes are enumerated as pretend quadrature points
      // using the _qp index to access coupled variables. In order to be able to
      // use _zero (resized according to _max_qps) with _qp, we need to count nodes.
      if (elem->n_nodes() > _max)
        _max = elem->n_nodes();
    }
  }
}

void
MaxQpsThread::join(const MaxQpsThread & y)
{
  if (y._max > _max)
    _max = y._max;

  if (y._max_shape_funcs > _max_shape_funcs)
    _max_shape_funcs = y._max_shape_funcs;
}
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Material.h"
#include "SubProblem.h"
#include "MaterialData.h"
#include "Assembly.h"

// libMesh includes
#include "libmesh/quadrature.h"

template<>
InputParameters validParams<Material>()
{
  InputParameters params = validParams<MooseObject>();
  params += validParams<BlockRestrictable>();
  params += validParams<BoundaryRestrictable>();
  params += validParams<RandomInterface>();

  params.addParam<bool>("use_displaced_mesh", false, "Whether or not this object should use the displaced mesh for computation.  Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used.");

  // Outputs
  params += validParams<OutputInterface>();
  params.set<std::vector<OutputName> >("outputs") =  std::vector<OutputName>(1, "none");
  params.addParam<std::vector<std::string> >("output_properties", "List of material properties, from this material, to output (outputs must also be defined to an output type)");

  params.addParamNamesToGroup("outputs output_properties", "Outputs");
  params.addParamNamesToGroup("use_displaced_mesh", "Advanced");
  params.registerBase("Material");

  return params;
}

Material::Material(const InputParameters & parameters) :
    MooseObject(parameters),
    BlockRestrictable(parameters),
    BoundaryRestrictable(parameters, blockIDs()),
    SetupInterface(parameters),
    Coupleable(parameters, false),
    MooseVariableDependencyInterface(),
    ScalarCoupleable(parameters),
    FunctionInterface(parameters),
    UserObjectInterface(parameters),
    TransientInterface(parameters, "materials"),
    MaterialPropertyInterface(parameters, blockIDs(), boundaryIDs()),
    PostprocessorInterface(parameters),
    DependencyResolverInterface(),
    Restartable(parameters, "Materials"),
    ZeroInterface(parameters),
    MeshChangedInterface(parameters),

    // The false flag disables the automatic call  buildOutputVariableHideList;
    // for Material objects the hide lists are handled by MaterialOutputAction
    OutputInterface(parameters, false),
    RandomInterface(parameters, *parameters.get<FEProblem *>("_fe_problem"), parameters.get<THREAD_ID>("_tid"), false),
    _subproblem(*parameters.get<SubProblem *>("_subproblem")),
    _fe_problem(*parameters.get<FEProblem *>("_fe_problem")),
    _tid(parameters.get<THREAD_ID>("_tid")),
    _assembly(_subproblem.assembly(_tid)),
    _bnd(parameters.get<bool>("_bnd")),
    _neighbor(getParam<bool>("_neighbor")),
    _material_data(*parameters.get<MaterialData *>("_material_data")),
    _qp(std::numeric_limits<unsigned int>::max()),
    _qrule(_bnd ? _assembly.qRuleFace() : _assembly.qRule()),
    _JxW(_bnd ? _assembly.JxWFace() : _assembly.JxW()),
    _coord(_assembly.coordTransformation()),
    _q_point(_bnd ? _assembly.qPointsFace() : _assembly.qPoints()),
    _normals(_assembly.normals()),
    _current_elem(_neighbor ? _assembly.neighbor() : _assembly.elem()),
    _current_side(_neighbor ? _assembly.neighborSide() : _assembly.side()),
    _mesh(_subproblem.mesh()),
    _coord_sys(_assembly.coordSystem()),
    _has_stateful_property(false)
{
  // Fill in the MooseVariable dependencies
  const std::vector<MooseVariable *> & coupled_vars = getCoupledMooseVars();
  for (unsigned int i=0; i<coupled_vars.size(); i++)
    addMooseVariableDependency(coupled_vars[i]);

  // Update the MaterialData pointer in BlockRestrictable to use the correct MaterialData object
  _blk_material_data = &_material_data;
}

Material::~Material()
{
}

void
Material::computeProperties()
{
  for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
    computeQpProperties();
}

void
Material::initStatefulProperties(unsigned int n_points)
{
  if (_has_stateful_property)
    for (_qp = 0; _qp < n_points; ++_qp)
      initQpStatefulProperties();
}

void
Material::initQpStatefulProperties()
{
  mooseDoOnce(mooseWarning(std::string("Material \"") + name() + "\" declares one or more stateful properties but initQpStatefulProperties() was not overridden in the derived class."));
}

void
Material::computeQpProperties()
{
}

QpData *
Material::createData()
{
  return NULL;
}

void
Material::setZeroPropAsRequested(const std::string & prop_name)
{
  // look if property name is in _zero_props
  std::set<std::string>::iterator it = _zero_props.find(prop_name);
  if (it != _zero_props.end())
  {
    // move the property from _zero_props to _requested_props
    _requested_props.insert(*it);
    _zero_props.erase(it);
  }
}

void
Material::checkStatefulSanity() const
{
  for (std::map<std::string, int>::const_iterator it = _props_to_flags.begin(); it != _props_to_flags.end(); ++it)
  {
    if (static_cast<int>(it->second) % 2 == 0) // Only Stateful properties declared!
      mooseError("Material '" << name() << "' has stateful properties declared but not associated \"current\" properties." << it->second);
  }
}

void
Material::registerPropName(std::string prop_name, bool is_get, Material::Prop_State state)
{
  if (!is_get)
  {
    _props_to_flags[prop_name] |= static_cast<int>(state);
    if (static_cast<int>(state) % 2 == 0)
      _has_stateful_property = true;
  }

  // Store material properties for block ids
  for (std::set<SubdomainID>::const_iterator it = blockIDs().begin(); it != blockIDs().end(); ++it)
  {
    // Only save this prop as a "supplied" prop is it was registered as a result of a call to declareProperty not getMaterialProperty
    if (!is_get)
      _supplied_props.insert(prop_name);
    _fe_problem.storeMatPropName(*it, prop_name);
  }

  // Store material properties for the boundary ids
  for (std::set<BoundaryID>::const_iterator it = boundaryIDs().begin(); it != boundaryIDs().end(); ++it)
  {
    // Only save this prop as a "supplied" prop is it was registered as a result of a call to declareProperty not getMaterialProperty
    if (!is_get)
      _supplied_props.insert(prop_name);
    _fe_problem.storeMatPropName(*it, prop_name);
  }
}

std::set<OutputName>
Material::getOutputs()
{
  const std::vector<OutputName> & out = getParam<std::vector<OutputName> >("outputs");
  return std::set<OutputName>(out.begin(), out.end());
}

bool
Material::hasBlockMaterialPropertyHelper(const std::string & name)
{
  // Reference to MaterialWarehouse for testing and retrieving block ids
  MaterialWarehouse & material_warehouse = _fe_problem.getMaterialWarehouse(_tid);

  // Complete set of ids that this object is active
  const std::set<SubdomainID> & ids = hasBlocks(Moose::ANY_BLOCK_ID) ? meshBlockIDs() : blockIDs();

  // Flags for the various material types
  bool neighbor = getParam<bool>("_neighbor");
  bool bnd = getParam<bool>("_bnd");

  // Define function pointers to the correct has/get methods for the type of material
  bool(MaterialWarehouse::*has_func)(SubdomainID) const;
  std::vector<Material *> & (MaterialWarehouse::*get_func)(SubdomainID);
  if (bnd && neighbor)
  {
    has_func = &MaterialWarehouse::hasNeighborMaterials;
    get_func = &MaterialWarehouse::getNeighborMaterials;
  }
  else if (bnd && !neighbor)
  {
    has_func = &MaterialWarehouse::hasFaceMaterials;
    get_func = &MaterialWarehouse::getFaceMaterials;
  }
  else
  {
    has_func = &MaterialWarehouse::hasMaterials;
    get_func = &MaterialWarehouse::getMaterials;
  }

  // Loop over each id for this object
  for (std::set<SubdomainID>::const_iterator id_it = ids.begin(); id_it != ids.end(); ++id_it)
  {
    // Storage of material properties that have been DECLARED on this id
    std::set<std::string> declared_props;

    // If block materials exist, populated the set of properties that were declared
    if ((material_warehouse.*has_func)(*id_it))
    {
      std::vector<Material *> mats = (material_warehouse.*get_func)(*id_it);
      for (std::vector<Material *>::iterator mat_it = mats.begin(); mat_it != mats.end(); ++mat_it)
      {
        const std::set<std::string> & mat_props = (*mat_it)->getSuppliedItems();
        declared_props.insert(mat_props.begin(), mat_props.end());
      }
    }

    // If the supplied property is not in the list of properties on the current id, return false
    if (declared_props.find(name) == declared_props.end())
      return false;
  }

  // If you get here the supplied property is defined on all blocks
  return true;
}
<commit_msg>Inherit "implicit" parameter from TransientInterface<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Material.h"
#include "SubProblem.h"
#include "MaterialData.h"
#include "Assembly.h"

// libMesh includes
#include "libmesh/quadrature.h"

template<>
InputParameters validParams<Material>()
{
  InputParameters params = validParams<MooseObject>();
  params += validParams<BlockRestrictable>();
  params += validParams<BoundaryRestrictable>();
  params += validParams<TransientInterface>();
  params += validParams<RandomInterface>();

  params.addParam<bool>("use_displaced_mesh", false, "Whether or not this object should use the displaced mesh for computation.  Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used.");

  // Outputs
  params += validParams<OutputInterface>();
  params.set<std::vector<OutputName> >("outputs") =  std::vector<OutputName>(1, "none");
  params.addParam<std::vector<std::string> >("output_properties", "List of material properties, from this material, to output (outputs must also be defined to an output type)");

  params.addParamNamesToGroup("outputs output_properties", "Outputs");
  params.addParamNamesToGroup("use_displaced_mesh", "Advanced");
  params.registerBase("Material");

  return params;
}

Material::Material(const InputParameters & parameters) :
    MooseObject(parameters),
    BlockRestrictable(parameters),
    BoundaryRestrictable(parameters, blockIDs()),
    SetupInterface(parameters),
    Coupleable(parameters, false),
    MooseVariableDependencyInterface(),
    ScalarCoupleable(parameters),
    FunctionInterface(parameters),
    UserObjectInterface(parameters),
    TransientInterface(parameters, "materials"),
    MaterialPropertyInterface(parameters, blockIDs(), boundaryIDs()),
    PostprocessorInterface(parameters),
    DependencyResolverInterface(),
    Restartable(parameters, "Materials"),
    ZeroInterface(parameters),
    MeshChangedInterface(parameters),

    // The false flag disables the automatic call  buildOutputVariableHideList;
    // for Material objects the hide lists are handled by MaterialOutputAction
    OutputInterface(parameters, false),
    RandomInterface(parameters, *parameters.get<FEProblem *>("_fe_problem"), parameters.get<THREAD_ID>("_tid"), false),
    _subproblem(*parameters.get<SubProblem *>("_subproblem")),
    _fe_problem(*parameters.get<FEProblem *>("_fe_problem")),
    _tid(parameters.get<THREAD_ID>("_tid")),
    _assembly(_subproblem.assembly(_tid)),
    _bnd(parameters.get<bool>("_bnd")),
    _neighbor(getParam<bool>("_neighbor")),
    _material_data(*parameters.get<MaterialData *>("_material_data")),
    _qp(std::numeric_limits<unsigned int>::max()),
    _qrule(_bnd ? _assembly.qRuleFace() : _assembly.qRule()),
    _JxW(_bnd ? _assembly.JxWFace() : _assembly.JxW()),
    _coord(_assembly.coordTransformation()),
    _q_point(_bnd ? _assembly.qPointsFace() : _assembly.qPoints()),
    _normals(_assembly.normals()),
    _current_elem(_neighbor ? _assembly.neighbor() : _assembly.elem()),
    _current_side(_neighbor ? _assembly.neighborSide() : _assembly.side()),
    _mesh(_subproblem.mesh()),
    _coord_sys(_assembly.coordSystem()),
    _has_stateful_property(false)
{
  // Fill in the MooseVariable dependencies
  const std::vector<MooseVariable *> & coupled_vars = getCoupledMooseVars();
  for (unsigned int i=0; i<coupled_vars.size(); i++)
    addMooseVariableDependency(coupled_vars[i]);

  // Update the MaterialData pointer in BlockRestrictable to use the correct MaterialData object
  _blk_material_data = &_material_data;
}

Material::~Material()
{
}

void
Material::computeProperties()
{
  for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
    computeQpProperties();
}

void
Material::initStatefulProperties(unsigned int n_points)
{
  if (_has_stateful_property)
    for (_qp = 0; _qp < n_points; ++_qp)
      initQpStatefulProperties();
}

void
Material::initQpStatefulProperties()
{
  mooseDoOnce(mooseWarning(std::string("Material \"") + name() + "\" declares one or more stateful properties but initQpStatefulProperties() was not overridden in the derived class."));
}

void
Material::computeQpProperties()
{
}

QpData *
Material::createData()
{
  return NULL;
}

void
Material::setZeroPropAsRequested(const std::string & prop_name)
{
  // look if property name is in _zero_props
  std::set<std::string>::iterator it = _zero_props.find(prop_name);
  if (it != _zero_props.end())
  {
    // move the property from _zero_props to _requested_props
    _requested_props.insert(*it);
    _zero_props.erase(it);
  }
}

void
Material::checkStatefulSanity() const
{
  for (std::map<std::string, int>::const_iterator it = _props_to_flags.begin(); it != _props_to_flags.end(); ++it)
  {
    if (static_cast<int>(it->second) % 2 == 0) // Only Stateful properties declared!
      mooseError("Material '" << name() << "' has stateful properties declared but not associated \"current\" properties." << it->second);
  }
}

void
Material::registerPropName(std::string prop_name, bool is_get, Material::Prop_State state)
{
  if (!is_get)
  {
    _props_to_flags[prop_name] |= static_cast<int>(state);
    if (static_cast<int>(state) % 2 == 0)
      _has_stateful_property = true;
  }

  // Store material properties for block ids
  for (std::set<SubdomainID>::const_iterator it = blockIDs().begin(); it != blockIDs().end(); ++it)
  {
    // Only save this prop as a "supplied" prop is it was registered as a result of a call to declareProperty not getMaterialProperty
    if (!is_get)
      _supplied_props.insert(prop_name);
    _fe_problem.storeMatPropName(*it, prop_name);
  }

  // Store material properties for the boundary ids
  for (std::set<BoundaryID>::const_iterator it = boundaryIDs().begin(); it != boundaryIDs().end(); ++it)
  {
    // Only save this prop as a "supplied" prop is it was registered as a result of a call to declareProperty not getMaterialProperty
    if (!is_get)
      _supplied_props.insert(prop_name);
    _fe_problem.storeMatPropName(*it, prop_name);
  }
}

std::set<OutputName>
Material::getOutputs()
{
  const std::vector<OutputName> & out = getParam<std::vector<OutputName> >("outputs");
  return std::set<OutputName>(out.begin(), out.end());
}

bool
Material::hasBlockMaterialPropertyHelper(const std::string & name)
{
  // Reference to MaterialWarehouse for testing and retrieving block ids
  MaterialWarehouse & material_warehouse = _fe_problem.getMaterialWarehouse(_tid);

  // Complete set of ids that this object is active
  const std::set<SubdomainID> & ids = hasBlocks(Moose::ANY_BLOCK_ID) ? meshBlockIDs() : blockIDs();

  // Flags for the various material types
  bool neighbor = getParam<bool>("_neighbor");
  bool bnd = getParam<bool>("_bnd");

  // Define function pointers to the correct has/get methods for the type of material
  bool(MaterialWarehouse::*has_func)(SubdomainID) const;
  std::vector<Material *> & (MaterialWarehouse::*get_func)(SubdomainID);
  if (bnd && neighbor)
  {
    has_func = &MaterialWarehouse::hasNeighborMaterials;
    get_func = &MaterialWarehouse::getNeighborMaterials;
  }
  else if (bnd && !neighbor)
  {
    has_func = &MaterialWarehouse::hasFaceMaterials;
    get_func = &MaterialWarehouse::getFaceMaterials;
  }
  else
  {
    has_func = &MaterialWarehouse::hasMaterials;
    get_func = &MaterialWarehouse::getMaterials;
  }

  // Loop over each id for this object
  for (std::set<SubdomainID>::const_iterator id_it = ids.begin(); id_it != ids.end(); ++id_it)
  {
    // Storage of material properties that have been DECLARED on this id
    std::set<std::string> declared_props;

    // If block materials exist, populated the set of properties that were declared
    if ((material_warehouse.*has_func)(*id_it))
    {
      std::vector<Material *> mats = (material_warehouse.*get_func)(*id_it);
      for (std::vector<Material *>::iterator mat_it = mats.begin(); mat_it != mats.end(); ++mat_it)
      {
        const std::set<std::string> & mat_props = (*mat_it)->getSuppliedItems();
        declared_props.insert(mat_props.begin(), mat_props.end());
      }
    }

    // If the supplied property is not in the list of properties on the current id, return false
    if (declared_props.find(name) == declared_props.end())
      return false;
  }

  // If you get here the supplied property is defined on all blocks
  return true;
}
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "PatternedMesh.h"
#include "Parser.h"
#include "InputParameters.h"

// libMesh includes
#include "libmesh/mesh_modification.h"
#include "libmesh/serial_mesh.h"
#include "libmesh/exodusII_io.h"

template<>
InputParameters validParams<PatternedMesh>()
{
  InputParameters params = validParams<MooseMesh>();
  params.addRequiredParam<std::vector<MeshFileName> >("files", "The name of the mesh files to read.  They are automatically assigned ids starting with zero.");

  params.addRangeCheckedParam<Real>("x_width", 0, "x_width>=0", "The tile width in the x direction");
  params.addRangeCheckedParam<Real>("y_width", 0, "y_width>=0", "The tile width in the y direction");
  params.addRangeCheckedParam<Real>("z_width", 0, "z_width>=0", "The tile width in the z direction");

  // x boundary names
  params.addParam<BoundaryName>("left_boundary", "left_boundary", "name of the left (x) boundary");
  params.addParam<BoundaryName>("right_boundary", "right_boundary", "name of the right (x) boundary");

  // y boundary names
  params.addParam<BoundaryName>("top_boundary", "top_boundary", "name of the top (y) boundary");
  params.addParam<BoundaryName>("bottom_boundary", "bottom_boundary", "name of the bottom (y) boundary");

  params.addRequiredParam<std::vector<std::vector<unsigned int> > >("pattern", "A double-indexed array starting with the upper-left corner");

  params.addClassDescription("Creates a 2D mesh from a specified set of unique 'tiles' meshes and a two-dimensional pattern.");

  return params;
}

PatternedMesh::PatternedMesh(const InputParameters & parameters) :
    MooseMesh(parameters),
    _files(getParam<std::vector<MeshFileName> >("files")),
    _pattern(getParam<std::vector<std::vector<unsigned int> > >("pattern")),
    _x_width(getParam<Real>("x_width")),
    _y_width(getParam<Real>("y_width")),
    _z_width(getParam<Real>("z_width"))
{
  // The PatternedMesh class only works with ReplicatedMesh
  errorIfDistributedMesh("PatternedMesh");

  _meshes.reserve(_files.size());

  // Read in all of the meshes
  for (auto i = beginIndex(_files); i < _files.size(); ++i)
  {
    _meshes.emplace_back(libmesh_make_unique<ReplicatedMesh>(_communicator));
    auto & mesh = _meshes.back();

    mesh->read(_files[i]);
  }

  _original_mesh = dynamic_cast<ReplicatedMesh *>(&getMesh());
  if (!_original_mesh)
    mooseError("PatternedMesh does not support DistributedMesh");

  // Create a mesh for all n-1 rows, the first row is the original mesh
  _row_meshes.reserve(_pattern.size() - 1);
  for (auto i = beginIndex(_pattern); i < _pattern.size() - 1; ++i)
    _row_meshes.emplace_back(libmesh_make_unique<ReplicatedMesh>(_communicator));
}

PatternedMesh::PatternedMesh(const PatternedMesh & other_mesh) :
    MooseMesh(other_mesh),
    _files(other_mesh._files),
    _pattern(other_mesh._pattern),
    _x_width(other_mesh._x_width),
    _y_width(other_mesh._y_width),
    _z_width(other_mesh._z_width)
{
}

PatternedMesh::~PatternedMesh()
{
}

MooseMesh &
PatternedMesh::clone() const
{
  return *(new PatternedMesh(*this));
}

void
PatternedMesh::buildMesh()
{
  // Local pointers to simplify algorithm
  std::vector<ReplicatedMesh *> row_meshes;
  row_meshes.reserve(_pattern.size());
  // First row is the original mesh
  row_meshes.push_back(_original_mesh);
  // Copy the remaining pointers into the local vector
  std::transform(_row_meshes.begin(), _row_meshes.end(), std::back_inserter(row_meshes),
                [](std::unique_ptr<ReplicatedMesh> & row_mesh)
                {
                  return row_mesh.get();
                });

  BoundaryID left = getBoundaryID(getParam<BoundaryName>("left_boundary"));
  BoundaryID right = getBoundaryID(getParam<BoundaryName>("right_boundary"));
  BoundaryID top = getBoundaryID(getParam<BoundaryName>("top_boundary"));
  BoundaryID bottom = getBoundaryID(getParam<BoundaryName>("bottom_boundary"));

  // Build each row mesh
  for (unsigned int i = 0; i < _pattern.size(); i++)
    for (unsigned int j = 0; j < _pattern[i].size(); j++)
    {
      Real
        deltax = j * _x_width,
        deltay = i * _y_width;

      // If this is the first cell of the row initialize the row mesh
      if (j == 0)
      {
        row_meshes[i]->read(_files[_pattern[i][j]]);

        MeshTools::Modification::translate(*row_meshes[i], deltax, -deltay, 0);

        continue;
      }

      ReplicatedMesh & cell_mesh = *_meshes[_pattern[i][j]];

      // Move the mesh into the right spot.  -i because we are starting at the top
      MeshTools::Modification::translate(cell_mesh, deltax, -deltay, 0);

      row_meshes[i]->stitch_meshes(dynamic_cast<ReplicatedMesh &>(cell_mesh), right, left, TOLERANCE, /*clear_stitched_boundary_ids=*/true);

      // Undo the translation
      MeshTools::Modification::translate(cell_mesh, -deltax, deltay, 0);
    }

  // Now stitch together the rows
  // We're going to stitch them all to row 0 (which is the real mesh)
  for (unsigned int i = 1; i < _pattern.size(); i++)
    row_meshes[0]->stitch_meshes(*row_meshes[i], bottom, top, TOLERANCE, /*clear_stitched_boundary_ids=*/true);
}
<commit_msg>Addressing comments, making the rest of the class consistent<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "PatternedMesh.h"
#include "Parser.h"
#include "InputParameters.h"

// libMesh includes
#include "libmesh/mesh_modification.h"
#include "libmesh/serial_mesh.h"
#include "libmesh/exodusII_io.h"

template<>
InputParameters validParams<PatternedMesh>()
{
  InputParameters params = validParams<MooseMesh>();
  params.addRequiredParam<std::vector<MeshFileName> >("files", "The name of the mesh files to read.  They are automatically assigned ids starting with zero.");

  params.addRangeCheckedParam<Real>("x_width", 0, "x_width>=0", "The tile width in the x direction");
  params.addRangeCheckedParam<Real>("y_width", 0, "y_width>=0", "The tile width in the y direction");
  params.addRangeCheckedParam<Real>("z_width", 0, "z_width>=0", "The tile width in the z direction");

  // x boundary names
  params.addParam<BoundaryName>("left_boundary", "left_boundary", "name of the left (x) boundary");
  params.addParam<BoundaryName>("right_boundary", "right_boundary", "name of the right (x) boundary");

  // y boundary names
  params.addParam<BoundaryName>("top_boundary", "top_boundary", "name of the top (y) boundary");
  params.addParam<BoundaryName>("bottom_boundary", "bottom_boundary", "name of the bottom (y) boundary");

  params.addRequiredParam<std::vector<std::vector<unsigned int> > >("pattern", "A double-indexed array starting with the upper-left corner");

  params.addClassDescription("Creates a 2D mesh from a specified set of unique 'tiles' meshes and a two-dimensional pattern.");

  return params;
}

PatternedMesh::PatternedMesh(const InputParameters & parameters) :
    MooseMesh(parameters),
    _files(getParam<std::vector<MeshFileName> >("files")),
    _pattern(getParam<std::vector<std::vector<unsigned int> > >("pattern")),
    _x_width(getParam<Real>("x_width")),
    _y_width(getParam<Real>("y_width")),
    _z_width(getParam<Real>("z_width"))
{
  // The PatternedMesh class only works with ReplicatedMesh
  errorIfDistributedMesh("PatternedMesh");

  _meshes.reserve(_files.size());

  // Read in all of the meshes
  for (auto i = beginIndex(_files); i < _files.size(); ++i)
  {
    _meshes.emplace_back(libmesh_make_unique<ReplicatedMesh>(_communicator));
    auto & mesh = _meshes.back();

    mesh->read(_files[i]);
  }

  _original_mesh = dynamic_cast<ReplicatedMesh *>(&getMesh());
  if (!_original_mesh)
    mooseError("PatternedMesh does not support DistributedMesh");

  // Create a mesh for all n-1 rows, the first row is the original mesh
  _row_meshes.reserve(_pattern.size() - 1);
  for (auto i = beginIndex(_pattern); i < _pattern.size() - 1; ++i)
    _row_meshes.emplace_back(libmesh_make_unique<ReplicatedMesh>(_communicator));
}

PatternedMesh::PatternedMesh(const PatternedMesh & other_mesh) :
    MooseMesh(other_mesh),
    _files(other_mesh._files),
    _pattern(other_mesh._pattern),
    _x_width(other_mesh._x_width),
    _y_width(other_mesh._y_width),
    _z_width(other_mesh._z_width)
{
}

PatternedMesh::~PatternedMesh()
{
}

MooseMesh &
PatternedMesh::clone() const
{
  return *(new PatternedMesh(*this));
}

void
PatternedMesh::buildMesh()
{
  // Local pointers to simplify algorithm
  std::vector<ReplicatedMesh *> row_meshes;
  row_meshes.reserve(_pattern.size());
  // First row is the original mesh
  row_meshes.push_back(_original_mesh);
  // Copy the remaining raw pointers into the local vector
  for (const auto & row_mesh: _row_meshes)
    row_meshes.push_back(row_mesh.get());

  BoundaryID left = getBoundaryID(getParam<BoundaryName>("left_boundary"));
  BoundaryID right = getBoundaryID(getParam<BoundaryName>("right_boundary"));
  BoundaryID top = getBoundaryID(getParam<BoundaryName>("top_boundary"));
  BoundaryID bottom = getBoundaryID(getParam<BoundaryName>("bottom_boundary"));

  // Build each row mesh
  for (auto i = beginIndex(_pattern); i < _pattern.size(); ++i)
    for (auto j = beginIndex(_pattern[i]); j < _pattern[i].size(); ++j)
    {
      Real
        deltax = j * _x_width,
        deltay = i * _y_width;

      // If this is the first cell of the row initialize the row mesh
      if (j == 0)
      {
        row_meshes[i]->read(_files[_pattern[i][j]]);

        MeshTools::Modification::translate(*row_meshes[i], deltax, -deltay, 0);

        continue;
      }

      ReplicatedMesh & cell_mesh = *_meshes[_pattern[i][j]];

      // Move the mesh into the right spot.  -i because we are starting at the top
      MeshTools::Modification::translate(cell_mesh, deltax, -deltay, 0);

      row_meshes[i]->stitch_meshes(dynamic_cast<ReplicatedMesh &>(cell_mesh), right, left, TOLERANCE, /*clear_stitched_boundary_ids=*/true);

      // Undo the translation
      MeshTools::Modification::translate(cell_mesh, -deltax, deltay, 0);
    }

  // Now stitch together the rows
  // We're going to stitch them all to row 0 (which is the real mesh)
  for (auto i = beginIndex(_pattern, 1); i < _pattern.size(); i++)
    row_meshes[0]->stitch_meshes(*row_meshes[i], bottom, top, TOLERANCE, /*clear_stitched_boundary_ids=*/true);
}
<|endoftext|>


<commit_before>//
//  MultiLayerTileTexturizer.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 08/08/12.
//
//

#include "MultiLayerTileTexturizer.hpp"
#include "Context.hpp"
#include "LayerSet.hpp"
#include "TilesRenderParameters.hpp"
#include "Tile.hpp"
#include "TexturedMesh.hpp"

enum PetitionStatus {
  STATUS_PENDING,
  STATUS_DOWNLOADED,
  STATUS_CANCELED
};

class PetitionsMixer {
private:
  Tile*                  _tile;
  std::vector<Petition*> _petitions;
  const int              _petitionsCount;

  std::vector<PetitionStatus>    _status;
  std::vector<const ByteBuffer*> _buffers;

public:
  PetitionsMixer(Tile* tile,
                 std::vector<Petition*>& petitions) :
  _tile(tile),
  _petitions(petitions),
  _petitionsCount(petitions.size())
  {

    for (int i = 0; i < _petitionsCount; i++) {
      _status.push_back(STATUS_PENDING);
      _buffers.push_back(NULL);
    }
  }

  void checkCompletion() {
    bool completed   = true;
    bool anyCanceled = false;

    for (int i = 0; i < _petitionsCount; i++) {
      const int status = _status[i];
      if (status == STATUS_PENDING) {
        completed = false;
        break;
      }
      else if (status == STATUS_CANCELED) {
        anyCanceled = true;
      }
    }

    if (completed) {
      int __diego_at_work;
      if (anyCanceled) {
        printf("Completed with cancelation\n");
      }
      else {
        printf("Completed!!!!\n");
      }
      _tile->setTextureSolved(true);
    }
  }

  void checkIsPending(int position) {
    if (_status[position] != STATUS_PENDING) {
      printf("Logic error: Expected STATUS_PENDING at position #%d but found status: %d\n",
             position,
             _status[position]);
    }
  }

  void downloaded(int position,
                  const ByteBuffer* buffer) {
    checkIsPending(position);

    _status[position]  = STATUS_DOWNLOADED;
    _buffers[position] = buffer;

    checkCompletion();
  }

  void canceled(int position) {
    checkIsPending(position);

    _status[position] = STATUS_CANCELED;

    checkCompletion();
  }
};

class DownloadListener : public IDownloadListener {
private:
  PetitionsMixer* _mixer;
  const int       _position;

public:
  DownloadListener(PetitionsMixer* mixer,
                   int position) :
  _mixer(mixer),
  _position(position)
  {

  }

  void onDownload(const Response& response) {
    _mixer->downloaded(_position, response.getByteBuffer());
  }

  void onError(const Response& response) {
    _mixer->canceled(_position);
  }

  void onCancel(const URL& url) {
    _mixer->canceled(_position);
  }
};

void MultiLayerTileTexturizer::initialize(const InitializationContext* ic,
                                          const TilesRenderParameters* parameters) {
  _downloader = ic->getDownloader();
  _parameters = parameters;
}

void MultiLayerTileTexturizer::justCreatedTopTile(const RenderContext* rc,
                                                  Tile* tile) {

}

bool MultiLayerTileTexturizer::isReady(const RenderContext *rc) {
  return true;
}

Mesh* MultiLayerTileTexturizer::texturize(const RenderContext* rc,
                                          const TileRenderContext* trc,
                                          Tile* tile,
                                          Mesh* tessellatorMesh,
                                          Mesh* previousMesh) {

  //  TexturedMesh* result = getFinalTexturedMesh(tile, tessellatorMesh);

  const TileKey key = tile->getKey();

  PetitionsMixer* mixer = _mixers[key];
  if (mixer == NULL) {
    std::vector<Petition*> petitions = _layerSet->createTilePetitions(rc,
                                                                      tile,
                                                                      _parameters->_tileTextureWidth,
                                                                      _parameters->_tileTextureHeight);

    mixer = new PetitionsMixer(tile, petitions);
    _mixers[key] = mixer;

    for (int i = 0; i < petitions.size(); i++) {
      const Petition* petition = petitions[i];

      const URL url = URL(petition->getURL());
      const long priority = tile->getLevel();
      const bool deleteListener = true;

      _downloader->request(url,
                           priority,
                           new DownloadListener(mixer, i),
                           deleteListener);
    }
  }
  else {
    printf("****** mixer already created\n");
  }

//  tile->setTexturizerInProgress(true);

  Mesh* result = NULL;

//  if (previousMesh == NULL) {
//    const TextureMapping* textureMapping;
//
//    result = new TexturedMesh(tessellatorMesh, false,
//                              textureMapping, true);
//  }
//  else {
//    result = previousMesh;
//  }

  int ___XX;

  return result;
}

void MultiLayerTileTexturizer::tileToBeDeleted(Tile* tile,
                                               Mesh* mesh) {

}

bool MultiLayerTileTexturizer::tileMeetsRenderCriteria(Tile* tile) {
  return true;
}
<commit_msg>progress on new texturizer and downloader<commit_after>//
//  MultiLayerTileTexturizer.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 08/08/12.
//
//

#include "MultiLayerTileTexturizer.hpp"
#include "Context.hpp"
#include "LayerSet.hpp"
#include "TilesRenderParameters.hpp"
#include "Tile.hpp"
#include "TexturedMesh.hpp"

enum PetitionStatus {
  STATUS_PENDING,
  STATUS_DOWNLOADED,
  STATUS_CANCELED
};

class DownloadListener : public IDownloadListener {
private:
  PetitionsMixer* _mixer;
  const int       _position;

public:
  DownloadListener(PetitionsMixer* mixer,
                   int position) :
  _mixer(mixer),
  _position(position)
  {

  }

  void onDownload(const Response& response);

  void onError(const Response& response);

  void onCancel(const URL& url);

};

class PetitionsMixer {
private:
  Tile*                  _tile;
  std::vector<Petition*> _petitions;
  int                    _petitionsCount;

  std::vector<PetitionStatus>    _status;
  std::vector<const ByteBuffer*> _buffers;

  Mesh* _mesh;

public:
  PetitionsMixer(const RenderContext*         rc,
                 const LayerSet* const        layerSet,
                 const TilesRenderParameters* parameters,
                 IDownloader*                 downloader,
                 Tile* tile) :
  _tile(tile),
  _mesh(NULL)
  {

    for (int i = 0; i < _petitionsCount; i++) {
      _status.push_back(STATUS_PENDING);
      _buffers.push_back(NULL);
    }

    _petitions = layerSet->createTilePetitions(rc,
                                               tile,
                                               parameters->_tileTextureWidth,
                                               parameters->_tileTextureHeight);

    _petitionsCount = _petitions.size();

    for (int i = 0; i < _petitionsCount; i++) {
      const Petition* petition = _petitions[i];

      const long priority = tile->getLevel() * 1000000 + tile->getRow() * 1000 + tile->getColumn();

      downloader->request(URL(petition->getURL()),
                           priority,
                           new DownloadListener(this, i),
                           true);
    }

  }

  void checkCompletion() {
    bool completed   = true;
    bool anyCanceled = false;

    for (int i = 0; i < _petitionsCount; i++) {
      const int status = _status[i];
      if (status == STATUS_PENDING) {
        completed = false;
        break;
      }
      else if (status == STATUS_CANCELED) {
        anyCanceled = true;
      }
    }

    if (completed) {
      int __diego_at_work;
      if (anyCanceled) {
        printf("Completed with cancelation\n");
      }
      else {
        printf("Completed!!!!\n");
      }
      _tile->setTextureSolved(true);
    }
  }

  void checkIsPending(int position) {
    if (_status[position] != STATUS_PENDING) {
      printf("Logic error: Expected STATUS_PENDING at position #%d but found status: %d\n",
             position,
             _status[position]);
    }
  }

  void downloaded(int position,
                  const ByteBuffer* buffer) {
    checkIsPending(position);

    _status[position]  = STATUS_DOWNLOADED;
    _buffers[position] = buffer;

    checkCompletion();
  }

  void canceled(int position) {
    checkIsPending(position);

    _status[position] = STATUS_CANCELED;

    checkCompletion();
  }

  Mesh* createMesh() const {
//    LeveledTexturedMesh* mesh = new LeveledTexturedMesh();
//
//    return mesh;
    return NULL;
  }

  Mesh* getMesh() {
    if (_mesh == NULL) {
      _mesh = createMesh();
    }
    return _mesh;
  }
};

void DownloadListener::onDownload(const Response& response) {
  _mixer->downloaded(_position, response.getByteBuffer());
}

void DownloadListener::onError(const Response& response) {
  _mixer->canceled(_position);
}

void DownloadListener::onCancel(const URL& url) {
  _mixer->canceled(_position);
}

void MultiLayerTileTexturizer::initialize(const InitializationContext* ic,
                                          const TilesRenderParameters* parameters) {
  _downloader = ic->getDownloader();
  _parameters = parameters;
}

void MultiLayerTileTexturizer::justCreatedTopTile(const RenderContext* rc,
                                                  Tile* tile) {

}

bool MultiLayerTileTexturizer::isReady(const RenderContext *rc) {
  return true;
}

Mesh* MultiLayerTileTexturizer::texturize(const RenderContext* rc,
                                          const TileRenderContext* trc,
                                          Tile* tile,
                                          Mesh* tessellatorMesh,
                                          Mesh* previousMesh) {

  if (previousMesh != NULL) {
    return previousMesh;
  }

  const TileKey key = tile->getKey();
  PetitionsMixer* mixer = _mixers[key];
  if (mixer == NULL) {
    mixer = new PetitionsMixer(rc, _layerSet, _parameters, _downloader, tile);
    _mixers[key] = mixer;
  }

  int ___XX;

  return mixer->getMesh();
}

void MultiLayerTileTexturizer::tileToBeDeleted(Tile* tile,
                                               Mesh* mesh) {

}

bool MultiLayerTileTexturizer::tileMeetsRenderCriteria(Tile* tile) {
  return true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_posh/internal/roudi_environment/roudi_environment.hpp"
#include "iceoryx_posh/runtime/node.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"

#include "test.hpp"

using namespace ::testing;
using namespace iox::runtime;
using namespace iox::roudi;

namespace iox
{
namespace test
{
/// @brief Test goal: This test suit verifies class node

class PoshRuntimeNode_test : public Test
{
  public:
    PoshRuntimeNode_test()
    {
    }

    virtual ~PoshRuntimeNode_test()
    {
    }

    virtual void SetUp(){};

    virtual void TearDown(){};

    const ProcessName_t m_runtimeName{"App"};
    RouDiEnvironment m_roudiEnv{iox::RouDiConfig_t().setDefaults()};
    PoshRuntime* m_runtime{&iox::runtime::PoshRuntime::initRuntime(m_runtimeName)};
};

TEST_F(PoshRuntimeNode_test, ConstructorNodeIsSuccess)
{
    const NodeName_t nodeName{"Node"};

    Node node("Node");

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, ConstructorNodeEmptyNodeNameIsSuccess)
{
    const NodeName_t nodeName{""};

    Node node("");

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, VerifyMoveAssignmentOperatorAssignsCorrectName)
{
    const NodeName_t nodeName{"@!~*"};
    Node testNode(nodeName);
    Node node("Node");

    node = std::move(testNode);

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, SelfMoveAssignmentIsExcluded)
{
    const NodeName_t nodeName{"Node"};
    Node node1(nodeName);
    Node& node2 = node1;

    node1 = std::move(node2);

    EXPECT_THAT(node1.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, VerifyMoveConstructorAssignsCorrectNodeName)
{
    const NodeName_t nodeNewName{"Node"};

    Node node(nodeNewName);

    Node nodeTest(std::move(node));

    EXPECT_THAT(nodeTest.getNodeName(), Eq(nodeNewName));
}

} // namespace test
} // namespace iox
<commit_msg>iox-#496 fix review findings<commit_after>// Copyright (c) 2021 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_posh/internal/roudi_environment/roudi_environment.hpp"
#include "iceoryx_posh/runtime/node.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"

#include "test.hpp"

using namespace ::testing;
using namespace iox::runtime;
using namespace iox::roudi;

namespace iox
{
namespace test
{
/// @brief Test goal: This test suit verifies class node

class PoshRuntimeNode_test : public Test
{
  public:
    PoshRuntimeNode_test()
    {
    }

    virtual ~PoshRuntimeNode_test()
    {
    }

    virtual void SetUp(){};

    virtual void TearDown(){};

    const ProcessName_t m_runtimeName{"App"};
    RouDiEnvironment m_roudiEnv{iox::RouDiConfig_t().setDefaults()};
    PoshRuntime* m_runtime{&iox::runtime::PoshRuntime::initRuntime(m_runtimeName)};
};

TEST_F(PoshRuntimeNode_test, ConstructorNodeIsSuccess)
{
    const NodeName_t nodeName{"Node"};

    Node node("Node");

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, ConstructorNodeEmptyNodeNameIsSuccess)
{
    const NodeName_t nodeName{""};

    Node node("");

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, ConstructorNodeWithMaximalSizeNodeNameIsSuccess)
{
    const NodeName_t nodeName{"aaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccddddd"};

    Node node("aaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccddddd");

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, VerifyMoveAssignmentOperatorAssignsCorrectName)
{
    const NodeName_t nodeName{"@!~*"};
    Node testNode(nodeName);
    Node node("Node");

    node = std::move(testNode);

    EXPECT_THAT(node.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, SelfMoveAssignmentIsExcluded)
{
    const NodeName_t nodeName{"Node"};
    Node node1(nodeName);
    Node& node2 = node1;

    node1 = std::move(node2);

    EXPECT_THAT(node1.getNodeName(), Eq(nodeName));
}

TEST_F(PoshRuntimeNode_test, VerifyMoveConstructorAssignsCorrectNodeName)
{
    const NodeName_t nodeNewName{"Node"};

    Node node(nodeNewName);

    Node nodeTest(std::move(node));

    EXPECT_THAT(nodeTest.getNodeName(), Eq(nodeNewName));
}

} // namespace test
} // namespace iox
<|endoftext|>


<commit_before>#include "builtin/data.hpp"
#include "builtin/class.hpp"
#include "objectmemory.hpp"
#include "object_utils.hpp"

#include "gc/gc.hpp"

#include "capi/capi.hpp"

#include "ontology.hpp"

namespace rubinius {

  void Data::init(STATE) {
    GO(data).set(ontology::new_class(state, "Data", G(object)));
    G(data)->set_object_type(state, DataType);
  }

  Data* Data::create(STATE, void* data_ptr, Data::MarkFunctor mark, Data::FreeFunctor free) {
    Data* data;

    data = state->new_object<Data>(G(data));

    // Data is just a heap alias for the handle, so go ahead and create
    // the handle and populate it as an RData now.
    capi::Handle* handle = data->handle(state);

    assert(!handle && "can't already have a handle, it's brand new!");

    handle = state->shared().add_global_handle(state, data);

    // Don't call ->ref() on handle! We don't want the handle to keep the object
    // alive by default. The handle needs to have the lifetime of the object.

    RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rdata(0));

    rdata->data = data_ptr;
    rdata->dmark = mark;
    rdata->dfree = free;

    data->internal_ = rdata;
    data->freed_    = false;

    if(mark || free) {
      state->memory()->needs_finalization(data, (FinalizerFunction)&Data::finalize);
    }

    return data;
  }

  RDataShadow* Data::slow_rdata(STATE) {
    capi::Handle* handle = this->handle(state);

    assert(handle && handle->is_rdata() && "invalid initialized Data object");

    return reinterpret_cast<RDataShadow*>(handle->as_rdata(0));
  }

  void* Data::data(STATE) {
    return rdata(state)->data;
  }

  Data::FreeFunctor Data::free(STATE) {
    return rdata(state)->dfree;
  }

  Data::MarkFunctor Data::mark(STATE) {
    return rdata(state)->dmark;
  }

  void Data::finalize(STATE, Data* data) {
    if(data->freed_p()) {
      std::cerr << "Data::finalize called for already freed object" << std::endl;
      return;
    }

    // MRI only calls free if the data_ptr is not NULL.
    if(void* data_ptr = data->data(state)) {
      Data::FreeFunctor f = data->free(state);
      if(f) {
        // If the user specifies -1, then we call free. We check here rather
        // than when Data_Make_Struct is called because the user is allowed to
        // change dfree.
        if(reinterpret_cast<intptr_t>(f) == -1) {
          ::free(data_ptr);
        } else {
          f(data_ptr);
        }
      }
      data->set_freed();
    }
  }

  void Data::Info::mark(Object* t, ObjectMark& mark) {
    auto_mark(t, mark);

    Data* data = force_as<Data>(t);

    if(data->freed_p()) {
      std::cerr << "Data::Info::mark called for already freed object" << std::endl;
      return;
    }

    RDataShadow* rdata = data->rdata();

    if(rdata->dmark) {
      ObjectMark* cur = capi::current_mark();
      capi::set_current_mark(&mark);

      (*rdata->dmark)(rdata->data);

      capi::set_current_mark(cur);
    }
  }

}
<commit_msg>Silence finalizer warnings for now.<commit_after>#include "builtin/data.hpp"
#include "builtin/class.hpp"
#include "objectmemory.hpp"
#include "object_utils.hpp"

#include "gc/gc.hpp"

#include "capi/capi.hpp"

#include "ontology.hpp"

namespace rubinius {

  void Data::init(STATE) {
    GO(data).set(ontology::new_class(state, "Data", G(object)));
    G(data)->set_object_type(state, DataType);
  }

  Data* Data::create(STATE, void* data_ptr, Data::MarkFunctor mark, Data::FreeFunctor free) {
    Data* data;

    data = state->new_object<Data>(G(data));

    // Data is just a heap alias for the handle, so go ahead and create
    // the handle and populate it as an RData now.
    capi::Handle* handle = data->handle(state);

    assert(!handle && "can't already have a handle, it's brand new!");

    handle = state->shared().add_global_handle(state, data);

    // Don't call ->ref() on handle! We don't want the handle to keep the object
    // alive by default. The handle needs to have the lifetime of the object.

    RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rdata(0));

    rdata->data = data_ptr;
    rdata->dmark = mark;
    rdata->dfree = free;

    data->internal_ = rdata;
    data->freed_    = false;

    if(mark || free) {
      state->memory()->needs_finalization(data, (FinalizerFunction)&Data::finalize);
    }

    return data;
  }

  RDataShadow* Data::slow_rdata(STATE) {
    capi::Handle* handle = this->handle(state);

    assert(handle && handle->is_rdata() && "invalid initialized Data object");

    return reinterpret_cast<RDataShadow*>(handle->as_rdata(0));
  }

  void* Data::data(STATE) {
    return rdata(state)->data;
  }

  Data::FreeFunctor Data::free(STATE) {
    return rdata(state)->dfree;
  }

  Data::MarkFunctor Data::mark(STATE) {
    return rdata(state)->dmark;
  }

  void Data::finalize(STATE, Data* data) {
    if(data->freed_p()) {
      // TODO: Fix the issue of finalizer ordering.
      // std::cerr << "Data::finalize called for already freed object" << std::endl;
      return;
    }

    // MRI only calls free if the data_ptr is not NULL.
    if(void* data_ptr = data->data(state)) {
      Data::FreeFunctor f = data->free(state);
      if(f) {
        // If the user specifies -1, then we call free. We check here rather
        // than when Data_Make_Struct is called because the user is allowed to
        // change dfree.
        if(reinterpret_cast<intptr_t>(f) == -1) {
          ::free(data_ptr);
        } else {
          f(data_ptr);
        }
      }
      data->set_freed();
    }
  }

  void Data::Info::mark(Object* t, ObjectMark& mark) {
    auto_mark(t, mark);

    Data* data = force_as<Data>(t);

    if(data->freed_p()) {
      // TODO: Fix the issue of finalizer ordering.
      // std::cerr << "Data::Info::mark called for already freed object" << std::endl;
      return;
    }

    RDataShadow* rdata = data->rdata();

    if(rdata->dmark) {
      ObjectMark* cur = capi::current_mark();
      capi::set_current_mark(&mark);

      (*rdata->dmark)(rdata->data);

      capi::set_current_mark(cur);
    }
  }

}
<|endoftext|>