<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: representation.C,v 1.52 2004/12/03 00:31:07 amoll Exp $
//

#include <BALL/VIEW/KERNEL/representation.h>
#include <BALL/VIEW/MODELS/modelProcessor.h>
#include <BALL/VIEW/MODELS/colorProcessor.h>
#include <BALL/VIEW/KERNEL/geometricObject.h>

#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/message.h>

#include <BALL/KERNEL/atom.h>

#include <BALL/SYSTEM/timer.h>

#include <qapplication.h>

// #define BALL_BENCHMARKING

namespace BALL
{
	namespace VIEW
	{
		Representation::Representation()
			throw()
				: PropertyManager(),
					drawing_mode_(DRAWING_MODE_SOLID),
					drawing_precision_(DRAWING_PRECISION_HIGH),
					surface_drawing_precision_(-1),
					model_type_(MODEL_UNKNOWN),
					coloring_method_(COLORING_UNKNOWN),
					transparency_(0),
					model_processor_(0),
					color_processor_(0),
					geometric_objects_(),
					composites_(),
					rebuild_(true),
					hidden_(false)
		{
		}

		Representation::Representation(const Representation& rp)
			throw()
				: PropertyManager(rp),
					drawing_mode_(rp.drawing_mode_),
					drawing_precision_(rp.drawing_precision_),
					surface_drawing_precision_(rp.drawing_precision_),
					model_type_(rp.model_type_),
					coloring_method_(rp.coloring_method_),
					transparency_(rp.transparency_),
					model_processor_(0),
					color_processor_(0),
					geometric_objects_(),
					composites_(rp.composites_),
					rebuild_(rp.rebuild_),
					hidden_(rp.hidden_)
		{
			if (rp.model_processor_ != 0)
			{
				model_processor_ = new ModelProcessor(*rp.model_processor_);
			}

			if (rp.color_processor_ != 0)
			{
				color_processor_ = new ColorProcessor(*rp.color_processor_);
			}

			GeometricObjectList::ConstIterator it = rp.geometric_objects_.begin();
			for (;it != rp.geometric_objects_.end(); it++)
			{
				GeometricObject* object = new GeometricObject(**it);
				geometric_objects_.push_back(object);
			}
		}

		Representation::Representation(ModelType model_type,
																	 DrawingPrecision drawing_precision,
																	 DrawingMode drawing_mode)
			throw()
				: PropertyManager(),
					drawing_mode_(drawing_mode),
					drawing_precision_(drawing_precision),
					surface_drawing_precision_(-1),
					model_type_(model_type),
					transparency_(0),
					model_processor_(0),
					color_processor_(0),
					geometric_objects_(),
					composites_(),
					rebuild_(true),
					hidden_(false)
		{
		}

		Representation::Representation(const HashSet<const Composite*>& composites,
																	 ModelProcessor* model_processor)
			throw()
			:	PropertyManager(),
				drawing_mode_(DRAWING_MODE_SOLID),
				drawing_precision_(DRAWING_PRECISION_HIGH),
				surface_drawing_precision_(-1),
				transparency_(0),
				model_processor_(model_processor),
				color_processor_(0),
				geometric_objects_(),
				composites_(composites),
				rebuild_(true),
				hidden_(false)
		{
		}

		const Representation& Representation::operator = (const Representation& representation)
			throw()
		{
			clear();

			drawing_mode_= representation.drawing_mode_;
			drawing_precision_= representation.drawing_precision_;
			model_type_ = representation.model_type_;
			coloring_method_ = representation.coloring_method_;
			transparency_ = representation.transparency_;
			surface_drawing_precision_ = representation.surface_drawing_precision_;

			PropertyManager::operator = (representation);

			if (representation.model_processor_ != 0)
			{
				model_processor_ = new ModelProcessor(*representation.model_processor_);
			}
			else
			{
				model_processor_ = 0;
			}

			if (representation.color_processor_ != 0)
			{
				color_processor_ = new ColorProcessor(*representation.color_processor_);
				color_processor_->setTransparency(transparency_);
			}
			else
			{
				color_processor_ = 0;
			}

			GeometricObjectList::ConstIterator it = representation.geometric_objects_.begin();
			for (;it != representation.geometric_objects_.end(); it++)
			{
				GeometricObject* object = new GeometricObject(**it);
				geometric_objects_.push_back(object);
			}

			composites_ = representation.composites_;

			rebuild_ = true;
			hidden_ = representation.hidden_;

			return *this;
		}

		Representation::~Representation()
			throw()
		{
			clear();
		}

		void Representation::clear()
			throw()
		{
			clearGeometricObjects();
			composites_.clear();

			if (model_processor_  != 0) delete model_processor_;
			if (color_processor_  != 0) delete color_processor_;
			model_processor_ 	= 0;
			color_processor_ 	= 0;

			drawing_mode_= DRAWING_MODE_SOLID;
			drawing_precision_= DRAWING_PRECISION_HIGH;
			model_type_ = MODEL_UNKNOWN;
			coloring_method_ = COLORING_UNKNOWN;
			transparency_ = 0;
			surface_drawing_precision_ = -1;

			rebuild_ = true;
			hidden_ = false;
		}

		void Representation::clearGeometricObjects()
			throw()
		{
			List<GeometricObject*>::Iterator it = geometric_objects_.begin();
			for (; it != geometric_objects_.end(); it++)
			{
				delete *it;
			}
			geometric_objects_.clear();

			if (model_processor_ != 0)
			{
				model_processor_->getGeometricObjects().clear();
			}
		}

		void Representation::dump(std::ostream& s, Size depth) const
			throw()
		{
			BALL_DUMP_STREAM_PREFIX(s);

			BALL_DUMP_DEPTH(s, depth);
			BALL_DUMP_HEADER(s, this, this);

			BALL_DUMP_DEPTH(s, depth);
			s << "drawing mode: " << drawing_mode_<< std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "drawing precision: " << drawing_precision_<< std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "model type : " << model_type_ << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "coloring type : " << coloring_method_ << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "number of primitives: " << geometric_objects_.size() << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "number of composites: " << composites_.size() << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "model processor: " << model_processor_ << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "hidden: " << hidden_ << std::endl;

			BALL_DUMP_DEPTH(s, depth);
			s << "PropertyManager: " << std::endl;
			PropertyManager::dump(s, depth + 1);

			BALL_DUMP_STREAM_SUFFIX(s);
		}

		bool Representation::isValid() const
			throw()
		{
			if (drawing_precision_  < 0 || drawing_precision_ > BALL_VIEW_MAXIMAL_DRAWING_PRECISION ||
					drawing_mode_ 			< 0 || drawing_mode_ > BALL_VIEW_MAXIMAL_DRAWING_MODE ||
					transparency_ 			> 255)
			{
				return false;
			}

#ifdef BALL_VIEW_DEBUG
			GeometricObjectList::ConstIterator it = geometric_objects_.begin();
			for (; it != geometric_objects_.end(); it++)
			{
				if (!(*it)->isValid()) return false;
			}
#endif

			if (model_processor_ != 0 && !model_processor_->isValid()) return false;

			return true;
		}

		void Representation::update(bool rebuild)
			throw()
		{
			rebuild_ = rebuild;

#ifdef BALL_QT_HAS_THREADS
			MainControl* mc = getMainControl();
			if (mc != 0)
			{
//   				MainControl* mc = dynamic_cast<MainControl*>(qApp->mainWidget());
				mc->getPrimitiveManager().update_(*this);
				return;
			}
#endif

			update_();
		}

		void Representation::update_()
			throw()
		{
			needs_update_ = false;

#ifdef BALL_BENCHMARKING
	Timer t;
	t.start();
#endif
			// if no ModelProcessor was given, there can only exist
			// handmade GeometricObjects, which dont need to be updated
			if (model_processor_ != 0 && rebuild_)
			{
				clearGeometricObjects();
				model_processor_->getGeometricObjects().clear();
				model_processor_->clearComposites();

				CompositeSet::Iterator it = composites_.begin();
				for (; it!= composites_.end(); it++)
				{
					(const_cast<Composite*>(*it))->apply(*model_processor_);
				}
				model_processor_->createGeometricObjects();
				geometric_objects_ = model_processor_->getGeometricObjects();
				model_build_time_ = PreciseTime::now();
			}

			if (color_processor_ != 0)
			{
				// make sure, that the atom grid is recomputed for meshes
				if (rebuild_) color_processor_->setComposites(&composites_);
				color_processor_->setTransparency(transparency_);
				color_processor_->setModelType(model_type_);
				geometric_objects_.apply(*color_processor_);
			}

#ifdef BALL_BENCHMARKING
			Log.info() << "Calculating Representation time: " << t.getCPUTime() << std::endl;
			t.stop();
#endif
		}

		String Representation::getModelName() const
			throw()
		{
			return VIEW::getModelName(model_type_);
		}

		String Representation::getColoringName() const
			throw()
		{
			return VIEW::getColoringName(coloring_method_);
		}

		String Representation::getProperties() const
			throw()
		{
			return String(composites_.size()) + " C, " + String(geometric_objects_.size()) + " P";
		}

		void Representation::setModelProcessor(ModelProcessor* processor)
			throw()
		{
			if (model_processor_ != 0)
			{
				delete model_processor_;
			}
			model_processor_ = processor;

			if (model_processor_ != 0)
			{
				model_processor_->setDrawingPrecision(drawing_precision_);
				model_processor_->setSurfaceDrawingPrecision(surface_drawing_precision_);
			}
		}

		void Representation::setColorProcessor(ColorProcessor* processor)
			throw()
		{
			if (color_processor_ != 0)
			{
				delete color_processor_;
			}
			color_processor_ = processor;

			if (color_processor_ != 0)
			{
				color_processor_->setComposites(&composites_);
				color_processor_->setTransparency(transparency_);
			}
		}

		void Representation::setDrawingPrecision(DrawingPrecision precision)
			throw()
		{
			drawing_precision_ = precision;
			if (model_processor_ != 0) model_processor_->setDrawingPrecision(drawing_precision_);
		}

		void Representation::setSurfaceDrawingPrecision(float precision)
			throw()
		{
			surface_drawing_precision_ = precision;
			if (model_processor_ != 0) model_processor_->setSurfaceDrawingPrecision(surface_drawing_precision_);
		}

		void Representation::setTransparency(Size value)
			throw()
		{
			transparency_ = value;
			if (transparency_ > 255)
			{
				transparency_ = 255;
			}

			if (color_processor_ != 0)
			{
				color_processor_->setTransparency(transparency_);
			}
		}

