<commit_before>
#include "FrameDerivatives.hpp"
#include "Utilities.hpp"
#include <exception>
#include <cstdio>

using namespace std;

namespace YerFace {

FrameDerivatives::FrameDerivatives(int myClassificationBoundingBox, double myClassificationScaleFactor) {
	logger = new Logger("FrameDerivatives");
	if((myMutex = SDL_CreateMutex()) == NULL) {
		throw runtime_error("Failed creating mutex!");
	}
	if(myClassificationBoundingBox < 0) {
		throw invalid_argument("Classification Bounding Box is invalid.");
	}
	classificationBoundingBox = myClassificationBoundingBox;
	if(myClassificationScaleFactor < 0.0 || myClassificationScaleFactor > 1.0) {
		throw invalid_argument("Classification Scale Factor is invalid.");
	}
	workingFrameSet = false;
	completedFrameSet = false;
	workingPreviewFrameSet = false;
	completedPreviewFrameSet = false;
	workingFrameSizeSet = false;
	classificationScaleFactor = myClassificationScaleFactor;
	metrics = new Metrics("FrameDerivatives");
	logger->debug("FrameDerivatives constructed and ready to go!");
}

FrameDerivatives::~FrameDerivatives() {
	logger->debug("FrameDerivatives object destructing...");
	SDL_DestroyMutex(myMutex);
	delete metrics;
	delete logger;
}

void FrameDerivatives::setWorkingFrame(Mat newFrame) {
	YerFace_MutexLock(myMutex);
	metrics->startClock();
	workingFrame = newFrame.clone();

	Size frameSize = workingFrame.size();

	if(classificationBoundingBox > 0) {
		if(frameSize.width >= frameSize.height) {
			classificationScaleFactor = (double)classificationBoundingBox / (double)frameSize.width;
		} else {
			classificationScaleFactor = (double)classificationBoundingBox / (double)frameSize.height;
		}
	}

	resize(workingFrame, classificationFrame, Size(), classificationScaleFactor, classificationScaleFactor);

	static bool reportedScale = false;
	if(!reportedScale) {
		logger->debug("Scaled current frame <%dx%d> down to <%dx%d> for classification", frameSize.width, frameSize.height, classificationFrame.size().width, classificationFrame.size().height);
		reportedScale = true;
	}

	workingFrameSet = true;
	workingPreviewFrameSet = false;

	metrics->endClock();
	YerFace_MutexUnlock(myMutex);
}

Mat FrameDerivatives::getWorkingFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getWorkingFrame() called, but no working frame set");
	}
	Mat value = workingFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

void FrameDerivatives::advanceWorkingFrameToCompleted(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("advanceWorkingFrameToCompleted() called, but no working frame set");
	}
	completedFrame = workingFrame;
	completedFrameSet = true;
	workingFrameSet = false;
	if(workingPreviewFrameSet) {
		completedPreviewFrameSource = workingPreviewFrame;
	} else {
		completedPreviewFrameSource = completedFrame;
	}
	completedPreviewFrameSet = false;
	workingPreviewFrameSet = false;
	YerFace_MutexUnlock(myMutex);
}

Mat FrameDerivatives::getClassificationFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getClassificationFrame() called, but no working frame set");
	}
	Mat value = classificationFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

Mat FrameDerivatives::getWorkingPreviewFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getWorkingPreviewFrame() called, but no working frame set");
	}
	if(!workingPreviewFrameSet) {
		workingPreviewFrame = workingFrame.clone();
		workingPreviewFrameSet = true;
	}
	Mat value = workingPreviewFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

Mat FrameDerivatives::getCompletedPreviewFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!completedFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getCompletedPreviewFrame() called, but no completed frame set");
	}
	if(!completedPreviewFrameSet) {
		completedPreviewFrame = completedPreviewFrameSource.clone();
		completedPreviewFrameSet = true;
	}
	Mat value = completedPreviewFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

void FrameDerivatives::resetCompletedPreviewFrame(void) {
	YerFace_MutexLock(myMutex);
	completedPreviewFrameSet = false;
	YerFace_MutexUnlock(myMutex);
}

double FrameDerivatives::getClassificationScaleFactor(void) {
	YerFace_MutexLock(myMutex);
	double status = classificationScaleFactor;
	YerFace_MutexUnlock(myMutex);
	return status;
}

Size FrameDerivatives::getWorkingFrameSize(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSizeSet) {
		if(!workingFrameSet) {
			YerFace_MutexUnlock(myMutex);
			throw runtime_error("getWorkingFrameSize() called, but no working frame set and no cached size");
		}
		workingFrameSize = workingFrame.size();
		workingFrameSizeSet = true;
	}
	Size size = workingFrameSize;
	YerFace_MutexUnlock(myMutex);
	return size;
}