		bool Representation::needsUpdate() const
			throw()
		{
			if (getModelType() == MODEL_CLIPPING_PLANE)
			{
				return false;
			}

			if (needs_update_ ||
					getModelBuildTime() < Atom::getAttributesModificationTime())
			{
				return true;
			}

			CompositeSet::ConstIterator it = composites_.begin();
			for (;it != composites_.end(); it++)
			{
				if (getModelBuildTime() < (*it)->getModificationTime()) return true;
			}

			return false;
		}

		String Representation::toString() const
			throw()
		{
			String result;
			if (getModelType() == MODEL_CLIPPING_PLANE)
			{
				result+= "CP:";
				result+= String(getProperty("AX").getFloat()) + " ";
				result+= String(getProperty("BY").getFloat()) + " ";
				result+= String(getProperty("CZ").getFloat()) + " ";
				result+= String(getProperty("D").getFloat());
				return result;
			}

			result += String(model_type_) + " ";
			result += String(drawing_mode_) + " ";
			result += String(drawing_precision_) + " ";
			result += String(surface_drawing_precision_) + " ";
			result += String(coloring_method_) + " ";
			result += String(transparency_) + " ";

			if (composites_.size() == 0)
			{
				result += "[]";
				return result;
			}

			result += "[";

			const Composite& root = (*composites_.begin())->getRoot();
			HashMap<const Composite*, Position> composite_to_index;
			collectRecursive_(root, composite_to_index);

			CompositesConstIterator it = begin();
			for (; it != end(); it++)
			{
				if (composite_to_index.has(*it))
				{
					result += String(composite_to_index[*it]) + ",";
				}
			}

			result.trimRight(",");
			result += "]";

			if (color_processor_ != 0)
			{
				result += "|";
				String temp;
				result += color_processor_->getDefaultColor();
				result += "|";
			}

			if (isHidden())
			{
				result += "H";
			}

			return result;
		}

		void Representation::collectRecursive_(const Composite& c,
									HashMap<const Composite*, Position>& hashmap) const
			throw()
		{
			hashmap[&c] = hashmap.size();
			for (Position p = 0; p < c.getDegree(); p++)
			{
				collectRecursive_(*c.getChild(p), hashmap);
			}
		}

	} // namespace VIEW
} // namespace BALL
<commit_msg>no message<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: representation.C,v 1.53 2004/12/03 00:42:49 amoll Exp $
//

#include <BALL/VIEW/KERNEL/representation.h>
#include <BALL/VIEW/MODELS/modelProcessor.h>
#include <BALL/VIEW/MODELS/colorProcessor.h>
#include <BALL/VIEW/KERNEL/geometricObject.h>

#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/message.h>

#include <BALL/KERNEL/atom.h>

#include <BALL/SYSTEM/timer.h>

#include <qapplication.h>

// #define BALL_BENCHMARKING

namespace BALL
{
	namespace VIEW
	{
		Representation::Representation()
			throw()
				: PropertyManager(),
					drawing_mode_(DRAWING_MODE_SOLID),
					drawing_precision_(DRAWING_PRECISION_HIGH),
					surface_drawing_precision_(-1),
					model_type_(MODEL_UNKNOWN),
					coloring_method_(COLORING_UNKNOWN),
					transparency_(0),
					model_processor_(0),
					color_processor_(0),
					geometric_objects_(),
					composites_(),
					model_build_time_(),
					rebuild_(true),
					hidden_(false)
		{
		}

		Representation::Representation(const Representation& rp)
			throw()
				: PropertyManager(rp),
					drawing_mode_(rp.drawing_mode_),
					drawing_precision_(rp.drawing_precision_),
					surface_drawing_precision_(rp.drawing_precision_),
					model_type_(rp.model_type_),
					coloring_method_(rp.coloring_method_),
					transparency_(rp.transparency_),
					model_processor_(0),
					color_processor_(0),
					geometric_objects_(),
					composites_(rp.composites_),
					model_build_time_(),
					rebuild_(rp.rebuild_),
					hidden_(rp.hidden_)
		{
			if (rp.model_processor_ != 0)
			{
				model_processor_ = new ModelProcessor(*rp.model_processor_);
			}

			if (rp.color_processor_ != 0)
			{
				color_processor_ = new ColorProcessor(*rp.color_processor_);
			}

			GeometricObjectList::ConstIterator it = rp.geometric_objects_.begin();
			for (;it != rp.geometric_objects_.end(); it++)
			{
				GeometricObject* object = new GeometricObject(**it);
				geometric_objects_.push_back(object);
			}
		}

		Representation::Representation(ModelType model_type,
																	 DrawingPrecision drawing_precision,
																	 DrawingMode drawing_mode)
			throw()
				: PropertyManager(),
					drawing_mode_(drawing_mode),
					drawing_precision_(drawing_precision),
					surface_drawing_precision_(-1),
					model_type_(model_type),
					transparency_(0),
					model_processor_(0),
					color_processor_(0),
					geometric_objects_(),
					composites_(),
					model_build_time_(),
					rebuild_(true),
					hidden_(false)
		{
		}

		Representation::Representation(const HashSet<const Composite*>& composites,
																	 ModelProcessor* model_processor)
			throw()
			:	PropertyManager(),
				drawing_mode_(DRAWING_MODE_SOLID),
				drawing_precision_(DRAWING_PRECISION_HIGH),
				surface_drawing_precision_(-1),
				transparency_(0),
				model_processor_(model_processor),
				color_processor_(0),
				geometric_objects_(),
				composites_(composites),
				model_build_time_(),
				rebuild_(true),
				hidden_(false)
		{
		}

		const Representation& Representation::operator = (const Representation& representation)
			throw()
		{
			clear();

			drawing_mode_= representation.drawing_mode_;
			drawing_precision_= representation.drawing_precision_;
			model_type_ = representation.model_type_;
			coloring_method_ = representation.coloring_method_;
			transparency_ = representation.transparency_;
			surface_drawing_precision_ = representation.surface_drawing_precision_;

			PropertyManager::operator = (representation);

			if (representation.model_processor_ != 0)
			{
				model_processor_ = new ModelProcessor(*representation.model_processor_);
			}
			else
			{
				model_processor_ = 0;
			}

			if (representation.color_processor_ != 0)
			{
				color_processor_ = new ColorProcessor(*representation.color_processor_);
				color_processor_->setTransparency(transparency_);
			}
			else
			{
				color_processor_ = 0;
			}

			GeometricObjectList::ConstIterator it = representation.geometric_objects_.begin();
			for (;it != representation.geometric_objects_.end(); it++)
			{
				GeometricObject* object = new GeometricObject(**it);
				geometric_objects_.push_back(object);
			}

			composites_ = representation.composites_;

			rebuild_ = true;
			hidden_ = representation.hidden_;

			return *this;
		}

		Representation::~Representation()
			throw()
		{
			clear();
		}

		void Representation::clear()
			throw()
		{
			clearGeometricObjects();
			composites_.clear();

			if (model_processor_  != 0) delete model_processor_;
			if (color_processor_  != 0) delete color_processor_;
			model_processor_ 	= 0;
			color_processor_ 	= 0;

			drawing_mode_= DRAWING_MODE_SOLID;
			drawing_precision_= DRAWING_PRECISION_HIGH;
			model_type_ = MODEL_UNKNOWN;
			coloring_method_ = COLORING_UNKNOWN;
			transparency_ = 0;
			surface_drawing_precision_ = -1;

			rebuild_ = true;
			hidden_ = false;
		}

		void Representation::clearGeometricObjects()
			throw()
		{
			List<GeometricObject*>::Iterator it = geometric_objects_.begin();
			for (; it != geometric_objects_.end(); it++)
			{
				delete *it;
			}
			geometric_objects_.clear();

			if (model_processor_ != 0)
			{
				model_processor_->getGeometricObjects().clear();
			}
		}

		void Representation::dump(std::ostream& s, Size depth) const
			throw()
		{
			BALL_DUMP_STREAM_PREFIX(s);

			BALL_DUMP_DEPTH(s, depth);
			BALL_DUMP_HEADER(s, this, this);

			BALL_DUMP_DEPTH(s, depth);
			s << "drawing mode: " << drawing_mode_<< std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "drawing precision: " << drawing_precision_<< std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "model type : " << model_type_ << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "coloring type : " << coloring_method_ << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "number of primitives: " << geometric_objects_.size() << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "number of composites: " << composites_.size() << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "model processor: " << model_processor_ << std::endl;
			BALL_DUMP_DEPTH(s, depth);
			s << "hidden: " << hidden_ << std::endl;

			BALL_DUMP_DEPTH(s, depth);
			s << "PropertyManager: " << std::endl;
			PropertyManager::dump(s, depth + 1);

			BALL_DUMP_STREAM_SUFFIX(s);
		}

		bool Representation::isValid() const
			throw()
		{
			if (drawing_precision_  < 0 || drawing_precision_ > BALL_VIEW_MAXIMAL_DRAWING_PRECISION ||
					drawing_mode_ 			< 0 || drawing_mode_ > BALL_VIEW_MAXIMAL_DRAWING_MODE ||
					transparency_ 			> 255)
			{
				return false;
			}

#ifdef BALL_VIEW_DEBUG
			GeometricObjectList::ConstIterator it = geometric_objects_.begin();
			for (; it != geometric_objects_.end(); it++)
			{
				if (!(*it)->isValid()) return false;
			}
#endif

			if (model_processor_ != 0 && !model_processor_->isValid()) return false;

			return true;
		}

		void Representation::update(bool rebuild)
			throw()
		{
			rebuild_ = rebuild;

#ifdef BALL_QT_HAS_THREADS
			MainControl* mc = getMainControl();
			if (mc != 0)
			{
//   				MainControl* mc = dynamic_cast<MainControl*>(qApp->mainWidget());
				mc->getPrimitiveManager().update_(*this);
				return;
			}
#endif

			update_();
		}

		void Representation::update_()
			throw()
		{
			needs_update_ = false;

#ifdef BALL_BENCHMARKING
	Timer t;
	t.start();
#endif
			// if no ModelProcessor was given, there can only exist
			// handmade GeometricObjects, which dont need to be updated
			if (model_processor_ != 0 && rebuild_)
			{
				clearGeometricObjects();
				model_processor_->getGeometricObjects().clear();
				model_processor_->clearComposites();

				CompositeSet::Iterator it = composites_.begin();
				for (; it!= composites_.end(); it++)
				{
					(const_cast<Composite*>(*it))->apply(*model_processor_);
				}
				model_processor_->createGeometricObjects();
				geometric_objects_ = model_processor_->getGeometricObjects();
				model_build_time_ = PreciseTime::now();
			}

			if (color_processor_ != 0)
			{
				// make sure, that the atom grid is recomputed for meshes
				if (rebuild_) color_processor_->setComposites(&composites_);
				color_processor_->setTransparency(transparency_);
				color_processor_->setModelType(model_type_);
				geometric_objects_.apply(*color_processor_);
			}

#ifdef BALL_BENCHMARKING
			Log.info() << "Calculating Representation time: " << t.getCPUTime() << std::endl;
			t.stop();
#endif
		}

		String Representation::getModelName() const
			throw()
		{
			return VIEW::getModelName(model_type_);
		}

		String Representation::getColoringName() const
			throw()
		{
			return VIEW::getColoringName(coloring_method_);
		}

		String Representation::getProperties() const
			throw()
		{
			return String(composites_.size()) + " C, " + String(geometric_objects_.size()) + " P";
		}

		void Representation::setModelProcessor(ModelProcessor* processor)
			throw()
		{
			if (model_processor_ != 0)
			{
				delete model_processor_;
			}
			model_processor_ = processor;

			if (model_processor_ != 0)
			{
				model_processor_->setDrawingPrecision(drawing_precision_);
				model_processor_->setSurfaceDrawingPrecision(surface_drawing_precision_);
			}
		}

		void Representation::setColorProcessor(ColorProcessor* processor)
			throw()
		{
			if (color_processor_ != 0)
			{
				delete color_processor_;
			}
			color_processor_ = processor;

			if (color_processor_ != 0)
			{
				color_processor_->setComposites(&composites_);
				color_processor_->setTransparency(transparency_);
			}
		}

		void Representation::setDrawingPrecision(DrawingPrecision precision)
			throw()
		{
			drawing_precision_ = precision;
			if (model_processor_ != 0) model_processor_->setDrawingPrecision(drawing_precision_);
		}

		void Representation::setSurfaceDrawingPrecision(float precision)
			throw()
		{
			surface_drawing_precision_ = precision;
			if (model_processor_ != 0) model_processor_->setSurfaceDrawingPrecision(surface_drawing_precision_);
		}

		void Representation::setTransparency(Size value)
			throw()
		{
			transparency_ = value;
			if (transparency_ > 255)
			{
				transparency_ = 255;
			}

			if (color_processor_ != 0)
			{
				color_processor_->setTransparency(transparency_);
			}
		}

		bool Representation::needsUpdate() const
			throw()
		{
			if (getModelType() == MODEL_CLIPPING_PLANE)
			{
				return false;
			}

			if (needs_update_ ||
					getModelBuildTime() < Atom::getAttributesModificationTime())
			{
				return true;
			}

			CompositeSet::ConstIterator it = composites_.begin();
			for (;it != composites_.end(); it++)
			{
				if (getModelBuildTime() < (*it)->getModificationTime()) return true;
			}

			return false;
		}

		String Representation::toString() const
			throw()
		{
			String result;
			if (getModelType() == MODEL_CLIPPING_PLANE)
			{
				result+= "CP:";
				result+= String(getProperty("AX").getFloat()) + " ";
				result+= String(getProperty("BY").getFloat()) + " ";
				result+= String(getProperty("CZ").getFloat()) + " ";
				result+= String(getProperty("D").getFloat());
				return result;
			}

			result += String(model_type_) + " ";
			result += String(drawing_mode_) + " ";
			result += String(drawing_precision_) + " ";
			result += String(surface_drawing_precision_) + " ";
			result += String(coloring_method_) + " ";
			result += String(transparency_) + " ";

			if (composites_.size() == 0)
			{
				result += "[]";
				return result;
			}

			result += "[";

			const Composite& root = (*composites_.begin())->getRoot();
			HashMap<const Composite*, Position> composite_to_index;
			collectRecursive_(root, composite_to_index);

			CompositesConstIterator it = begin();
			for (; it != end(); it++)
			{
				if (composite_to_index.has(*it))
				{
					result += String(composite_to_index[*it]) + ",";
				}
			}

			result.trimRight(",");
			result += "]";

			if (color_processor_ != 0)
			{
				result += "|";
				String temp;
				result += color_processor_->getDefaultColor();
				result += "|";
			}

			if (isHidden())
			{
				result += "H";
			}

			return result;
		}

		void Representation::collectRecursive_(const Composite& c,
									HashMap<const Composite*, Position>& hashmap) const
			throw()
		{
			hashmap[&c] = hashmap.size();
			for (Position p = 0; p < c.getDegree(); p++)
			{
				collectRecursive_(*c.getChild(p), hashmap);
			}
		}

	} // namespace VIEW
} // namespace BALL
<|endoftext|>


<commit_before><commit_msg>More loplugin:simplifybool<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "pow.h"

#include "chainparams.h"
#include "core.h"
#include "main.h"
#include "uint256.h"

unsigned int static GetNextWorkRequired_V1(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // Only change once per interval
    if ((pindexLast->nHeight+1) % Params().Interval() != 0)
    {
        if (Params().AllowMinDifficultyBlocks())
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* 10 minutes
            // then allow mining of a min-difficulty block.
            if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + Params().TargetSpacing()*2)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % Params().Interval() != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Go back by what we want to be 14 days worth of blocks
    const CBlockIndex* pindexFirst = pindexLast;
    for (int i = 0; pindexFirst && i < Params().Interval()-1; i++)
        pindexFirst = pindexFirst->pprev;
    assert(pindexFirst);

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);
    if (nActualTimespan < Params().TargetTimespan()/4)
        nActualTimespan = Params().TargetTimespan()/4;
    if (nActualTimespan > Params().TargetTimespan()*4)
        nActualTimespan = Params().TargetTimespan()*4;

    // Retarget
    uint256 bnNew;
    uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    bnNew *= nActualTimespan;
    bnNew /= Params().TargetTimespan();

    if (bnNew > Params().ProofOfWorkLimit())
        bnNew = Params().ProofOfWorkLimit();

    /// debug print
    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("Params().TargetTimespan() = %d    nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

/* current difficulty formula, DarkGravity v3, written by Evan Duffield - evan@darkcoin.io */
unsigned int static DarkGravityWave3(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    const CBlockIndex *BlockLastSolved = pindexLast;
    const CBlockIndex *BlockReading = pindexLast;
    const CBlockHeader *BlockCreating = pblock;
    BlockCreating = BlockCreating;
    int64_t nActualTimespan = 0;
    int64_t LastBlockTime = 0;
    int64_t PastBlocksMin = 24;
    int64_t PastBlocksMax = 24;
    int64_t CountBlocks = 0;
    uint256 PastDifficultyAverage;
    uint256 PastDifficultyAveragePrev;

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) {
        return Params().ProofOfWorkLimit().GetCompact();
    }

    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
            CountBlocks++;

        if (CountBlocks <= PastBlocksMin) {
            if (CountBlocks == 1)
                PastDifficultyAverage.SetCompact(BlockReading->nBits);
            else { PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks)+(uint256().SetCompact(BlockReading->nBits))) / (CountBlocks+1); }
                PastDifficultyAveragePrev = PastDifficultyAverage;
        }

        if (LastBlockTime > 0) {
            int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime());
            nActualTimespan += Diff;
        }
        LastBlockTime = BlockReading->GetBlockTime();

        if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
            BlockReading = BlockReading->pprev;
    }

    uint256 bnNew(PastDifficultyAverage);

    int64_t nTargetTimespan = CountBlocks*Params().TargetSpacing();

    if (nActualTimespan < nTargetTimespan/3)
        nActualTimespan = nTargetTimespan/3;
    if (nActualTimespan > nTargetTimespan*3)
        nActualTimespan = nTargetTimespan*3;

    // Retarget
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;

    if (bnNew > Params().ProofOfWorkLimit()) {
        bnNew = Params().ProofOfWorkLimit();
    }

    return bnNew.GetCompact();
}

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
        if (pindexLast->nHeight+1 >= 3600) { return DarkGravityWave3(pindexLast, pblock); }

        return GetNextWorkRequired_V1(pindexLast, pblock);
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits)
{
    bool fNegative;
    bool fOverflow;
    uint256 bnTarget;
    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
        return error("CheckProofOfWork() : nBits below minimum work");

    // Check proof of work matches claimed amount
    if (hash > bnTarget)
        return error("CheckProofOfWork() : hash doesn't match nBits");

    return true;
}

//
// minimum amount of work that could possibly be required nTime after
// minimum work required was nBase
//
unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
{
    const uint256 &bnLimit = Params().ProofOfWorkLimit();
    // Testnet has min-difficulty blocks
    // after Params().TargetSpacing()*2 time between blocks:
    if (Params().AllowMinDifficultyBlocks() && nTime > Params().TargetSpacing()*2)
        return bnLimit.GetCompact();

    uint256 bnResult;
    bnResult.SetCompact(nBase);
    while (nTime > 0 && bnResult < bnLimit)
    {
        // Maximum 400% adjustment...
        bnResult *= 4;
        // ... in best-case exactly 4-times-normal target time
        nTime -= Params().TargetTimespan()*4;
    }
    if (bnResult > bnLimit)
        bnResult = bnLimit;
    return bnResult.GetCompact();
}
<commit_msg>No longer call ComputeMinWork() ConputeMinWork() should not be called anymore with the Dark Gravity Wave. The combination of a checkpoint that was too close to the current date and time and fast blocks from fast pools had caused a fork and numerous banned hosts, causing them to isolate themselves into small islands, each with their own chain.<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "pow.h"

#include "chainparams.h"
#include "core.h"
#include "main.h"
#include "uint256.h"