bool FrameDerivatives::getCompletedFrameSet(void) {
	YerFace_MutexLock(myMutex);<commit_msg>avoid race condition where working frame has been advanced to completed (and thus its size is no longer available) but its size has never been cached yet<commit_after>
#include "FrameDerivatives.hpp"
#include "Utilities.hpp"
#include <exception>
#include <cstdio>

using namespace std;

namespace YerFace {

FrameDerivatives::FrameDerivatives(int myClassificationBoundingBox, double myClassificationScaleFactor) {
	logger = new Logger("FrameDerivatives");
	if((myMutex = SDL_CreateMutex()) == NULL) {
		throw runtime_error("Failed creating mutex!");
	}
	if(myClassificationBoundingBox < 0) {
		throw invalid_argument("Classification Bounding Box is invalid.");
	}
	classificationBoundingBox = myClassificationBoundingBox;
	if(myClassificationScaleFactor < 0.0 || myClassificationScaleFactor > 1.0) {
		throw invalid_argument("Classification Scale Factor is invalid.");
	}
	workingFrameSet = false;
	completedFrameSet = false;
	workingPreviewFrameSet = false;
	completedPreviewFrameSet = false;
	workingFrameSizeSet = false;
	classificationScaleFactor = myClassificationScaleFactor;
	metrics = new Metrics("FrameDerivatives");
	logger->debug("FrameDerivatives constructed and ready to go!");
}

FrameDerivatives::~FrameDerivatives() {
	logger->debug("FrameDerivatives object destructing...");
	SDL_DestroyMutex(myMutex);
	delete metrics;
	delete logger;
}

void FrameDerivatives::setWorkingFrame(Mat newFrame) {
	YerFace_MutexLock(myMutex);
	metrics->startClock();
	workingFrame = newFrame.clone();

	Size frameSize = workingFrame.size();

	if(classificationBoundingBox > 0) {
		if(frameSize.width >= frameSize.height) {
			classificationScaleFactor = (double)classificationBoundingBox / (double)frameSize.width;
		} else {
			classificationScaleFactor = (double)classificationBoundingBox / (double)frameSize.height;
		}
	}

	resize(workingFrame, classificationFrame, Size(), classificationScaleFactor, classificationScaleFactor);

	static bool reportedScale = false;
	if(!reportedScale) {
		logger->debug("Scaled current frame <%dx%d> down to <%dx%d> for classification", frameSize.width, frameSize.height, classificationFrame.size().width, classificationFrame.size().height);
		reportedScale = true;
	}

	workingFrameSize = frameSize;
	workingFrameSizeSet = true;

	workingFrameSet = true;
	workingPreviewFrameSet = false;

	metrics->endClock();
	YerFace_MutexUnlock(myMutex);
}

Mat FrameDerivatives::getWorkingFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getWorkingFrame() called, but no working frame set");
	}
	Mat value = workingFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

void FrameDerivatives::advanceWorkingFrameToCompleted(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("advanceWorkingFrameToCompleted() called, but no working frame set");
	}
	completedFrame = workingFrame;
	completedFrameSet = true;
	workingFrameSet = false;
	if(workingPreviewFrameSet) {
		completedPreviewFrameSource = workingPreviewFrame;
	} else {
		completedPreviewFrameSource = completedFrame;
	}
	completedPreviewFrameSet = false;
	workingPreviewFrameSet = false;
	YerFace_MutexUnlock(myMutex);
}

Mat FrameDerivatives::getClassificationFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getClassificationFrame() called, but no working frame set");
	}
	Mat value = classificationFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

Mat FrameDerivatives::getWorkingPreviewFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getWorkingPreviewFrame() called, but no working frame set");
	}
	if(!workingPreviewFrameSet) {
		workingPreviewFrame = workingFrame.clone();
		workingPreviewFrameSet = true;
	}
	Mat value = workingPreviewFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

Mat FrameDerivatives::getCompletedPreviewFrame(void) {
	YerFace_MutexLock(myMutex);
	if(!completedFrameSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getCompletedPreviewFrame() called, but no completed frame set");
	}
	if(!completedPreviewFrameSet) {
		completedPreviewFrame = completedPreviewFrameSource.clone();
		completedPreviewFrameSet = true;
	}
	Mat value = completedPreviewFrame;
	YerFace_MutexUnlock(myMutex);
	return value;
}

void FrameDerivatives::resetCompletedPreviewFrame(void) {
	YerFace_MutexLock(myMutex);
	completedPreviewFrameSet = false;
	YerFace_MutexUnlock(myMutex);
}

double FrameDerivatives::getClassificationScaleFactor(void) {
	YerFace_MutexLock(myMutex);
	double status = classificationScaleFactor;
	YerFace_MutexUnlock(myMutex);
	return status;
}

Size FrameDerivatives::getWorkingFrameSize(void) {
	YerFace_MutexLock(myMutex);
	if(!workingFrameSizeSet) {
		YerFace_MutexUnlock(myMutex);
		throw runtime_error("getWorkingFrameSize() called, but no cached working frame size");
	}
	Size size = workingFrameSize;
	YerFace_MutexUnlock(myMutex);
	return size;
}

bool FrameDerivatives::getCompletedFrameSet(void) {
	YerFace_MutexLock(myMutex);
{'fraction_non_alphanumeric': 0.10038156736131494, 'fraction_numerical': 0.001174053419430584, 'mean_word_length': 7.358135731807032, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7286576', 'n_tokens_mistral': 3228, 'n_tokens_neox': 3185, 'n_words': 605}