unsigned int static GetNextWorkRequired_V1(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // Only change once per interval
    if ((pindexLast->nHeight+1) % Params().Interval() != 0)
    {
        if (Params().AllowMinDifficultyBlocks())
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* 10 minutes
            // then allow mining of a min-difficulty block.
            if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + Params().TargetSpacing()*2)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % Params().Interval() != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Go back by what we want to be 14 days worth of blocks
    const CBlockIndex* pindexFirst = pindexLast;
    for (int i = 0; pindexFirst && i < Params().Interval()-1; i++)
        pindexFirst = pindexFirst->pprev;
    assert(pindexFirst);

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);
    if (nActualTimespan < Params().TargetTimespan()/4)
        nActualTimespan = Params().TargetTimespan()/4;
    if (nActualTimespan > Params().TargetTimespan()*4)
        nActualTimespan = Params().TargetTimespan()*4;

    // Retarget
    uint256 bnNew;
    uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    bnNew *= nActualTimespan;
    bnNew /= Params().TargetTimespan();

    if (bnNew > Params().ProofOfWorkLimit())
        bnNew = Params().ProofOfWorkLimit();

    /// debug print
    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("Params().TargetTimespan() = %d    nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

/* current difficulty formula, DarkGravity v3, written by Evan Duffield - evan@darkcoin.io */
unsigned int static DarkGravityWave3(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    const CBlockIndex *BlockLastSolved = pindexLast;
    const CBlockIndex *BlockReading = pindexLast;
    const CBlockHeader *BlockCreating = pblock;
    BlockCreating = BlockCreating;
    int64_t nActualTimespan = 0;
    int64_t LastBlockTime = 0;
    int64_t PastBlocksMin = 24;
    int64_t PastBlocksMax = 24;
    int64_t CountBlocks = 0;
    uint256 PastDifficultyAverage;
    uint256 PastDifficultyAveragePrev;

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) {
        return Params().ProofOfWorkLimit().GetCompact();
    }

    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
            CountBlocks++;

        if (CountBlocks <= PastBlocksMin) {
            if (CountBlocks == 1)
                PastDifficultyAverage.SetCompact(BlockReading->nBits);
            else { PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks)+(uint256().SetCompact(BlockReading->nBits))) / (CountBlocks+1); }
                PastDifficultyAveragePrev = PastDifficultyAverage;
        }

        if (LastBlockTime > 0) {
            int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime());
            nActualTimespan += Diff;
        }
        LastBlockTime = BlockReading->GetBlockTime();

        if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
            BlockReading = BlockReading->pprev;
    }

    uint256 bnNew(PastDifficultyAverage);

    int64_t nTargetTimespan = CountBlocks*Params().TargetSpacing();

    if (nActualTimespan < nTargetTimespan/3)
        nActualTimespan = nTargetTimespan/3;
    if (nActualTimespan > nTargetTimespan*3)
        nActualTimespan = nTargetTimespan*3;

    // Retarget
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;

    if (bnNew > Params().ProofOfWorkLimit()) {
        bnNew = Params().ProofOfWorkLimit();
    }

    return bnNew.GetCompact();
}

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
        if (pindexLast->nHeight+1 >= 3600) { return DarkGravityWave3(pindexLast, pblock); }

        return GetNextWorkRequired_V1(pindexLast, pblock);
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits)
{
    bool fNegative;
    bool fOverflow;
    uint256 bnTarget;
    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
        return error("CheckProofOfWork() : nBits below minimum work");

    // Check proof of work matches claimed amount
    if (hash > bnTarget)
        return error("CheckProofOfWork() : hash doesn't match nBits");

    return true;
}

#if 0
//
// minimum amount of work that could possibly be required nTime after
// minimum work required was nBase
//
unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
{
    const uint256 &bnLimit = Params().ProofOfWorkLimit();
    // Testnet has min-difficulty blocks
    // after Params().TargetSpacing()*2 time between blocks:
    if (Params().AllowMinDifficultyBlocks() && nTime > Params().TargetSpacing()*2)
        return bnLimit.GetCompact();

    uint256 bnResult;
    bnResult.SetCompact(nBase);
    while (nTime > 0 && bnResult < bnLimit)
    {
        // Maximum 400% adjustment...
        bnResult *= 4;
        // ... in best-case exactly 4-times-normal target time
        nTime -= Params().TargetTimespan()*4;
    }
    if (bnResult > bnLimit)
        bnResult = bnLimit;
    return bnResult.GetCompact();
}

#else

// DarkGravityWave doesn't use ComputeMinWork, but we do basic
// check here to see that at least we meet the minimum nBits
//
unsigned int ComputeMinWork(unsigned int, int64_t)
{
    const uint256 &bnLimit = Params().ProofOfWorkLimit();
    return bnLimit.GetCompact();
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#ifndef _Stroika_Foundation_Memory_SmallStackBuffer_inl_
#define _Stroika_Foundation_Memory_SmallStackBuffer_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include <algorithm>
#include <cstring>
#include <type_traits>

#include "../Debug/Assertions.h"
#include "../Execution/Throw.h"
#include "Common.h"

namespace Stroika::Foundation::Memory {

    /*
     ********************************************************************************
     ************************* SmallStackBuffer<T, BUF_SIZE> ************************
     ********************************************************************************
     */
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer ()
        : fLiveData_{BufferAsT_ ()}
    {
#if qDebug
        (void)::memcpy (fGuard1_, kGuard1_, sizeof (kGuard1_));
        (void)::memcpy (fGuard2_, kGuard2_, sizeof (kGuard2_));
#endif
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (size_t nElements)
        : SmallStackBuffer{}
    {
        resize (nElements);
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (UninitializedConstructorFlag, size_t nElements)
        : SmallStackBuffer{}
    {
        static_assert (is_trivially_default_constructible_v<T>);
        resize_uninitialized (nElements);
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    template <typename ITERATOR_OF_T, enable_if_t<Configuration::is_iterator_v<ITERATOR_OF_T>, char>*>
    SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (ITERATOR_OF_T start, ITERATOR_OF_T end)
        : SmallStackBuffer{}
    {
        auto sz = static_cast<size_t> (distance (start, end));
        ReserveAtLeast (sz);
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
        Configuration::uninitialized_copy_MSFT_BWA (start, end, this->begin ());
#else
        uninitialized_copy (start, end, this->begin ());
#endif
        fSize_ = sz;
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    template <size_t FROM_BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (const SmallStackBuffer<T, FROM_BUF_SIZE>& from)
        : SmallStackBuffer{from.begin (), from.end ()}
    {
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (const SmallStackBuffer& from)
        : SmallStackBuffer{from.begin (), from.end ()}
    {
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::~SmallStackBuffer ()
    {
        Invariant ();
        DestroyElts_ (this->begin (), this->end ());
        if (fLiveData_ != BufferAsT_ ())
            [[UNLIKELY_ATTR]] {
            // we must have used the heap...
            Deallocate_ (LiveDataAsAllocatedBytes_ ());
        }
    }
    template <typename T, size_t BUF_SIZE>
    template <size_t FROM_BUF_SIZE>
    SmallStackBuffer<T, BUF_SIZE>& SmallStackBuffer<T, BUF_SIZE>::operator= (const SmallStackBuffer<T, FROM_BUF_SIZE>& rhs)
    {
        Invariant ();
        Assert (this != &rhs); // because if same address should be same type so operator=(const SmallStackBuffer&) should be called
        // @todo this simple implementation could be more efficient
        DestroyElts_ (this->begin (), this->end ());
        fSize_ = 0;
        ReserveAtLeast (rhs.size ());
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
        Configuration::uninitialized_copy_MSFT_BWA (rhs.begin (), rhs.end (), this->begin ());
#else
        uninitialized_copy (rhs.begin (), rhs.end (), this->begin ());
#endif
        Invariant ();
        return *this;
    }
    template <typename T, size_t BUF_SIZE>
    SmallStackBuffer<T, BUF_SIZE>& SmallStackBuffer<T, BUF_SIZE>::operator= (const SmallStackBuffer& rhs)
    {
        Invariant ();
        if (this != &rhs) {
            // @todo this simple implementation could be more efficient
            DestroyElts_ (this->begin (), this->end ());
            fSize_ = 0;
            ReserveAtLeast (rhs.size ());
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
            Configuration::uninitialized_copy_MSFT_BWA (rhs.begin (), rhs.end (), this->begin ());
#else
            uninitialized_copy (rhs.begin (), rhs.end (), this->begin ());
#endif
            fSize_ = rhs.size ();
            Invariant ();
        }
        return *this;
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>& SmallStackBuffer<T, BUF_SIZE>::operator= (SmallStackBuffer&& rhs)
    {
        Invariant ();
        // @todo this simple implementation could be more efficient
        operator= (rhs); // call copy assign for now
        return *this;
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::GrowToSize (size_t nElements)
    {
        if (nElements > size ()) {
            resize (nElements);
        }
        Ensure (size () >= nElements);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::GrowToSize_uninitialized (size_t nElements)
    {
        static_assert (is_trivially_default_constructible_v<T>);
        if (nElements > size ()) {
            resize_uninitialized (nElements);
        }
        Ensure (size () >= nElements);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::resize (size_t nElements)
    {
        if (nElements > fSize_) {
            // Growing
            if (nElements > capacity ()) {
                /*
                 *   If we REALLY must grow, the double in size so unlikely we'll have to grow/malloc/copy again.
                 */
                reserve (max (nElements, capacity () * 2));
            }
            Assert (this->begin () + fSize_ == this->end ()); // docs/clarity
            auto newEnd = this->begin () + nElements;
            Assert (this->end () < newEnd);
            // uninitialized_fill() guarantees filling all or none - if an exception doing some, it undoes the ones it did (so setting fsize after safe)
            uninitialized_fill (this->end (), newEnd, T{});
            fSize_ = nElements;
            Assert (this->end () == newEnd);
        }
        else if (nElements < fSize_) {
            // Shrinking
            DestroyElts_ (this->begin () + nElements, this->end ());
            fSize_ = nElements;
        }
        Assert (fSize_ == nElements);
        Ensure (size () <= capacity ());
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::resize_uninitialized (size_t nElements)
    {
        static_assert (is_trivially_default_constructible_v<T>);
        if (nElements > fSize_) {
            // Growing
            if (nElements > capacity ())
                [[UNLIKELY_ATTR]] {
                /*
                 *   If we REALLY must grow, the double in size so unlikely we'll have to grow/malloc/copy again.
                 */
                reserve (max (nElements, capacity () * 2));
            }
            fSize_ = nElements;
        }
        else if (nElements < fSize_) {
            // Shrinking
            DestroyElts_ (this->begin () + nElements, this->end ());
            fSize_ = nElements;
        }
        Assert (fSize_ == nElements);
        Ensure (size () <= capacity ());
    }
    template <typename T, size_t BUF_SIZE>
    void SmallStackBuffer<T, BUF_SIZE>::reserve_ (size_t nElements)
    {
        Assert (nElements >= size ());
        Invariant ();
        size_t oldEltCount = capacity ();
        if (nElements != oldEltCount) {
            bool oldInPlaceBuffer = oldEltCount <= BUF_SIZE;
            bool newInPlaceBuffer = nElements <= BUF_SIZE;
            // Only if we changed if using inplace buffer, or if was and is using ramBuffer, and eltCount changed do we need to do anything
            if (oldInPlaceBuffer != newInPlaceBuffer or (not newInPlaceBuffer)) {
                bool  memoryAllocationNeeded = not newInPlaceBuffer;
                byte* newPtr                 = memoryAllocationNeeded ? Allocate_ (SizeInBytes_ (nElements)) : std::begin (fInlinePreallocatedBuffer_);

                // Initialize new memory from old
                Assert (this->begin () != reinterpret_cast<T*> (newPtr));
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
                Configuration::uninitialized_copy_MSFT_BWA (this->begin (), this->end (), reinterpret_cast<T*> (newPtr));
#else
                uninitialized_copy (this->begin (), this->end (), reinterpret_cast<T*> (newPtr));
#endif

                // destroy objects in old memory
                DestroyElts_ (this->begin (), this->end ());

                // free old memory if needed
                if (not oldInPlaceBuffer) {
                    Assert (fLiveData_ != BufferAsT_ ());
                    Deallocate_ (LiveDataAsAllocatedBytes_ ());
                }

                fLiveData_ = reinterpret_cast<T*> (newPtr);
                if (not newInPlaceBuffer) {
                    fCapacityOfFreeStoreAllocation_ = nElements;
                }
            }
        }
        Ensure ((nElements <= BUF_SIZE && capacity () == BUF_SIZE) or (nElements > BUF_SIZE and nElements == capacity ()));
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::iterator SmallStackBuffer<T, BUF_SIZE>::begin ()
    {
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::iterator SmallStackBuffer<T, BUF_SIZE>::end ()
    {
        return fLiveData_ + fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::const_iterator SmallStackBuffer<T, BUF_SIZE>::begin () const
    {
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::const_iterator SmallStackBuffer<T, BUF_SIZE>::end () const
    {
        return fLiveData_ + fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline size_t SmallStackBuffer<T, BUF_SIZE>::capacity () const
    {
        return (fLiveData_ == BufferAsT_ ()) ? BUF_SIZE : fCapacityOfFreeStoreAllocation_; // @see class Design Note
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::reserve (size_t newCapacity)
    {
        Require (newCapacity >= size ());
        reserve_ (newCapacity);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::ReserveAtLeast (size_t newCapacity)
    {
        if (newCapacity > capacity ()) {
            reserve_ (newCapacity);
        }
    }
    template <typename T, size_t BUF_SIZE>
    inline size_t SmallStackBuffer<T, BUF_SIZE>::GetSize () const
    {
        Ensure (fSize_ <= capacity ());
        return fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline size_t SmallStackBuffer<T, BUF_SIZE>::size () const
    {
        Ensure (fSize_ <= capacity ());
        return fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::reference SmallStackBuffer<T, BUF_SIZE>::at (size_t i)
    {
        Require (i < fSize_);
        return *(fLiveData_ + i);
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::const_reference SmallStackBuffer<T, BUF_SIZE>::at (size_t i) const
    {
        Require (i < fSize_);
        return *(fLiveData_ + i);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::push_back (Configuration::ArgByValueType<T> e)
    {
        size_t s = size ();
        if (s < capacity ()) {
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
            Configuration::uninitialized_copy_MSFT_BWA (&e, &e + 1, this->end ());
#else
            uninitialized_copy (&e, &e + 1, this->end ());
#endif
            this->fSize_++;
        }
        else {
            if constexpr (is_trivially_default_constructible_v<T>) {
                resize_uninitialized (s + 1);
            }
            else {
                resize (s + 1);
            }
            fLiveData_[s] = e;
        }
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::operator T* ()
    {
        AssertNotNull (fLiveData_);
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::operator const T* () const
    {
        AssertNotNull (fLiveData_);
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::Invariant () const
    {
#if qDebug
        Invariant_ ();
#endif
    }
#if qDebug
    template <typename T, size_t BUF_SIZE>
    void SmallStackBuffer<T, BUF_SIZE>::Invariant_ () const
    {
        Assert (capacity () >= size ());
        ValidateGuards_ ();
    }
    template <typename T, size_t BUF_SIZE>
    void SmallStackBuffer<T, BUF_SIZE>::ValidateGuards_ () const
    {
        Assert (::memcmp (kGuard1_, fGuard1_, sizeof (kGuard1_)) == 0);
        Assert (::memcmp (kGuard2_, fGuard2_, sizeof (kGuard2_)) == 0);
    }
#endif
    template <typename T, size_t BUF_SIZE>
    inline T* SmallStackBuffer<T, BUF_SIZE>::BufferAsT_ () noexcept
    {
        return reinterpret_cast<T*> (&fInlinePreallocatedBuffer_[0]);
    }
    template <typename T, size_t BUF_SIZE>
    inline const T* SmallStackBuffer<T, BUF_SIZE>::BufferAsT_ () const noexcept
    {
        return reinterpret_cast<const T*> (&fInlinePreallocatedBuffer_[0]);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::DestroyElts_ (T* start, T* end) noexcept
    {
        for (auto i = start; i != end; ++i) {
            i->~T ();
        }
    }
    template <typename T, size_t BUF_SIZE>
    inline byte* SmallStackBuffer<T, BUF_SIZE>::LiveDataAsAllocatedBytes_ ()
    {
        Require (fLiveData_ != BufferAsT_ ());
        return reinterpret_cast<byte*> (fLiveData_);
    }
    template <typename T, size_t BUF_SIZE>
    inline byte* SmallStackBuffer<T, BUF_SIZE>::Allocate_ (size_t bytes)
    {
        void* p = ::malloc (bytes);
        Execution::ThrowIfNull (p);
        return reinterpret_cast<byte*> (p);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::Deallocate_ (byte* bytes)
    {
        if (bytes != nullptr) {
            ::free (bytes);
        }
    }

}

#endif /*_Stroika_Foundation_Memory_SmallStackBuffer_inl_*/
<commit_msg>cosmetic<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#ifndef _Stroika_Foundation_Memory_SmallStackBuffer_inl_
#define _Stroika_Foundation_Memory_SmallStackBuffer_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include <algorithm>
#include <cstring>
#include <type_traits>

#include "../Debug/Assertions.h"
#include "../Execution/Throw.h"
#include "Common.h"

namespace Stroika::Foundation::Memory {

    /*
     ********************************************************************************
     ************************* SmallStackBuffer<T, BUF_SIZE> ************************
     ********************************************************************************
     */
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer ()
        : fLiveData_{BufferAsT_ ()}
    {
#if qDebug
        (void)::memcpy (fGuard1_, kGuard1_, sizeof (kGuard1_));
        (void)::memcpy (fGuard2_, kGuard2_, sizeof (kGuard2_));
#endif
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (size_t nElements)
        : SmallStackBuffer{}
    {
        resize (nElements);
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (UninitializedConstructorFlag, size_t nElements)
        : SmallStackBuffer{}
    {
        static_assert (is_trivially_default_constructible_v<T>);
        resize_uninitialized (nElements);
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    template <typename ITERATOR_OF_T, enable_if_t<Configuration::is_iterator_v<ITERATOR_OF_T>, char>*>
    SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (ITERATOR_OF_T start, ITERATOR_OF_T end)
        : SmallStackBuffer{}
    {
        auto sz = static_cast<size_t> (distance (start, end));
        ReserveAtLeast (sz);    // reserve not resize() so we can do uninitialized_copy (avoid constructing empty objects to be assigned over)
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
        Configuration::uninitialized_copy_MSFT_BWA (start, end, this->begin ());
#else
        uninitialized_copy (start, end, this->begin ());
#endif
        fSize_ = sz;
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    template <size_t FROM_BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (const SmallStackBuffer<T, FROM_BUF_SIZE>& from)
        : SmallStackBuffer{from.begin (), from.end ()}
    {
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::SmallStackBuffer (const SmallStackBuffer& from)
        : SmallStackBuffer{from.begin (), from.end ()}
    {
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::~SmallStackBuffer ()
    {
        Invariant ();
        DestroyElts_ (this->begin (), this->end ());
        if (fLiveData_ != BufferAsT_ ())
            [[UNLIKELY_ATTR]] {
            // we must have used the heap...
            Deallocate_ (LiveDataAsAllocatedBytes_ ());
        }
    }
    template <typename T, size_t BUF_SIZE>
    template <size_t FROM_BUF_SIZE>
    SmallStackBuffer<T, BUF_SIZE>& SmallStackBuffer<T, BUF_SIZE>::operator= (const SmallStackBuffer<T, FROM_BUF_SIZE>& rhs)
    {
        Invariant ();
        Assert (this != &rhs); // because if same address should be same type so operator=(const SmallStackBuffer&) should be called
        // @todo this simple implementation could be more efficient
        DestroyElts_ (this->begin (), this->end ());
        fSize_ = 0;
        ReserveAtLeast (rhs.size ());
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
        Configuration::uninitialized_copy_MSFT_BWA (rhs.begin (), rhs.end (), this->begin ());
#else
        uninitialized_copy (rhs.begin (), rhs.end (), this->begin ());
#endif
        Invariant ();
        return *this;
    }
    template <typename T, size_t BUF_SIZE>
    SmallStackBuffer<T, BUF_SIZE>& SmallStackBuffer<T, BUF_SIZE>::operator= (const SmallStackBuffer& rhs)
    {
        Invariant ();
        if (this != &rhs) {
            // @todo this simple implementation could be more efficient
            DestroyElts_ (this->begin (), this->end ());
            fSize_ = 0;
            ReserveAtLeast (rhs.size ());
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
            Configuration::uninitialized_copy_MSFT_BWA (rhs.begin (), rhs.end (), this->begin ());
#else
            uninitialized_copy (rhs.begin (), rhs.end (), this->begin ());
#endif
            fSize_ = rhs.size ();
            Invariant ();
        }
        return *this;
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>& SmallStackBuffer<T, BUF_SIZE>::operator= (SmallStackBuffer&& rhs)
    {
        Invariant ();
        // @todo this simple implementation could be more efficient
        operator= (rhs); // call copy assign for now
        return *this;
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::GrowToSize (size_t nElements)
    {
        if (nElements > size ()) {
            resize (nElements);
        }
        Ensure (size () >= nElements);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::GrowToSize_uninitialized (size_t nElements)
    {
        static_assert (is_trivially_default_constructible_v<T>);
        if (nElements > size ()) {
            resize_uninitialized (nElements);
        }
        Ensure (size () >= nElements);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::resize (size_t nElements)
    {
        if (nElements > fSize_) {
            // Growing
            if (nElements > capacity ()) {
                /*
                 *   If we REALLY must grow, the double in size so unlikely we'll have to grow/malloc/copy again.
                 */
                reserve (max (nElements, capacity () * 2));
            }
            Assert (this->begin () + fSize_ == this->end ()); // docs/clarity
            auto newEnd = this->begin () + nElements;
            Assert (this->end () < newEnd);
            // uninitialized_fill() guarantees filling all or none - if an exception doing some, it undoes the ones it did (so setting fsize after safe)
            uninitialized_fill (this->end (), newEnd, T{});
            fSize_ = nElements;
            Assert (this->end () == newEnd);
        }
        else if (nElements < fSize_) {
            // Shrinking
            DestroyElts_ (this->begin () + nElements, this->end ());
            fSize_ = nElements;
        }
        Assert (fSize_ == nElements);
        Ensure (size () <= capacity ());
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::resize_uninitialized (size_t nElements)
    {
        static_assert (is_trivially_default_constructible_v<T>);
        if (nElements > fSize_) {
            // Growing
            if (nElements > capacity ())
                [[UNLIKELY_ATTR]] {
                /*
                 *   If we REALLY must grow, the double in size so unlikely we'll have to grow/malloc/copy again.
                 */
                reserve (max (nElements, capacity () * 2));
            }
            fSize_ = nElements;
        }
        else if (nElements < fSize_) {
            // Shrinking
            DestroyElts_ (this->begin () + nElements, this->end ());
            fSize_ = nElements;
        }
        Assert (fSize_ == nElements);
        Ensure (size () <= capacity ());
    }
    template <typename T, size_t BUF_SIZE>
    void SmallStackBuffer<T, BUF_SIZE>::reserve_ (size_t nElements)
    {
        Assert (nElements >= size ());
        Invariant ();
        size_t oldEltCount = capacity ();
        if (nElements != oldEltCount) {
            bool oldInPlaceBuffer = oldEltCount <= BUF_SIZE;
            bool newInPlaceBuffer = nElements <= BUF_SIZE;
            // Only if we changed if using inplace buffer, or if was and is using ramBuffer, and eltCount changed do we need to do anything
            if (oldInPlaceBuffer != newInPlaceBuffer or (not newInPlaceBuffer)) {
                bool  memoryAllocationNeeded = not newInPlaceBuffer;
                byte* newPtr                 = memoryAllocationNeeded ? Allocate_ (SizeInBytes_ (nElements)) : std::begin (fInlinePreallocatedBuffer_);

                // Initialize new memory from old
                Assert (this->begin () != reinterpret_cast<T*> (newPtr));
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
                Configuration::uninitialized_copy_MSFT_BWA (this->begin (), this->end (), reinterpret_cast<T*> (newPtr));
#else
                uninitialized_copy (this->begin (), this->end (), reinterpret_cast<T*> (newPtr));
#endif

                // destroy objects in old memory
                DestroyElts_ (this->begin (), this->end ());

                // free old memory if needed
                if (not oldInPlaceBuffer) {
                    Assert (fLiveData_ != BufferAsT_ ());
                    Deallocate_ (LiveDataAsAllocatedBytes_ ());
                }

                fLiveData_ = reinterpret_cast<T*> (newPtr);
                if (not newInPlaceBuffer) {
                    fCapacityOfFreeStoreAllocation_ = nElements;
                }
            }
        }
        Ensure ((nElements <= BUF_SIZE && capacity () == BUF_SIZE) or (nElements > BUF_SIZE and nElements == capacity ()));
        Invariant ();
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::iterator SmallStackBuffer<T, BUF_SIZE>::begin ()
    {
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::iterator SmallStackBuffer<T, BUF_SIZE>::end ()
    {
        return fLiveData_ + fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::const_iterator SmallStackBuffer<T, BUF_SIZE>::begin () const
    {
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::const_iterator SmallStackBuffer<T, BUF_SIZE>::end () const
    {
        return fLiveData_ + fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline size_t SmallStackBuffer<T, BUF_SIZE>::capacity () const
    {
        return (fLiveData_ == BufferAsT_ ()) ? BUF_SIZE : fCapacityOfFreeStoreAllocation_; // @see class Design Note
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::reserve (size_t newCapacity)
    {
        Require (newCapacity >= size ());
        reserve_ (newCapacity);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::ReserveAtLeast (size_t newCapacity)
    {
        if (newCapacity > capacity ()) {
            reserve_ (newCapacity);
        }
    }
    template <typename T, size_t BUF_SIZE>
    inline size_t SmallStackBuffer<T, BUF_SIZE>::GetSize () const
    {
        Ensure (fSize_ <= capacity ());
        return fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline size_t SmallStackBuffer<T, BUF_SIZE>::size () const
    {
        Ensure (fSize_ <= capacity ());
        return fSize_;
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::reference SmallStackBuffer<T, BUF_SIZE>::at (size_t i)
    {
        Require (i < fSize_);
        return *(fLiveData_ + i);
    }
    template <typename T, size_t BUF_SIZE>
    inline typename SmallStackBuffer<T, BUF_SIZE>::const_reference SmallStackBuffer<T, BUF_SIZE>::at (size_t i) const
    {
        Require (i < fSize_);
        return *(fLiveData_ + i);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::push_back (Configuration::ArgByValueType<T> e)
    {
        size_t s = size ();
        if (s < capacity ()) {
#if qCompilerAndStdLib_uninitialized_copy_n_Warning_Buggy
            Configuration::uninitialized_copy_MSFT_BWA (&e, &e + 1, this->end ());
#else
            uninitialized_copy (&e, &e + 1, this->end ());
#endif
            this->fSize_++;
        }
        else {
            if constexpr (is_trivially_default_constructible_v<T>) {
                resize_uninitialized (s + 1);
            }
            else {
                resize (s + 1);
            }
            fLiveData_[s] = e;
        }
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::operator T* ()
    {
        AssertNotNull (fLiveData_);
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline SmallStackBuffer<T, BUF_SIZE>::operator const T* () const
    {
        AssertNotNull (fLiveData_);
        return fLiveData_;
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::Invariant () const
    {
#if qDebug
        Invariant_ ();
#endif
    }
#if qDebug
    template <typename T, size_t BUF_SIZE>
    void SmallStackBuffer<T, BUF_SIZE>::Invariant_ () const
    {
        Assert (capacity () >= size ());
        ValidateGuards_ ();
    }
    template <typename T, size_t BUF_SIZE>
    void SmallStackBuffer<T, BUF_SIZE>::ValidateGuards_ () const
    {
        Assert (::memcmp (kGuard1_, fGuard1_, sizeof (kGuard1_)) == 0);
        Assert (::memcmp (kGuard2_, fGuard2_, sizeof (kGuard2_)) == 0);
    }
#endif
    template <typename T, size_t BUF_SIZE>
    inline T* SmallStackBuffer<T, BUF_SIZE>::BufferAsT_ () noexcept
    {
        return reinterpret_cast<T*> (&fInlinePreallocatedBuffer_[0]);
    }
    template <typename T, size_t BUF_SIZE>
    inline const T* SmallStackBuffer<T, BUF_SIZE>::BufferAsT_ () const noexcept
    {
        return reinterpret_cast<const T*> (&fInlinePreallocatedBuffer_[0]);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::DestroyElts_ (T* start, T* end) noexcept
    {
        for (auto i = start; i != end; ++i) {
            i->~T ();
        }
    }
    template <typename T, size_t BUF_SIZE>
    inline byte* SmallStackBuffer<T, BUF_SIZE>::LiveDataAsAllocatedBytes_ ()
    {
        Require (fLiveData_ != BufferAsT_ ());
        return reinterpret_cast<byte*> (fLiveData_);
    }
    template <typename T, size_t BUF_SIZE>
    inline byte* SmallStackBuffer<T, BUF_SIZE>::Allocate_ (size_t bytes)
    {
        void* p = ::malloc (bytes);
        Execution::ThrowIfNull (p);
        return reinterpret_cast<byte*> (p);
    }
    template <typename T, size_t BUF_SIZE>
    inline void SmallStackBuffer<T, BUF_SIZE>::Deallocate_ (byte* bytes)
    {
        if (bytes != nullptr) {
            ::free (bytes);
        }
    }

}

#endif /*_Stroika_Foundation_Memory_SmallStackBuffer_inl_*/
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "futf8strchrfieldsearcher.h"
#include "fold.h"

using vespalib::Optimized;
using search::byte;
using search::QueryTerm;
using search::v16qi;

namespace vsm {

IMPLEMENT_DUPLICATE(FUTF8StrChrFieldSearcher);

FUTF8StrChrFieldSearcher::FUTF8StrChrFieldSearcher()
    : UTF8StrChrFieldSearcher(),
      _folded(4096)
{ }
FUTF8StrChrFieldSearcher::FUTF8StrChrFieldSearcher(FieldIdT fId)
    : UTF8StrChrFieldSearcher(fId),
      _folded(4096)
{ }
FUTF8StrChrFieldSearcher::~FUTF8StrChrFieldSearcher() {}

bool
FUTF8StrChrFieldSearcher::ansiFold(const char * toFold, size_t sz, char * folded)
{
  bool retval(true);
  for(size_t i=0; i < sz; i++) {
    byte c = toFold[i];
    if (c>=128) { retval = false; break; }
    folded[i] = FieldSearcher::_foldLowCase[c];
  }
  return retval;
}

bool
FUTF8StrChrFieldSearcher::lfoldaa(const char * toFold, size_t sz, char * folded, size_t & unalignedStart)
{
  bool retval(true);
  unalignedStart = (size_t(toFold) & 0xF);
  size_t unalignedsz = std::min(sz, (16 - unalignedStart) & 0xF);

  size_t foldedUnaligned = (size_t(folded) & 0xF);
  unalignedStart = (foldedUnaligned < unalignedStart) ? (unalignedStart-foldedUnaligned) : unalignedStart + 16 - foldedUnaligned;
  size_t alignedStart = unalignedStart+unalignedsz;

  size_t alignedsz = sz - unalignedsz;
  size_t alignsz16 = alignedsz & 0xFFFFFFF0;
  size_t rest = alignedsz - alignsz16;

  if (unalignedStart) {
    retval = ansiFold(toFold, unalignedsz, folded + unalignedStart);
  }
  if (alignsz16 && retval) {
    const byte * end = sse2_foldaa(reinterpret_cast<const byte *>(toFold+unalignedsz), alignsz16, reinterpret_cast<byte *>(folded+alignedStart));
    retval = (end == reinterpret_cast<const byte *>(toFold+unalignedsz+alignsz16));
  }
  if(rest && retval) {
    retval = ansiFold(toFold + unalignedsz + alignsz16, rest, folded+alignedStart+alignsz16);
  }
  return retval;
}

bool
FUTF8StrChrFieldSearcher::lfoldua(const char * toFold, size_t sz, char * folded, size_t & alignedStart)
{
  bool retval(true);

  alignedStart =  0xF - (size_t(folded + 0xF) % 0x10);

  size_t alignsz16 = sz & 0xFFFFFFF0;
  size_t rest = sz - alignsz16;

  if (alignsz16) {
    const byte * end = sse2_foldua(reinterpret_cast<const byte *>(toFold), alignsz16, reinterpret_cast<byte *>(folded+alignedStart));
    retval = (end == reinterpret_cast<const byte *>(toFold+alignsz16));
  }
  if(rest && retval) {
    retval = ansiFold(toFold + alignsz16, rest, folded+alignedStart+alignsz16);
  }
  return retval;
}

namespace {

inline const char * advance(const char * n, register const v16qi zero)
{
    uint32_t charMap = 0;
    unsigned zeroCountSum = 0;
    do { // find first '\0' character (the end of the word)
#ifndef __INTEL_COMPILER
        v16qi tmpCurrent = __builtin_ia32_loaddqu(n+zeroCountSum);
        v16qi tmp0       = __builtin_ia32_pcmpeqb128(tmpCurrent, reinterpret_cast<v16qi>(zero));
        charMap = __builtin_ia32_pmovmskb128(tmp0); // 1 in charMap equals to '\0' in input buffer
#else
#   warning "Intel's icc compiler does not like __builtin_ia32_xxxxx"
    abort();
#endif
        zeroCountSum += 16;
    } while (!charMap);
    int charCount = Optimized::lsbIdx(charMap); // number of word characters in last 16 bytes
    uint32_t zeroMap = ((~charMap) & 0xffff) >> charCount;

    int zeroCounter = Optimized::lsbIdx(zeroMap); // number of non-characters ('\0') in last 16 bytes
    int sum = zeroCountSum - 16 + charCount + zeroCounter;
    if (!zeroMap) { // only '\0' in last 16 bytes (no new word found)
        do { // find first word character (the next word)
#ifndef __INTEL_COMPILER
            v16qi tmpCurrent = __builtin_ia32_loaddqu(n+zeroCountSum);
            tmpCurrent  = __builtin_ia32_pcmpgtb128(tmpCurrent, reinterpret_cast<v16qi>(zero));
            zeroMap = __builtin_ia32_pmovmskb128(tmpCurrent); // 1 in zeroMap equals to word character in input buffer
#else
#   warning "Intel's icc compiler does not like __builtin_ia32_xxxxx"
    abort();
#endif
            zeroCountSum += 16;
        } while(!zeroMap);
        zeroCounter = Optimized::lsbIdx(zeroMap);
        sum = zeroCountSum - 16 + zeroCounter;
    }
    return n + sum;
}

}

size_t FUTF8StrChrFieldSearcher::match(const char *folded, size_t sz, QueryTerm & qt)
{
  register const v16qi _G_zero  = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  termcount_t words(0);
  const char * term;
  termsize_t tsz = qt.term(term);
  const char *et=term+tsz;
  const char * n = folded;
  const char *e = n + sz;

  while (!*n) n++;
  while (true) {
    if (n>=e) break;

#if 0
    v16qi current = __builtin_ia32_loaddqu(n);
    current = __builtin_ia32_pcmpeqb128(current, _qtlFast[0]);
    unsigned eqMap = __builtin_ia32_pmovmskb128(current);
    unsigned neqMap = ~eqMap;
    unsigned numEq = Optimized::lsbIdx(neqMap);
    /* if (eqMap)*/ {
      if (numEq >= 16) {
        const char *tt = term+16;
        const char *p = n+16;
        while ( (*tt == *p) && (tt < et)) { tt++; p++; numEq++; }
      }
      if ((numEq >= tsz) && (prefix() || qt.isPrefix() || !n[tsz])) {
        addHit(qt, words);
      }
    }
#else
    const char *tt = term;
    while ((tt < et) && (*tt == *n)) { tt++; n++; }
    if ((tt == et) && (prefix() || qt.isPrefix() || !*n)) {
      addHit(qt, words);
    }
#endif
    words++;
    n = advance(n, _G_zero);
  }
  return words;
}

size_t FUTF8StrChrFieldSearcher::match(const char *folded, size_t sz, size_t mintsz, QueryTerm ** qtl, size_t qtlSize)
{
  (void) mintsz;
  register const v16qi _G_zero  = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  termcount_t words(0);
  const char * n = folded;
  const char *e = n + sz;
  while (!*n) n++;
  for( ; ; ) {
    if (n>=e) break;
#if 0
    v16qi current = __builtin_ia32_loaddqu(n);
    for(size_t i=0; i < qtlSize; i++) {
      v16qi tmpEq = __builtin_ia32_pcmpeqb128(current, _qtlFast[i]);
      unsigned eqMap = __builtin_ia32_pmovmskb128(tmpEq);
      /* if (eqMap) */ {
        QueryTerm & qt = *qtl[i];
        unsigned neqMap = ~eqMap;
        unsigned numEq = Optimized::lsbIdx(neqMap);
        termsize_t tsz = qt.termLen();
        if (numEq >= 16) {
          const char *tt = qt.term() + 16;
          const char *et=tt+tsz;
          const char *p = n+16;
          while ( (*tt == *p) && (tt < et)) { tt++; p++; numEq++; }
        }
        if ((numEq >= tsz) && (prefix() || qt.isPrefix() || !n[tsz])) {
          addHit(qt, words);
        }
      }
    }
#else
    for(QueryTerm ** it=qtl, ** mt=qtl+qtlSize; it != mt; it++) {
      QueryTerm & qt = **it;
      const char * term;
      termsize_t tsz = qt.term(term);

      const char *et=term+tsz;
      const char *fnt;
      for (fnt = n; (term < et) && (*term == *fnt); term++, fnt++);
      if ((term == et) && (prefix() || qt.isPrefix() || !*fnt)) {
        addHit(qt, words);
      }
    }
#endif
    words++;
    n = advance(n, _G_zero);
  }
  return words;
}

size_t FUTF8StrChrFieldSearcher::matchTerm(const FieldRef & f, QueryTerm & qt)
{
  _folded.reserve(f.size()+16*3);  //Enable fulle xmm0 store
  size_t unalignedStart(0);
  bool ascii7Bit = lfoldua(f.c_str(), f.size(), &_folded[0], unalignedStart);
  if (ascii7Bit) {
    char * folded = &_folded[unalignedStart];
    /// Add the pattern 00 01 00 to avoid multiple eof tests of falling off the edge.
    folded[f.size()] = 0;
    folded[f.size()+1] = 0x01;
    memset(folded + f.size() + 2, 0, 16); // initialize padding data to avoid valgrind complaining about uninitialized values
    return match(folded, f.size(), qt);
    NEED_CHAR_STAT(addPureUsAsciiField(f.size()));
  } else {
    return UTF8StrChrFieldSearcher::matchTerm(f, qt);
  }
}

size_t FUTF8StrChrFieldSearcher::matchTerms(const FieldRef & f, const size_t mintsz)
{
  _folded.reserve(f.size()+16*3);  //Enable fulle xmm0 store
  size_t unalignedStart(0);
  bool ascii7Bit = lfoldua(f.c_str(), f.size(), &_folded[0], unalignedStart);
  if (ascii7Bit) {
    char * folded = &_folded[unalignedStart];
    /// Add the pattern 00 01 00 to avoid multiple eof tests of falling off the edge.
    folded[f.size()] = 0;
    folded[f.size()+1] = 0x01;
    memset(folded + f.size() + 2, 0, 16); // initialize padding data to avoid valgrind complaining about uninitialized values
    return match(folded, f.size(), mintsz, &_qtl[0], _qtl.size());
    NEED_CHAR_STAT(addPureUsAsciiField(f.size()));
  } else {
    return UTF8StrChrFieldSearcher::matchTerms(f, mintsz);
  }
}

}
<commit_msg>ISO C++1z does not allow ‘register’ storage class specifier (gcc 7)<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "futf8strchrfieldsearcher.h"
#include "fold.h"

using vespalib::Optimized;
using search::byte;
using search::QueryTerm;
using search::v16qi;

namespace vsm {

IMPLEMENT_DUPLICATE(FUTF8StrChrFieldSearcher);

FUTF8StrChrFieldSearcher::FUTF8StrChrFieldSearcher()
    : UTF8StrChrFieldSearcher(),
      _folded(4096)
{ }
FUTF8StrChrFieldSearcher::FUTF8StrChrFieldSearcher(FieldIdT fId)
    : UTF8StrChrFieldSearcher(fId),
      _folded(4096)
{ }
FUTF8StrChrFieldSearcher::~FUTF8StrChrFieldSearcher() {}

bool
FUTF8StrChrFieldSearcher::ansiFold(const char * toFold, size_t sz, char * folded)
{
  bool retval(true);
  for(size_t i=0; i < sz; i++) {
    byte c = toFold[i];
    if (c>=128) { retval = false; break; }
    folded[i] = FieldSearcher::_foldLowCase[c];
  }
  return retval;
}

bool
FUTF8StrChrFieldSearcher::lfoldaa(const char * toFold, size_t sz, char * folded, size_t & unalignedStart)
{
  bool retval(true);
  unalignedStart = (size_t(toFold) & 0xF);
  size_t unalignedsz = std::min(sz, (16 - unalignedStart) & 0xF);

  size_t foldedUnaligned = (size_t(folded) & 0xF);
  unalignedStart = (foldedUnaligned < unalignedStart) ? (unalignedStart-foldedUnaligned) : unalignedStart + 16 - foldedUnaligned;
  size_t alignedStart = unalignedStart+unalignedsz;

  size_t alignedsz = sz - unalignedsz;
  size_t alignsz16 = alignedsz & 0xFFFFFFF0;
  size_t rest = alignedsz - alignsz16;

  if (unalignedStart) {
    retval = ansiFold(toFold, unalignedsz, folded + unalignedStart);
  }
  if (alignsz16 && retval) {
    const byte * end = sse2_foldaa(reinterpret_cast<const byte *>(toFold+unalignedsz), alignsz16, reinterpret_cast<byte *>(folded+alignedStart));
    retval = (end == reinterpret_cast<const byte *>(toFold+unalignedsz+alignsz16));
  }
  if(rest && retval) {
    retval = ansiFold(toFold + unalignedsz + alignsz16, rest, folded+alignedStart+alignsz16);
  }
  return retval;
}

bool
FUTF8StrChrFieldSearcher::lfoldua(const char * toFold, size_t sz, char * folded, size_t & alignedStart)
{
  bool retval(true);

  alignedStart =  0xF - (size_t(folded + 0xF) % 0x10);

  size_t alignsz16 = sz & 0xFFFFFFF0;
  size_t rest = sz - alignsz16;

  if (alignsz16) {
    const byte * end = sse2_foldua(reinterpret_cast<const byte *>(toFold), alignsz16, reinterpret_cast<byte *>(folded+alignedStart));
    retval = (end == reinterpret_cast<const byte *>(toFold+alignsz16));
  }
  if(rest && retval) {
    retval = ansiFold(toFold + alignsz16, rest, folded+alignedStart+alignsz16);
  }
  return retval;
}

namespace {

inline const char * advance(const char * n, const v16qi zero)
{
    uint32_t charMap = 0;
    unsigned zeroCountSum = 0;
    do { // find first '\0' character (the end of the word)
#ifndef __INTEL_COMPILER
        v16qi tmpCurrent = __builtin_ia32_loaddqu(n+zeroCountSum);
        v16qi tmp0       = __builtin_ia32_pcmpeqb128(tmpCurrent, reinterpret_cast<v16qi>(zero));
        charMap = __builtin_ia32_pmovmskb128(tmp0); // 1 in charMap equals to '\0' in input buffer
#else
#   warning "Intel's icc compiler does not like __builtin_ia32_xxxxx"
    abort();
#endif
        zeroCountSum += 16;
    } while (!charMap);
    int charCount = Optimized::lsbIdx(charMap); // number of word characters in last 16 bytes
    uint32_t zeroMap = ((~charMap) & 0xffff) >> charCount;

    int zeroCounter = Optimized::lsbIdx(zeroMap); // number of non-characters ('\0') in last 16 bytes
    int sum = zeroCountSum - 16 + charCount + zeroCounter;
    if (!zeroMap) { // only '\0' in last 16 bytes (no new word found)
        do { // find first word character (the next word)
#ifndef __INTEL_COMPILER
            v16qi tmpCurrent = __builtin_ia32_loaddqu(n+zeroCountSum);
            tmpCurrent  = __builtin_ia32_pcmpgtb128(tmpCurrent, reinterpret_cast<v16qi>(zero));
            zeroMap = __builtin_ia32_pmovmskb128(tmpCurrent); // 1 in zeroMap equals to word character in input buffer
#else
#   warning "Intel's icc compiler does not like __builtin_ia32_xxxxx"
    abort();
#endif
            zeroCountSum += 16;
        } while(!zeroMap);
        zeroCounter = Optimized::lsbIdx(zeroMap);
        sum = zeroCountSum - 16 + zeroCounter;
    }
    return n + sum;
}

}

size_t FUTF8StrChrFieldSearcher::match(const char *folded, size_t sz, QueryTerm & qt)
{
  const v16qi _G_zero  = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  termcount_t words(0);
  const char * term;
  termsize_t tsz = qt.term(term);
  const char *et=term+tsz;
  const char * n = folded;
  const char *e = n + sz;

  while (!*n) n++;
  while (true) {
    if (n>=e) break;

#if 0
    v16qi current = __builtin_ia32_loaddqu(n);
    current = __builtin_ia32_pcmpeqb128(current, _qtlFast[0]);
    unsigned eqMap = __builtin_ia32_pmovmskb128(current);
    unsigned neqMap = ~eqMap;
    unsigned numEq = Optimized::lsbIdx(neqMap);
    /* if (eqMap)*/ {
      if (numEq >= 16) {
        const char *tt = term+16;
        const char *p = n+16;
        while ( (*tt == *p) && (tt < et)) { tt++; p++; numEq++; }
      }
      if ((numEq >= tsz) && (prefix() || qt.isPrefix() || !n[tsz])) {
        addHit(qt, words);
      }
    }
#else
    const char *tt = term;
    while ((tt < et) && (*tt == *n)) { tt++; n++; }
    if ((tt == et) && (prefix() || qt.isPrefix() || !*n)) {
      addHit(qt, words);
    }
#endif
    words++;
    n = advance(n, _G_zero);
  }
  return words;
}

size_t FUTF8StrChrFieldSearcher::match(const char *folded, size_t sz, size_t mintsz, QueryTerm ** qtl, size_t qtlSize)
{
  (void) mintsz;
  const v16qi _G_zero  = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  termcount_t words(0);
  const char * n = folded;
  const char *e = n + sz;
  while (!*n) n++;
  for( ; ; ) {
    if (n>=e) break;
#if 0
    v16qi current = __builtin_ia32_loaddqu(n);
    for(size_t i=0; i < qtlSize; i++) {
      v16qi tmpEq = __builtin_ia32_pcmpeqb128(current, _qtlFast[i]);
      unsigned eqMap = __builtin_ia32_pmovmskb128(tmpEq);
      /* if (eqMap) */ {
        QueryTerm & qt = *qtl[i];
        unsigned neqMap = ~eqMap;
        unsigned numEq = Optimized::lsbIdx(neqMap);
        termsize_t tsz = qt.termLen();
        if (numEq >= 16) {
          const char *tt = qt.term() + 16;
          const char *et=tt+tsz;
          const char *p = n+16;
          while ( (*tt == *p) && (tt < et)) { tt++; p++; numEq++; }
        }
        if ((numEq >= tsz) && (prefix() || qt.isPrefix() || !n[tsz])) {
          addHit(qt, words);
        }
      }
    }
#else
    for(QueryTerm ** it=qtl, ** mt=qtl+qtlSize; it != mt; it++) {
      QueryTerm & qt = **it;
      const char * term;
      termsize_t tsz = qt.term(term);

      const char *et=term+tsz;
      const char *fnt;
      for (fnt = n; (term < et) && (*term == *fnt); term++, fnt++);
      if ((term == et) && (prefix() || qt.isPrefix() || !*fnt)) {
        addHit(qt, words);
      }
    }
#endif
    words++;
    n = advance(n, _G_zero);
  }
  return words;
}

size_t FUTF8StrChrFieldSearcher::matchTerm(const FieldRef & f, QueryTerm & qt)
{
  _folded.reserve(f.size()+16*3);  //Enable fulle xmm0 store
  size_t unalignedStart(0);
  bool ascii7Bit = lfoldua(f.c_str(), f.size(), &_folded[0], unalignedStart);
  if (ascii7Bit) {
    char * folded = &_folded[unalignedStart];
    /// Add the pattern 00 01 00 to avoid multiple eof tests of falling off the edge.
    folded[f.size()] = 0;
    folded[f.size()+1] = 0x01;
    memset(folded + f.size() + 2, 0, 16); // initialize padding data to avoid valgrind complaining about uninitialized values
    return match(folded, f.size(), qt);
    NEED_CHAR_STAT(addPureUsAsciiField(f.size()));
  } else {
    return UTF8StrChrFieldSearcher::matchTerm(f, qt);
  }
}

size_t FUTF8StrChrFieldSearcher::matchTerms(const FieldRef & f, const size_t mintsz)
{
  _folded.reserve(f.size()+16*3);  //Enable fulle xmm0 store
  size_t unalignedStart(0);
  bool ascii7Bit = lfoldua(f.c_str(), f.size(), &_folded[0], unalignedStart);
  if (ascii7Bit) {
    char * folded = &_folded[unalignedStart];
    /// Add the pattern 00 01 00 to avoid multiple eof tests of falling off the edge.
    folded[f.size()] = 0;
    folded[f.size()+1] = 0x01;
    memset(folded + f.size() + 2, 0, 16); // initialize padding data to avoid valgrind complaining about uninitialized values
    return match(folded, f.size(), mintsz, &_qtl[0], _qtl.size());
    NEED_CHAR_STAT(addPureUsAsciiField(f.size()));
  } else {
    return UTF8StrChrFieldSearcher::matchTerms(f, mintsz);
  }
}

}
<|endoftext|>


<commit_before>//=-- lsan_common_mac.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of LeakSanitizer.
// Implementation of common leak checking functionality. Darwin-specific code.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#include "lsan_common.h"

#if CAN_SANITIZE_LEAKS && SANITIZER_MAC

#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "lsan_allocator.h"

#include <pthread.h>

namespace __lsan {

typedef struct {
  int disable_counter;
  u32 current_thread_id;
  AllocatorCache cache;
} thread_local_data_t;

static pthread_key_t key;
static pthread_once_t key_once = PTHREAD_ONCE_INIT;

static void make_tls_key() { CHECK_EQ(pthread_key_create(&key, NULL), 0); }

static thread_local_data_t *get_tls_val(bool alloc) {
  pthread_once(&key_once, make_tls_key);

  thread_local_data_t *ptr = (thread_local_data_t *)pthread_getspecific(key);
  if (ptr == NULL && alloc) {
    ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr));
    ptr->disable_counter = 0;
    ptr->current_thread_id = kInvalidTid;
    ptr->cache = AllocatorCache();
    pthread_setspecific(key, ptr);
  }

  return ptr;
}

bool DisabledInThisThread() {
  thread_local_data_t *data = get_tls_val(false);
  return data ? data->disable_counter > 0 : false;
}

void DisableInThisThread() { ++get_tls_val(true)->disable_counter; }

void EnableInThisThread() {
  int *disable_counter = &get_tls_val(true)->disable_counter;
  if (*disable_counter == 0) {
    DisableCounterUnderflow();
  }
  --*disable_counter;
}

u32 GetCurrentThread() { return get_tls_val(true)->current_thread_id; }

void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }

AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; }

void InitializePlatformSpecificModules() {
  CHECK(0 && "unimplemented");
}

// Scans global variables for heap pointers.
void ProcessGlobalRegions(Frontier *frontier) {
  CHECK(0 && "unimplemented");
}

void ProcessPlatformSpecificAllocations(Frontier *frontier) {
  CHECK(0 && "unimplemented");
}

void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
  CHECK(0 && "unimplemented");
}

} // namespace __lsan

#endif // CAN_SANITIZE_LEAKS && SANITIZER_MAC
<commit_msg>Remove failing check from platform specific darwin lsan initializer<commit_after>//=-- lsan_common_mac.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of LeakSanitizer.
// Implementation of common leak checking functionality. Darwin-specific code.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#include "lsan_common.h"

#if CAN_SANITIZE_LEAKS && SANITIZER_MAC

#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "lsan_allocator.h"

#include <pthread.h>

namespace __lsan {

typedef struct {
  int disable_counter;
  u32 current_thread_id;
  AllocatorCache cache;
} thread_local_data_t;

static pthread_key_t key;
static pthread_once_t key_once = PTHREAD_ONCE_INIT;

static void make_tls_key() { CHECK_EQ(pthread_key_create(&key, NULL), 0); }

static thread_local_data_t *get_tls_val(bool alloc) {
  pthread_once(&key_once, make_tls_key);

  thread_local_data_t *ptr = (thread_local_data_t *)pthread_getspecific(key);
  if (ptr == NULL && alloc) {
    ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr));
    ptr->disable_counter = 0;
    ptr->current_thread_id = kInvalidTid;
    ptr->cache = AllocatorCache();
    pthread_setspecific(key, ptr);
  }

  return ptr;
}

bool DisabledInThisThread() {
  thread_local_data_t *data = get_tls_val(false);
  return data ? data->disable_counter > 0 : false;
}

void DisableInThisThread() { ++get_tls_val(true)->disable_counter; }

void EnableInThisThread() {
  int *disable_counter = &get_tls_val(true)->disable_counter;
  if (*disable_counter == 0) {
    DisableCounterUnderflow();
  }
  --*disable_counter;
}

u32 GetCurrentThread() { return get_tls_val(true)->current_thread_id; }

void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }

AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; }

// Required on Linux for initialization of TLS behavior, but should not be
// required on Darwin.
void InitializePlatformSpecificModules() {}

// Scans global variables for heap pointers.
void ProcessGlobalRegions(Frontier *frontier) {
  CHECK(0 && "unimplemented");
}

void ProcessPlatformSpecificAllocations(Frontier *frontier) {
  CHECK(0 && "unimplemented");
}

void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
  CHECK(0 && "unimplemented");
}

} // namespace __lsan

#endif // CAN_SANITIZE_LEAKS && SANITIZER_MAC
<|endoftext|>