<commit_before>//
//  Drive.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 25/09/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "Drive.hpp"

#include "Track/UnformattedTrack.hpp"

#include <algorithm>
#include <cassert>
#include <cstdlib>

using namespace Storage::Disk;

Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads):
	Storage::TimedEventLoop(input_clock_rate),
	rotational_multiplier_(60, revolutions_per_minute),
	available_heads_(number_of_heads),
	random_source_(static_cast<uint64_t>(arc4random()) | (static_cast<uint64_t>(arc4random()) << 32)) {
	rotational_multiplier_.simplify();
}

Drive::~Drive() {
	if(disk_) disk_->flush_tracks();
}

void Drive::set_disk(const std::shared_ptr<Disk> &disk) {
	if(disk_) disk_->flush_tracks();
	disk_ = disk;
	has_disk_ = !!disk_;

	invalidate_track();
	update_sleep_observer();
}

bool Drive::has_disk() {
	return has_disk_;
}

bool Drive::is_sleeping() {
	return !motor_is_on_ || !has_disk_;
}

bool Drive::get_is_track_zero() {
	return head_position_ == HeadPosition(0);
}

void Drive::step(HeadPosition offset) {
	HeadPosition old_head_position = head_position_;
	head_position_ += offset;
	if(head_position_ < HeadPosition(0)) {
		head_position_ = HeadPosition(0);
		if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepBelowZero);
	} else {
		if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepNormal);
	}

	// If the head moved, flush the old track.
	if(head_position_ != old_head_position) {
		track_ = nullptr;
	}
}

void Drive::set_head(int head) {
	head = std::min(head, available_heads_ - 1);
	if(head != head_) {
		head_ = head;
		track_ = nullptr;
	}
}

Storage::Time Drive::get_time_into_track() {
	// `result` will initially be amount of time since the index hole was seen as a
	// proportion of a second; convert it into proportion of a rotation, simplify and return.
	Time result(cycles_since_index_hole_, static_cast<int>(get_input_clock_rate()));
	result /= rotational_multiplier_;
	result.simplify();
//	assert(result <= Time(1));
	return result;
}

bool Drive::get_is_read_only() {
	if(disk_) return disk_->get_is_read_only();
	return true;
}

bool Drive::get_is_ready() {
	return true;
	return ready_index_count_ == 2;
}

void Drive::set_motor_on(bool motor_is_on) {
	motor_is_on_ = motor_is_on;

	if(observer_) {
		observer_->set_drive_motor_status(drive_name_, motor_is_on_);
		if(announce_motor_led_) {
			observer_->set_led_status(drive_name_, motor_is_on_);
		}
	}

	if(!motor_is_on) {
		ready_index_count_ = 0;
		if(disk_) disk_->flush_tracks();
	}
	update_sleep_observer();
}

bool Drive::get_motor_on() {
	return motor_is_on_;
}

void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) {
	event_delegate_ = delegate;
}

void Drive::advance(const Cycles cycles) {
	cycles_since_index_hole_ += static_cast<unsigned int>(cycles.as_int());
	if(event_delegate_) event_delegate_->advance(cycles);
}

void Drive::run_for(const Cycles cycles) {
	if(has_disk_ && motor_is_on_) {
		Time zero(0);

		int number_of_cycles = cycles.as_int();
		while(number_of_cycles) {
			int cycles_until_next_event = static_cast<int>(get_cycles_until_next_event());
			int cycles_to_run_for = std::min(cycles_until_next_event, number_of_cycles);
			if(!is_reading_ && cycles_until_bits_written_ > zero) {
				int write_cycles_target = cycles_until_bits_written_.get<int>();
				if(cycles_until_bits_written_.length % cycles_until_bits_written_.clock_rate) write_cycles_target++;
				cycles_to_run_for = std::min(cycles_to_run_for, write_cycles_target);
			}

			number_of_cycles -= cycles_to_run_for;
			if(!is_reading_) {
				if(cycles_until_bits_written_ > zero) {
					Storage::Time cycles_to_run_for_time(cycles_to_run_for);
					if(cycles_until_bits_written_ <= cycles_to_run_for_time) {
						if(event_delegate_) event_delegate_->process_write_completed();
						if(cycles_until_bits_written_ <= cycles_to_run_for_time)
							cycles_until_bits_written_.set_zero();
						else
							cycles_until_bits_written_ -= cycles_to_run_for_time;
					} else {
						cycles_until_bits_written_ -= cycles_to_run_for_time;
					}
				}
			}
			TimedEventLoop::run_for(Cycles(cycles_to_run_for));
		}
	}
}

// MARK: - Track timed event loop

void Drive::get_next_event(const Time &duration_already_passed) {
	// Grab a new track if not already in possession of one. This will recursively call get_next_event,
	// supplying a proper duration_already_passed.
	if(!track_) {
		random_interval_.set_zero();
		setup_track();
		return;
	}

	// If gain has now been turned up so as to generate noise, generate some noise.
	if(random_interval_ > Time(0)) {
		current_event_.type = Track::Event::IndexHole;
		current_event_.length.length = 2 + (random_source_&1);
		current_event_.length.clock_rate = 1000000;
		random_source_ = (random_source_ >> 1) | (random_source_ << 63);

		if(random_interval_ < current_event_.length) {
			current_event_.length = random_interval_;
			random_interval_.set_zero();
		} else {
			random_interval_ -= current_event_.length;
		}
		set_next_event_time_interval(current_event_.length);
		return;
	}

	if(track_) {
		current_event_ = track_->get_next_event();
	} else {
		current_event_.length.length = 1;
		current_event_.length.clock_rate = 1;
		current_event_.type = Track::Event::IndexHole;
	}

	// divide interval, which is in terms of a single rotation of the disk, by rotation speed to
	// convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_
	assert(current_event_.length <= Time(1) && current_event_.length >= Time(0));
	assert(current_event_.length > duration_already_passed);
	Time interval = (current_event_.length - duration_already_passed) * rotational_multiplier_;

	// An interval greater than 15ms => adjust gain up the point where noise starts happening.
	// Seed that up and leave a 15ms gap until it starts.
	const Time safe_gain_period(15, 1000000);
	if(interval >= safe_gain_period) {
		random_interval_ = interval - safe_gain_period;
		interval = safe_gain_period;
	}

	set_next_event_time_interval(interval);
}

void Drive::process_next_event() {
	if(current_event_.type == Track::Event::IndexHole) {
//		assert(get_time_into_track() == Time(1) || get_time_into_track() == Time(0));
		if(ready_index_count_ < 2) ready_index_count_++;
		cycles_since_index_hole_ = 0;
	}
	if(
		event_delegate_ &&
		(current_event_.type == Track::Event::IndexHole || is_reading_)
	){
		event_delegate_->process_event(current_event_);
	}
	get_next_event(Time(0));
}

// MARK: - Track management

std::shared_ptr<Track> Drive::get_track() {
	if(disk_) return disk_->get_track_at_position(Track::Address(head_, head_position_));
	return nullptr;
}

void Drive::set_track(const std::shared_ptr<Track> &track) {
	if(disk_) disk_->set_track_at_position(Track::Address(head_, head_position_), track);
}

void Drive::setup_track() {
	track_ = get_track();
	if(!track_) {
		track_.reset(new UnformattedTrack);
	}

	Time offset;
	Time track_time_now = get_time_into_track();
	assert(track_time_now >= Time(0) && current_event_.length <= Time(1));

	Time time_found = track_->seek_to(track_time_now);

	// time_found can be greater than track_time_now if limited precision caused rounding
	if(time_found <= track_time_now) {
		offset = track_time_now - time_found;
	} else {
		offset.set_zero();
	}

	get_next_event(offset);
}

void Drive::invalidate_track() {
	track_ = nullptr;
	if(patched_track_) {
		set_track(patched_track_);
		patched_track_ = nullptr;
	}
}

// MARK: - Writing

void Drive::begin_writing(Time bit_length, bool clamp_to_index_hole) {
	is_reading_ = false;
	clamp_writing_to_index_hole_ = clamp_to_index_hole;

	cycles_per_bit_ = Storage::Time(get_input_clock_rate()) * bit_length;
	cycles_per_bit_.simplify();

	write_segment_.length_of_a_bit = bit_length / rotational_multiplier_;
	write_segment_.data.clear();
	write_segment_.number_of_bits = 0;

	write_start_time_ = get_time_into_track();
}

void Drive::write_bit(bool value) {
	bool needs_new_byte = !(write_segment_.number_of_bits&7);
	if(needs_new_byte) write_segment_.data.push_back(0);
	if(value) write_segment_.data[write_segment_.number_of_bits >> 3] |= 0x80 >> (write_segment_.number_of_bits & 7);
	write_segment_.number_of_bits++;

	cycles_until_bits_written_ += cycles_per_bit_;
}

void Drive::end_writing() {
	if(!is_reading_) {
		is_reading_ = true;

		if(!patched_track_) {
			// Avoid creating a new patched track if this one is already patched
			patched_track_ = std::dynamic_pointer_cast<PCMPatchedTrack>(track_);
			if(!patched_track_) {
				patched_track_.reset(new PCMPatchedTrack(track_));
			}
		}
		patched_track_->add_segment(write_start_time_, write_segment_, clamp_writing_to_index_hole_);
		cycles_since_index_hole_ %= get_input_clock_rate();
		invalidate_track();
	}
}

void Drive::set_activity_observer(Activity::Observer *observer, const std::string &name, bool add_motor_led) {
	observer_ = observer;
	announce_motor_led_ = add_motor_led;
	if(observer) {
		drive_name_ = name;

		observer->register_drive(drive_name_);
		observer->set_drive_motor_status(drive_name_, motor_is_on_);

		if(add_motor_led) {
			observer->register_led(drive_name_);
			observer->set_led_status(drive_name_, motor_is_on_);
		}
	}
}
<commit_msg>Eliminates `arc4random`.<commit_after>//
//  Drive.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 25/09/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "Drive.hpp"

#include "Track/UnformattedTrack.hpp"

#include <algorithm>
#include <cassert>
#include <cmath>
#include <chrono>
#include <random>

using namespace Storage::Disk;

Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads):
	Storage::TimedEventLoop(input_clock_rate),
	rotational_multiplier_(60, revolutions_per_minute),
	available_heads_(number_of_heads){
	rotational_multiplier_.simplify();

	const auto seed = static_cast<std::default_random_engine::result_type>(std::chrono::system_clock::now().time_since_epoch().count());
	std::default_random_engine randomiser(seed);

	// Get at least 64 bits of random information; rounding is likey to give this a slight bias.
	random_source_ = 0;
	auto half_range = (randomiser.max() - randomiser.min()) / 2;
	for(int bit = 0; bit < 64; ++bit) {
		random_source_ <<= 1;
		random_source_ |= ((randomiser() - randomiser.min()) >= half_range) ? 1 : 0;
	}
}

Drive::~Drive() {
	if(disk_) disk_->flush_tracks();
}

void Drive::set_disk(const std::shared_ptr<Disk> &disk) {
	if(disk_) disk_->flush_tracks();
	disk_ = disk;
	has_disk_ = !!disk_;

	invalidate_track();
	update_sleep_observer();
}

bool Drive::has_disk() {
	return has_disk_;
}

bool Drive::is_sleeping() {
	return !motor_is_on_ || !has_disk_;
}

bool Drive::get_is_track_zero() {
	return head_position_ == HeadPosition(0);
}

void Drive::step(HeadPosition offset) {
	HeadPosition old_head_position = head_position_;
	head_position_ += offset;
	if(head_position_ < HeadPosition(0)) {
		head_position_ = HeadPosition(0);
		if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepBelowZero);
	} else {
		if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepNormal);
	}

	// If the head moved, flush the old track.
	if(head_position_ != old_head_position) {
		track_ = nullptr;
	}
}

void Drive::set_head(int head) {
	head = std::min(head, available_heads_ - 1);
	if(head != head_) {
		head_ = head;
		track_ = nullptr;
	}
}

Storage::Time Drive::get_time_into_track() {
	// `result` will initially be amount of time since the index hole was seen as a
	// proportion of a second; convert it into proportion of a rotation, simplify and return.
	Time result(cycles_since_index_hole_, static_cast<int>(get_input_clock_rate()));
	result /= rotational_multiplier_;
	result.simplify();
//	assert(result <= Time(1));
	return result;
}

bool Drive::get_is_read_only() {
	if(disk_) return disk_->get_is_read_only();
	return true;
}

bool Drive::get_is_ready() {
	return true;
	return ready_index_count_ == 2;
}

void Drive::set_motor_on(bool motor_is_on) {
	motor_is_on_ = motor_is_on;

	if(observer_) {
		observer_->set_drive_motor_status(drive_name_, motor_is_on_);
		if(announce_motor_led_) {
			observer_->set_led_status(drive_name_, motor_is_on_);
		}
	}

	if(!motor_is_on) {
		ready_index_count_ = 0;
		if(disk_) disk_->flush_tracks();
	}
	update_sleep_observer();
}

bool Drive::get_motor_on() {
	return motor_is_on_;
}

void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) {
	event_delegate_ = delegate;
}

void Drive::advance(const Cycles cycles) {
	cycles_since_index_hole_ += static_cast<unsigned int>(cycles.as_int());
	if(event_delegate_) event_delegate_->advance(cycles);
}

void Drive::run_for(const Cycles cycles) {
	if(has_disk_ && motor_is_on_) {
		Time zero(0);

		int number_of_cycles = cycles.as_int();
		while(number_of_cycles) {
			int cycles_until_next_event = static_cast<int>(get_cycles_until_next_event());
			int cycles_to_run_for = std::min(cycles_until_next_event, number_of_cycles);
			if(!is_reading_ && cycles_until_bits_written_ > zero) {
				int write_cycles_target = cycles_until_bits_written_.get<int>();
				if(cycles_until_bits_written_.length % cycles_until_bits_written_.clock_rate) write_cycles_target++;
				cycles_to_run_for = std::min(cycles_to_run_for, write_cycles_target);
			}

			number_of_cycles -= cycles_to_run_for;
			if(!is_reading_) {
				if(cycles_until_bits_written_ > zero) {
					Storage::Time cycles_to_run_for_time(cycles_to_run_for);
					if(cycles_until_bits_written_ <= cycles_to_run_for_time) {
						if(event_delegate_) event_delegate_->process_write_completed();
						if(cycles_until_bits_written_ <= cycles_to_run_for_time)
							cycles_until_bits_written_.set_zero();
						else
							cycles_until_bits_written_ -= cycles_to_run_for_time;
					} else {
						cycles_until_bits_written_ -= cycles_to_run_for_time;
					}
				}
			}
			TimedEventLoop::run_for(Cycles(cycles_to_run_for));
		}
	}
}

// MARK: - Track timed event loop

void Drive::get_next_event(const Time &duration_already_passed) {
	// Grab a new track if not already in possession of one. This will recursively call get_next_event,
	// supplying a proper duration_already_passed.
	if(!track_) {
		random_interval_.set_zero();
		setup_track();
		return;
	}

	// If gain has now been turned up so as to generate noise, generate some noise.
	if(random_interval_ > Time(0)) {
		current_event_.type = Track::Event::IndexHole;
		current_event_.length.length = 2 + (random_source_&1);
		current_event_.length.clock_rate = 1000000;
		random_source_ = (random_source_ >> 1) | (random_source_ << 63);

		if(random_interval_ < current_event_.length) {
			current_event_.length = random_interval_;
			random_interval_.set_zero();
		} else {
			random_interval_ -= current_event_.length;
		}
		set_next_event_time_interval(current_event_.length);
		return;
	}

	if(track_) {
		current_event_ = track_->get_next_event();
	} else {
		current_event_.length.length = 1;
		current_event_.length.clock_rate = 1;
		current_event_.type = Track::Event::IndexHole;
	}

	// divide interval, which is in terms of a single rotation of the disk, by rotation speed to
	// convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_
	assert(current_event_.length <= Time(1) && current_event_.length >= Time(0));
	assert(current_event_.length > duration_already_passed);
	Time interval = (current_event_.length - duration_already_passed) * rotational_multiplier_;

	// An interval greater than 15ms => adjust gain up the point where noise starts happening.
	// Seed that up and leave a 15ms gap until it starts.
	const Time safe_gain_period(15, 1000000);
	if(interval >= safe_gain_period) {
		random_interval_ = interval - safe_gain_period;
		interval = safe_gain_period;
	}

	set_next_event_time_interval(interval);
}

void Drive::process_next_event() {
	if(current_event_.type == Track::Event::IndexHole) {
//		assert(get_time_into_track() == Time(1) || get_time_into_track() == Time(0));
		if(ready_index_count_ < 2) ready_index_count_++;
		cycles_since_index_hole_ = 0;
	}
	if(
		event_delegate_ &&
		(current_event_.type == Track::Event::IndexHole || is_reading_)
	){
		event_delegate_->process_event(current_event_);
	}
	get_next_event(Time(0));
}

// MARK: - Track management

std::shared_ptr<Track> Drive::get_track() {
	if(disk_) return disk_->get_track_at_position(Track::Address(head_, head_position_));
	return nullptr;
}

void Drive::set_track(const std::shared_ptr<Track> &track) {
	if(disk_) disk_->set_track_at_position(Track::Address(head_, head_position_), track);
}

void Drive::setup_track() {
	track_ = get_track();
	if(!track_) {
		track_.reset(new UnformattedTrack);
	}

	Time offset;
	Time track_time_now = get_time_into_track();
	assert(track_time_now >= Time(0) && current_event_.length <= Time(1));

	Time time_found = track_->seek_to(track_time_now);

	// time_found can be greater than track_time_now if limited precision caused rounding
	if(time_found <= track_time_now) {
		offset = track_time_now - time_found;
	} else {
		offset.set_zero();
	}

	get_next_event(offset);
}

void Drive::invalidate_track() {
	track_ = nullptr;
	if(patched_track_) {
		set_track(patched_track_);
		patched_track_ = nullptr;
	}
}

// MARK: - Writing

void Drive::begin_writing(Time bit_length, bool clamp_to_index_hole) {
	is_reading_ = false;
	clamp_writing_to_index_hole_ = clamp_to_index_hole;

	cycles_per_bit_ = Storage::Time(get_input_clock_rate()) * bit_length;
	cycles_per_bit_.simplify();

	write_segment_.length_of_a_bit = bit_length / rotational_multiplier_;
	write_segment_.data.clear();
	write_segment_.number_of_bits = 0;

	write_start_time_ = get_time_into_track();
}

void Drive::write_bit(bool value) {
	bool needs_new_byte = !(write_segment_.number_of_bits&7);
	if(needs_new_byte) write_segment_.data.push_back(0);
	if(value) write_segment_.data[write_segment_.number_of_bits >> 3] |= 0x80 >> (write_segment_.number_of_bits & 7);
	write_segment_.number_of_bits++;

	cycles_until_bits_written_ += cycles_per_bit_;
}

void Drive::end_writing() {
	if(!is_reading_) {
		is_reading_ = true;

		if(!patched_track_) {
			// Avoid creating a new patched track if this one is already patched
			patched_track_ = std::dynamic_pointer_cast<PCMPatchedTrack>(track_);
			if(!patched_track_) {
				patched_track_.reset(new PCMPatchedTrack(track_));
			}
		}
		patched_track_->add_segment(write_start_time_, write_segment_, clamp_writing_to_index_hole_);
		cycles_since_index_hole_ %= get_input_clock_rate();
		invalidate_track();
	}
}

void Drive::set_activity_observer(Activity::Observer *observer, const std::string &name, bool add_motor_led) {
	observer_ = observer;
	announce_motor_led_ = add_motor_led;
	if(observer) {
		drive_name_ = name;

		observer->register_drive(drive_name_);
		observer->set_drive_motor_status(drive_name_, motor_is_on_);

		if(add_motor_led) {
			observer->register_led(drive_name_);
			observer->set_led_status(drive_name_, motor_is_on_);
		}
	}
}
<|endoftext|>


<commit_before>//
//  Drive.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 25/09/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#ifndef Drive_hpp
#define Drive_hpp

#include <memory>

#include "Disk.hpp"
#include "../../ClockReceiver/Sleeper.hpp"
#include "../TimedEventLoop.hpp"

namespace Storage {
namespace Disk {

class Drive: public Sleeper, public TimedEventLoop {
	public:
		Drive(unsigned int input_clock_rate, int revolutions_per_minute);

		/*!
			Replaces whatever is in the drive with @c disk.
		*/
		void set_disk(const std::shared_ptr<Disk> &disk);

		/*!
			Replaces whatever is in the drive with a disk that contains endless copies of @c track.
		*/
		void set_disk_with_track(const std::shared_ptr<Track> &track);

		/*!
			@returns @c true if a disk is currently inserted; @c false otherwise.
		*/
		bool has_disk();

		/*!
			@returns @c true if the drive head is currently at track zero; @c false otherwise.
		*/
		bool get_is_track_zero();

		/*!
			Steps the disk head the specified number of tracks. Positive numbers step inwards (i.e. away from track 0),
			negative numbers step outwards (i.e. towards track 0).
		*/
		void step(int direction);

		/*!
			Sets the current read head.
		*/
		void set_head(unsigned int head);

		/*!
			@returns @c true if the inserted disk is read-only or no disk is inserted; @c false otherwise.
		*/
		bool get_is_read_only();

		/*!
			@returns the track underneath the current head at the location now stepped to.
		*/
		std::shared_ptr<Track> get_track();

		/*!
			Attempts to set @c track as the track underneath the current head at the location now stepped to.
		*/
		void set_track(const std::shared_ptr<Track> &track);

		/*!
			@returns @c true if the drive is ready; @c false otherwise.
		*/
		bool get_is_ready();

		/*!
			Sets whether the disk motor is on.
		*/
		void set_motor_on(bool);

		/*!
			Advances the drive by @c number_of_cycles cycles.
		*/
		void run_for(const Cycles cycles);

		/*!
			Provides a mechanism to receive track events as they occur.
		*/
		struct EventDelegate {
			virtual void process_event(const Track::Event &event) = 0;
		};

		/// Sets the current event delegate.
		void set_event_delegate(EventDelegate *);

		// As per Sleeper.
		bool is_sleeping();

	private:
		std::shared_ptr<Track> track_;
		std::shared_ptr<Disk> disk_;
		int cycles_since_index_hole_ = 0;
		Time rotational_multiplier_;

		bool has_disk_ = false;

		int head_position_ = 0;
		unsigned int head_ = 0;

		void process_next_event();
		void get_next_event(const Time &duration_already_passed);
		Track::Event current_event_;
		bool motor_is_on_ = false;

		Time get_time_into_track();
		EventDelegate *event_delegate_ = nullptr;
};

}
}

#endif /* Drive_hpp */
<commit_msg>Introduces necessary storage and interface for writing.<commit_after>//
//  Drive.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 25/09/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#ifndef Drive_hpp
#define Drive_hpp

#include "Disk.hpp"
#include "PCMSegment.hpp"
#include "PCMPatchedTrack.hpp"

#include "../TimedEventLoop.hpp"
#include "../../ClockReceiver/Sleeper.hpp"

#include <memory>

namespace Storage {
namespace Disk {

class Drive: public Sleeper, public TimedEventLoop {
	public:
		Drive(unsigned int input_clock_rate, int revolutions_per_minute);

		/*!
			Replaces whatever is in the drive with @c disk.
		*/
		void set_disk(const std::shared_ptr<Disk> &disk);

		/*!
			Replaces whatever is in the drive with a disk that contains endless copies of @c track.
		*/
		void set_disk_with_track(const std::shared_ptr<Track> &track);

		/*!
			@returns @c true if a disk is currently inserted; @c false otherwise.
		*/
		bool has_disk();

		/*!
			@returns @c true if the drive head is currently at track zero; @c false otherwise.
		*/
		bool get_is_track_zero();

		/*!
			Steps the disk head the specified number of tracks. Positive numbers step inwards (i.e. away from track 0),
			negative numbers step outwards (i.e. towards track 0).
		*/
		void step(int direction);

		/*!
			Sets the current read head.
		*/
		void set_head(unsigned int head);

		/*!
			@returns @c true if the inserted disk is read-only or no disk is inserted; @c false otherwise.
		*/
		bool get_is_read_only();

		/*!
			@returns the track underneath the current head at the location now stepped to.
		*/
		std::shared_ptr<Track> get_track();

		/*!
			Attempts to set @c track as the track underneath the current head at the location now stepped to.
		*/
		void set_track(const std::shared_ptr<Track> &track);

		/*!
			@returns @c true if the drive is ready; @c false otherwise.
		*/
		bool get_is_ready();

		/*!
			Sets whether the disk motor is on.
		*/
		void set_motor_on(bool);

		/*!
			@returns @c true if the motor is on; @c false otherwise.
		*/
		bool get_motor_on();

		/*!
			Begins write mode, initiating a PCM sampled region of data. Bits should be written via
			@c write_bit. They will be written with the length set via @c set_expected_bit_length.
			It is acceptable to supply a backlog of bits. Flux transition events will not be reported
			while writing.

			@param clamp_to_index_hole If @c true then writing will automatically be truncated by
			the index hole. Writing will continue over the index hole otherwise.
		*/
		void begin_writing(bool clamp_to_index_hole);

		/*!
			Writes the bit @c value as the next in the PCM stream initiated by @c begin_writing.
		*/
		void write_bit(bool value);

		/*!
			Ends write mode, switching back to read mode. The drive will stop overwriting events.
		*/
		void end_writing();

		/*!
			Advances the drive by @c number_of_cycles cycles.
		*/
		void run_for(const Cycles cycles);

		/*!
			Provides a mechanism to receive track events as they occur, including the synthetic
			event of "you told me to output the following data, and I've done that now".
		*/
		struct EventDelegate {
			/// Informs the delegate that @c event has been reached.
			virtual void process_event(const Track::Event &event) = 0;

			/*!
				If the drive is in write mode, announces that all queued bits have now been written.
				If the controller provides further bits now then there will be no gap in written data.
			*/
			virtual void process_write_completed() {}
		};

		/// Sets the current event delegate.
		void set_event_delegate(EventDelegate *);

		// As per Sleeper.
		bool is_sleeping();

	private:
		// Drives [usually] contain an entire disk; from that a certain track
		// will be currently under the head.
		std::shared_ptr<Disk> disk_;
		std::shared_ptr<Track> track_;
		bool has_disk_ = false;

		// Contains the multiplier that converts between track-relative lengths
		// to real-time lengths — so it's the reciprocal of rotation speed.
		Time rotational_multiplier_;

		// A count of time since the index hole was last seen. Which is used to
		// determine how far the drive is into a full rotation when switching to
		// a new track.
		int cycles_since_index_hole_ = 0;

		// A record of head position and active head.
		int head_position_ = 0;
		unsigned int head_ = 0;

		// Motor control state.
		bool motor_is_on_ = false;

		// If the drive is not currently reading then it is writing. While writing
		// it can optionally be told to clamp to the index hole.
		bool is_reading_;
		bool clamp_writing_to_index_hole_;

		// If writing is occurring then the drive will be accumulating a write segment,
		// for addition to a patched track.
		std::shared_ptr<PCMPatchedTrack> patched_track_;
		PCMSegment write_segment_;
		Time write_start_time_;

		// Maintains appropriate counting to know when to indicate that writing
		// is complete.
		Time cycles_until_bits_written_;
		Time cycles_per_bit_;

		// TimedEventLoop call-ins and state.
		void process_next_event();
		void get_next_event(const Time &duration_already_passed);
		Track::Event current_event_;

		// Helper for track changes.
		Time get_time_into_track();

		// The target (if any) for track events.
		EventDelegate *event_delegate_ = nullptr;
};

}
}

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


<commit_before>#include "generator/regions/admin_suburbs_marker.hpp"

#include "generator/regions/region.hpp"

namespace generator
{
namespace regions
{
void AdminSuburbsMarker::MarkSuburbs(Node::Ptr & tree)
{
  auto const & region = tree->GetData();
  if (region.GetLevel() == PlaceLevel::Locality)
  {
    MarkLocality(tree);
    return;
  }

  for (auto & subtree : tree->GetChildren())
    MarkSuburbs(subtree);
}

void AdminSuburbsMarker::MarkLocality(Node::Ptr & tree)
{
  ASSERT_EQUAL(tree->GetData().GetLevel(), PlaceLevel::Locality, ());
  for (auto & subtree : tree->GetChildren())
    MarkSuburbsInLocality(subtree);
}

void AdminSuburbsMarker::MarkSuburbsInLocality(Node::Ptr & tree)
{
  auto & region = tree->GetData();
  if (region.GetLevel() == PlaceLevel::Locality)
  {
    MarkLocality(tree);
    return;
  }

  if (region.GetAdminLevel() != AdminLevel::Unknown)
    region.SetLevel(PlaceLevel::Suburb);

  for (auto & subtree : tree->GetChildren())
    MarkUnderLocalityAsSublocalities(subtree);
}

void AdminSuburbsMarker::MarkUnderLocalityAsSublocalities(Node::Ptr & tree)
{
  auto & region = tree->GetData();
  auto const level = region.GetLevel();
  if (level == PlaceLevel::Locality)
  {
    MarkLocality(tree);
    return;
  }

  if (level == PlaceLevel::Suburb)
    region.SetLevel(PlaceLevel::Sublocality);
  else if (level == PlaceLevel::Unknown && region.GetAdminLevel() != AdminLevel::Unknown)
    region.SetLevel(PlaceLevel::Sublocality);

  for (auto & subtree : tree->GetChildren())
    MarkUnderLocalityAsSublocalities(subtree);
}
}  // namespace regions
}  // namespace generator
<commit_msg>[generator:regions] Fix debug compile<commit_after>#include "generator/regions/admin_suburbs_marker.hpp"

#include "generator/regions/region.hpp"

namespace generator
{
namespace regions
{
void AdminSuburbsMarker::MarkSuburbs(Node::Ptr & tree)
{
  auto const & region = tree->GetData();
  if (region.GetLevel() == PlaceLevel::Locality)
  {
    MarkLocality(tree);
    return;
  }

  for (auto & subtree : tree->GetChildren())
    MarkSuburbs(subtree);
}

void AdminSuburbsMarker::MarkLocality(Node::Ptr & tree)
{
  ASSERT(tree->GetData().GetLevel() == PlaceLevel::Locality, ());
  for (auto & subtree : tree->GetChildren())
    MarkSuburbsInLocality(subtree);
}

void AdminSuburbsMarker::MarkSuburbsInLocality(Node::Ptr & tree)
{
  auto & region = tree->GetData();
  if (region.GetLevel() == PlaceLevel::Locality)
  {
    MarkLocality(tree);
    return;
  }

  if (region.GetAdminLevel() != AdminLevel::Unknown)
    region.SetLevel(PlaceLevel::Suburb);

  for (auto & subtree : tree->GetChildren())
    MarkUnderLocalityAsSublocalities(subtree);
}

void AdminSuburbsMarker::MarkUnderLocalityAsSublocalities(Node::Ptr & tree)
{
  auto & region = tree->GetData();
  auto const level = region.GetLevel();
  if (level == PlaceLevel::Locality)
  {
    MarkLocality(tree);
    return;
  }

  if (level == PlaceLevel::Suburb)
    region.SetLevel(PlaceLevel::Sublocality);
  else if (level == PlaceLevel::Unknown && region.GetAdminLevel() != AdminLevel::Unknown)
    region.SetLevel(PlaceLevel::Sublocality);

  for (auto & subtree : tree->GetChildren())
    MarkUnderLocalityAsSublocalities(subtree);
}
}  // namespace regions
}  // namespace generator
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: expfld.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 08:01:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _EXPFLD_HXX
#define _EXPFLD_HXX

#ifndef _SVARRAY_HXX //autogen
#include <svtools/svarray.hxx>
#endif

#ifndef INCLUDED_SWDLLAPI_H
#include "swdllapi.h"
#endif
#ifndef _FLDBAS_HXX
#include <fldbas.hxx>
#endif
#ifndef _CELLFML_HXX
#include <cellfml.hxx>
#endif

class SfxPoolItem;
class SwTxtNode;
class SwFrm;
struct SwPosition;
class SwTxtFld;
class SwDoc;
class SwFmtFld;
class _SetGetExpFlds;
class SwEditShell;

// Vorwaertsdeklaration: besorge den "Body-TextNode", fuer Exp.Fld in Fly's
//                      Header/Footers/Footnodes
const SwTxtNode* GetBodyTxtNode( const SwDoc& pDoc, SwPosition& rPos,
                                 const SwFrm& rFrm );
// Wandlung Address -> Adressen
void ReplacePoint(String& sTmpName, BOOL bWithCommandType = FALSE);

struct _SeqFldLstElem
{
    String sDlgEntry;
    USHORT nSeqNo;

    _SeqFldLstElem( const String& rStr, USHORT nNo )
        : sDlgEntry( rStr ), nSeqNo( nNo )
    {}
};
SV_DECL_PTRARR_DEL( _SwSeqFldList, _SeqFldLstElem*, 10, 10 )

class SW_DLLPUBLIC SwSeqFldList : public _SwSeqFldList
{
public:
    SwSeqFldList()  : _SwSeqFldList( 10, 10 ) {}

    BOOL InsertSort( _SeqFldLstElem* );
    BOOL SeekEntry( const _SeqFldLstElem& , USHORT* pPos = 0 );
};

/*--------------------------------------------------------------------
    Beschreibung: Ausdruck
 --------------------------------------------------------------------*/

class SwGetExpFieldType : public SwValueFieldType
{
public:
        SwGetExpFieldType(SwDoc* pDoc);
        virtual SwFieldType*    Copy() const;

        // ueberlagert, weil das Get-Field nicht veraendert werden kann
        // und dann auch nicht aktualisiert werden muss. Aktualisierung
        // erfolgt beim Aendern von Set-Werten !

        virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew );
};

/*--------------------------------------------------------------------
    Beschreibung: GetExperession
 --------------------------------------------------------------------*/

class SwGetExpField : public SwFormulaField
{
    String          sExpand;
    BOOL            bIsInBodyTxt;
    USHORT          nSubType;

public:
    SwGetExpField( SwGetExpFieldType*, const String& rFormel,
                   USHORT nSubType = nsSwGetSetExpType::GSE_EXPR, ULONG nFmt = 0);

    virtual void                SetValue( const double& rVal );
    virtual void                SetLanguage(USHORT nLng);

    virtual String              Expand() const;
    virtual SwField*            Copy() const;

    inline const String&        GetExpStr() const;
    inline void                 ChgExpStr(const String& rExpand);

    // wird von der Formatierung abgefragt
    inline BOOL                 IsInBodyTxt() const;
    // wird von UpdateExpFlds gesetzt (dort ist die Node-Position bekannt)
    inline void                 ChgBodyTxtFlag( BOOL bIsInBody );
    // fuer Felder in Header/Footer/Footnotes/Flys:
    // (wird nur von der Formatierung aufgerufen!!)
    void                        ChangeExpansion( const SwFrm&, const SwTxtFld& );

    virtual String              GetCntnt(BOOL bName = FALSE) const;

    // Die Formel aendern
    virtual String              GetPar2() const;
    virtual void                SetPar2(const String& rStr);

    virtual USHORT              GetSubType() const;
    virtual void                SetSubType(USHORT nType);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );

    static USHORT       GetReferenceTextPos( const SwFmtFld& rFmt, SwDoc& rDoc);
};

inline void SwGetExpField::ChgExpStr(const String& rExpand)
    { sExpand = rExpand;}

inline const String& SwGetExpField::GetExpStr() const
    { return sExpand;   }

// wird von der Formatierung abgefragt
inline BOOL SwGetExpField::IsInBodyTxt() const
    { return bIsInBodyTxt; }

// wird von UpdateExpFlds gesetzt (dort ist die Node-Position bekannt)
inline void SwGetExpField::ChgBodyTxtFlag( BOOL bIsInBody )
    { bIsInBodyTxt = bIsInBody; }

/*--------------------------------------------------------------------
    Beschreibung: Ausdruck setzen
 --------------------------------------------------------------------*/

class SwSetExpField;

class SW_DLLPUBLIC SwSetExpFieldType : public SwValueFieldType
{
    String      sName;
    const SwNode* pOutlChgNd;
//  sal_Unicode cDelim;
    String      sDelim;
    USHORT      nType;
    BYTE        nLevel;
    BOOL        bDeleted;

public:
    SwSetExpFieldType( SwDoc* pDoc, const String& rName,
                        USHORT nType = nsSwGetSetExpType::GSE_EXPR );
    virtual SwFieldType*    Copy() const;
    virtual const String&   GetName() const;

    inline void             SetType(USHORT nTyp);
    inline USHORT           GetType() const;

    void                    SetSeqFormat(ULONG nFormat);
    ULONG                   GetSeqFormat();

    BOOL                    IsDeleted() const       { return bDeleted; }
    void                    SetDeleted( BOOL b )    { bDeleted = b; }

    // ueberlagert, weil das Set-Field selbst dafuer sorgt, das
    // es aktualisiert wird.
    virtual void            Modify( SfxPoolItem *pOld, SfxPoolItem *pNew );
    inline const String&    GetSetRefName() const;

    USHORT SetSeqRefNo( SwSetExpField& rFld );

    USHORT GetSeqFldList( SwSeqFldList& rList );
    String MakeSeqName( USHORT nSeqNo );

    // Seqencefelder ggfs. Kapitelweise numerieren
//  sal_Unicode GetDelimiter() const        { return cDelim; }
//  void SetDelimiter( sal_Unicode c )      { cDelim = c; }
    const String& GetDelimiter() const      { return sDelim; }
    void SetDelimiter( const String& s )    { sDelim = s; }
    BYTE GetOutlineLvl() const              { return nLevel; }
    void SetOutlineLvl( BYTE n )            { nLevel = n; }
    void SetChapter( SwSetExpField& rFld, const SwNode& rNd );
    // Member nur fuers SwDoc::UpdateExpFld - wird nur waehrend der Laufzeit
    // von SequencefeldTypen benoetigt!!!
    const SwNode* GetOutlineChgNd() const   { return pOutlChgNd; }
    void SetOutlineChgNd( const SwNode* p ) { pOutlChgNd = p; }

    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

inline void SwSetExpFieldType::SetType( USHORT nTyp )
{
        nType = nTyp;
        EnableFormat( !(nType & (nsSwGetSetExpType::GSE_SEQ|nsSwGetSetExpType::GSE_STRING)));
}

inline USHORT SwSetExpFieldType::GetType() const
    { return nType;   }

inline const String& SwSetExpFieldType::GetSetRefName() const
    { return sName; }

/*--------------------------------------------------------------------
    Beschreibung: Ausdruck
 --------------------------------------------------------------------*/

class SwSetExpField : public SwFormulaField
{
    String          sExpand;
    String          aPText;
    String          aSeqText;
    BOOL            bInput;
    USHORT          nSeqNo;
    USHORT          nSubType;

public:
    SwSetExpField(SwSetExpFieldType*, const String& rFormel, ULONG nFmt = 0);

    virtual void                SetValue( const double& rVal );

    virtual String              Expand() const;
    virtual SwField*            Copy() const;

    inline const String&        GetExpStr() const;

    inline void                 ChgExpStr( const String& rExpand );

    inline void                 SetPromptText(const String& rStr);
    inline const                String& GetPromptText() const;

    inline void                 SetInputFlag(BOOL bInp);
    inline BOOL                 GetInputFlag() const;

    virtual String              GetCntnt(BOOL bName = FALSE) const;
    virtual USHORT              GetSubType() const;
    virtual void                SetSubType(USHORT nType);

    inline BOOL                 IsSequenceFld() const;

    // fuer SequenceFelder - logische Nummer
    inline void                 SetSeqNumber( USHORT n )    { nSeqNo = n; }
    inline USHORT               GetSeqNumber() const        { return nSeqNo; }

    // Der Name nur erfragen
    virtual const String&       GetPar1()   const;

    // Die Formel
    virtual String              GetPar2()   const;
    virtual void                SetPar2(const String& rStr);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

inline const String& SwSetExpField::GetExpStr() const
    { return sExpand;       }

inline void SwSetExpField::ChgExpStr( const String& rExpand )
    { sExpand = rExpand;    }

inline void  SwSetExpField::SetPromptText(const String& rStr)
    { aPText = rStr;        }

inline const String& SwSetExpField::GetPromptText() const
    { return aPText;        }

inline void SwSetExpField::SetInputFlag(BOOL bInp)
    { bInput = bInp; }

inline BOOL SwSetExpField::GetInputFlag() const
    { return bInput; }

inline BOOL SwSetExpField::IsSequenceFld() const
    { return 0 != (nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)GetTyp())->GetType()); }

/*--------------------------------------------------------------------
    Beschreibung: Eingabe im Text/Variable setzen
 --------------------------------------------------------------------*/

class SwInputFieldType : public SwFieldType
{
    SwDoc* pDoc;
public:
    SwInputFieldType( SwDoc* pDoc );

    virtual SwFieldType* Copy() const;

    SwDoc* GetDoc() const { return pDoc; }
};

/*--------------------------------------------------------------------
    Beschreibung: Eingabefeld
 --------------------------------------------------------------------*/

class SwInputField : public SwField
{
    String  aContent;
    String  aPText;
    String  aHelp;
    String  aToolTip;
    USHORT  nSubType;
public:
    // Direkte Eingabe ueber Dialog alten Wert loeschen
    SwInputField(SwInputFieldType*, const String& rContent ,
                 const String& rPrompt, USHORT nSubType = 0,
                 ULONG nFmt = 0);

    virtual String          GetCntnt(BOOL bName = FALSE) const;
    virtual String          Expand() const;
    virtual SwField*        Copy() const;

    // Content
    virtual const String&   GetPar1() const;
    virtual void            SetPar1(const String& rStr);

    // aPromptText
    virtual String          GetPar2() const;
    virtual void            SetPar2(const String& rStr);

    virtual String          GetHelp() const;
    virtual void            SetHelp(const String & rStr);

    virtual String          GetToolTip() const;
    virtual void            SetToolTip(const String & rStr);

    virtual BOOL            isFormField() const;

    virtual USHORT          GetSubType() const;
    virtual void            SetSubType(USHORT nSub);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

/*--------------------------------------------------------------------
    Description: Sorted list of input fields and DropDown fields
 --------------------------------------------------------------------*/

class SwInputFieldList
{
public:
    SwInputFieldList( SwEditShell* pShell, BOOL bBuildTmpLst = FALSE );
    ~SwInputFieldList();

    USHORT      Count() const;
    SwField*    GetField(USHORT nId);

    void        GotoFieldPos(USHORT nId);
    void        PushCrsr();
    void        PopCrsr();

    // vergleiche TmpLst mit akt Feldern. Alle neue kommen in die SortLst
    // damit sie geupdatet werden koennen. Returnt die Anzahl.
    // (Fuer Textbausteine: nur seine Input-Felder aktualisieren)
    USHORT      BuildSortLst();

    // Alle unselektierten Felder aus Liste entfernen
    void        RemoveUnselectedFlds();

private:
    SwEditShell*    pSh;
    _SetGetExpFlds* pSrtLst;
    SvPtrarr        aTmpLst;
};

/*--------------------------------------------------------------------
    Beschreibung: Tabellen-Formelfeld
                  (Implementierung steht in tblcalc.cxx)
 --------------------------------------------------------------------*/

class SwTblFieldType : public SwValueFieldType
{
public:
    SwTblFieldType(SwDoc* pDocPtr);
    virtual SwFieldType* Copy() const;
};

// MSC will den hier nicht
//typedef void (SwField:: *FnScanFormel)( const SwTable&, String&,
//                                   String&, String* = 0, void* = 0 );

class SwTblField : public SwValueField, public SwTableFormula
{
    String      sExpand;
    USHORT      nSubType;

    // suche den TextNode, in dem das Feld steht
    virtual const SwNode* GetNodeOfFormula() const;

public:
    SwTblField( SwTblFieldType*, const String& rFormel,
                USHORT nSubType = 0, ULONG nFmt = 0);

    virtual void        SetValue( const double& rVal );
    virtual USHORT      GetSubType() const;
    virtual void        SetSubType(USHORT nType);
    virtual String      Expand() const;
    virtual SwField*    Copy() const;

    const String&       GetExpStr() const               { return sExpand; }
    void                ChgExpStr(const String& rStr)   { sExpand = rStr; }

    // berechne sich selbst
    void                CalcField( SwTblCalcPara& rCalcPara );

    virtual String      GetCntnt(BOOL bName = FALSE) const;
    // Die Formel
    virtual String      GetPar2()   const;
    virtual void        SetPar2(const String& rStr);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

#endif // _EXPFLD_HXX
<commit_msg>INTEGRATION: CWS changefileheader (1.10.242); FILE MERGED 2008/04/01 15:56:10 thb 1.10.242.3: #i85898# Stripping all external header guards 2008/04/01 12:53:28 thb 1.10.242.2: #i85898# Stripping all external header guards 2008/03/31 16:52:36 rt 1.10.242.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: expfld.hxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _EXPFLD_HXX
#define _EXPFLD_HXX

#include <svtools/svarray.hxx>
#include "swdllapi.h"
#include <fldbas.hxx>
#include <cellfml.hxx>

class SfxPoolItem;
class SwTxtNode;
class SwFrm;
struct SwPosition;
class SwTxtFld;
class SwDoc;
class SwFmtFld;
class _SetGetExpFlds;
class SwEditShell;

// Vorwaertsdeklaration: besorge den "Body-TextNode", fuer Exp.Fld in Fly's
//                      Header/Footers/Footnodes
const SwTxtNode* GetBodyTxtNode( const SwDoc& pDoc, SwPosition& rPos,
                                 const SwFrm& rFrm );
// Wandlung Address -> Adressen
void ReplacePoint(String& sTmpName, BOOL bWithCommandType = FALSE);

struct _SeqFldLstElem
{
    String sDlgEntry;
    USHORT nSeqNo;

    _SeqFldLstElem( const String& rStr, USHORT nNo )
        : sDlgEntry( rStr ), nSeqNo( nNo )
    {}
};
SV_DECL_PTRARR_DEL( _SwSeqFldList, _SeqFldLstElem*, 10, 10 )

class SW_DLLPUBLIC SwSeqFldList : public _SwSeqFldList
{
public:
    SwSeqFldList()  : _SwSeqFldList( 10, 10 ) {}

    BOOL InsertSort( _SeqFldLstElem* );
    BOOL SeekEntry( const _SeqFldLstElem& , USHORT* pPos = 0 );
};

/*--------------------------------------------------------------------
    Beschreibung: Ausdruck
 --------------------------------------------------------------------*/

class SwGetExpFieldType : public SwValueFieldType
{
public:
        SwGetExpFieldType(SwDoc* pDoc);
        virtual SwFieldType*    Copy() const;

        // ueberlagert, weil das Get-Field nicht veraendert werden kann
        // und dann auch nicht aktualisiert werden muss. Aktualisierung
        // erfolgt beim Aendern von Set-Werten !

        virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew );
};

/*--------------------------------------------------------------------
    Beschreibung: GetExperession
 --------------------------------------------------------------------*/

class SwGetExpField : public SwFormulaField
{
    String          sExpand;
    BOOL            bIsInBodyTxt;
    USHORT          nSubType;

public:
    SwGetExpField( SwGetExpFieldType*, const String& rFormel,
                   USHORT nSubType = nsSwGetSetExpType::GSE_EXPR, ULONG nFmt = 0);

    virtual void                SetValue( const double& rVal );
    virtual void                SetLanguage(USHORT nLng);

    virtual String              Expand() const;
    virtual SwField*            Copy() const;

    inline const String&        GetExpStr() const;
    inline void                 ChgExpStr(const String& rExpand);

    // wird von der Formatierung abgefragt
    inline BOOL                 IsInBodyTxt() const;
    // wird von UpdateExpFlds gesetzt (dort ist die Node-Position bekannt)
    inline void                 ChgBodyTxtFlag( BOOL bIsInBody );
    // fuer Felder in Header/Footer/Footnotes/Flys:
    // (wird nur von der Formatierung aufgerufen!!)
    void                        ChangeExpansion( const SwFrm&, const SwTxtFld& );

    virtual String              GetCntnt(BOOL bName = FALSE) const;

    // Die Formel aendern
    virtual String              GetPar2() const;
    virtual void                SetPar2(const String& rStr);

    virtual USHORT              GetSubType() const;
    virtual void                SetSubType(USHORT nType);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );

    static USHORT       GetReferenceTextPos( const SwFmtFld& rFmt, SwDoc& rDoc);
};

inline void SwGetExpField::ChgExpStr(const String& rExpand)
    { sExpand = rExpand;}

inline const String& SwGetExpField::GetExpStr() const
    { return sExpand;   }

// wird von der Formatierung abgefragt
inline BOOL SwGetExpField::IsInBodyTxt() const
    { return bIsInBodyTxt; }

// wird von UpdateExpFlds gesetzt (dort ist die Node-Position bekannt)
inline void SwGetExpField::ChgBodyTxtFlag( BOOL bIsInBody )
    { bIsInBodyTxt = bIsInBody; }

/*--------------------------------------------------------------------
    Beschreibung: Ausdruck setzen
 --------------------------------------------------------------------*/

class SwSetExpField;

class SW_DLLPUBLIC SwSetExpFieldType : public SwValueFieldType
{
    String      sName;
    const SwNode* pOutlChgNd;
//  sal_Unicode cDelim;
    String      sDelim;
    USHORT      nType;
    BYTE        nLevel;
    BOOL        bDeleted;

public:
    SwSetExpFieldType( SwDoc* pDoc, const String& rName,
                        USHORT nType = nsSwGetSetExpType::GSE_EXPR );
    virtual SwFieldType*    Copy() const;
    virtual const String&   GetName() const;

    inline void             SetType(USHORT nTyp);
    inline USHORT           GetType() const;

    void                    SetSeqFormat(ULONG nFormat);
    ULONG                   GetSeqFormat();

    BOOL                    IsDeleted() const       { return bDeleted; }
    void                    SetDeleted( BOOL b )    { bDeleted = b; }

    // ueberlagert, weil das Set-Field selbst dafuer sorgt, das
    // es aktualisiert wird.
    virtual void            Modify( SfxPoolItem *pOld, SfxPoolItem *pNew );
    inline const String&    GetSetRefName() const;

    USHORT SetSeqRefNo( SwSetExpField& rFld );

    USHORT GetSeqFldList( SwSeqFldList& rList );
    String MakeSeqName( USHORT nSeqNo );

    // Seqencefelder ggfs. Kapitelweise numerieren
//  sal_Unicode GetDelimiter() const        { return cDelim; }
//  void SetDelimiter( sal_Unicode c )      { cDelim = c; }
    const String& GetDelimiter() const      { return sDelim; }
    void SetDelimiter( const String& s )    { sDelim = s; }
    BYTE GetOutlineLvl() const              { return nLevel; }
    void SetOutlineLvl( BYTE n )            { nLevel = n; }
    void SetChapter( SwSetExpField& rFld, const SwNode& rNd );
    // Member nur fuers SwDoc::UpdateExpFld - wird nur waehrend der Laufzeit
    // von SequencefeldTypen benoetigt!!!
    const SwNode* GetOutlineChgNd() const   { return pOutlChgNd; }
    void SetOutlineChgNd( const SwNode* p ) { pOutlChgNd = p; }

    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

inline void SwSetExpFieldType::SetType( USHORT nTyp )
{
        nType = nTyp;
        EnableFormat( !(nType & (nsSwGetSetExpType::GSE_SEQ|nsSwGetSetExpType::GSE_STRING)));
}

inline USHORT SwSetExpFieldType::GetType() const
    { return nType;   }

inline const String& SwSetExpFieldType::GetSetRefName() const
    { return sName; }

/*--------------------------------------------------------------------
    Beschreibung: Ausdruck
 --------------------------------------------------------------------*/

class SwSetExpField : public SwFormulaField
{
    String          sExpand;
    String          aPText;
    String          aSeqText;
    BOOL            bInput;
    USHORT          nSeqNo;
    USHORT          nSubType;

public:
    SwSetExpField(SwSetExpFieldType*, const String& rFormel, ULONG nFmt = 0);

    virtual void                SetValue( const double& rVal );

    virtual String              Expand() const;
    virtual SwField*            Copy() const;

    inline const String&        GetExpStr() const;

    inline void                 ChgExpStr( const String& rExpand );

    inline void                 SetPromptText(const String& rStr);
    inline const                String& GetPromptText() const;

    inline void                 SetInputFlag(BOOL bInp);
    inline BOOL                 GetInputFlag() const;

    virtual String              GetCntnt(BOOL bName = FALSE) const;
    virtual USHORT              GetSubType() const;
    virtual void                SetSubType(USHORT nType);

    inline BOOL                 IsSequenceFld() const;

    // fuer SequenceFelder - logische Nummer
    inline void                 SetSeqNumber( USHORT n )    { nSeqNo = n; }
    inline USHORT               GetSeqNumber() const        { return nSeqNo; }

    // Der Name nur erfragen
    virtual const String&       GetPar1()   const;

    // Die Formel
    virtual String              GetPar2()   const;
    virtual void                SetPar2(const String& rStr);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

inline const String& SwSetExpField::GetExpStr() const
    { return sExpand;       }

inline void SwSetExpField::ChgExpStr( const String& rExpand )
    { sExpand = rExpand;    }

inline void  SwSetExpField::SetPromptText(const String& rStr)
    { aPText = rStr;        }

inline const String& SwSetExpField::GetPromptText() const
    { return aPText;        }

inline void SwSetExpField::SetInputFlag(BOOL bInp)
    { bInput = bInp; }

inline BOOL SwSetExpField::GetInputFlag() const
    { return bInput; }

inline BOOL SwSetExpField::IsSequenceFld() const
    { return 0 != (nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)GetTyp())->GetType()); }

/*--------------------------------------------------------------------
    Beschreibung: Eingabe im Text/Variable setzen
 --------------------------------------------------------------------*/

class SwInputFieldType : public SwFieldType
{
    SwDoc* pDoc;
public:
    SwInputFieldType( SwDoc* pDoc );

    virtual SwFieldType* Copy() const;

    SwDoc* GetDoc() const { return pDoc; }
};

/*--------------------------------------------------------------------
    Beschreibung: Eingabefeld
 --------------------------------------------------------------------*/

class SwInputField : public SwField
{
    String  aContent;
    String  aPText;
    String  aHelp;
    String  aToolTip;
    USHORT  nSubType;
public:
    // Direkte Eingabe ueber Dialog alten Wert loeschen
    SwInputField(SwInputFieldType*, const String& rContent ,
                 const String& rPrompt, USHORT nSubType = 0,
                 ULONG nFmt = 0);

    virtual String          GetCntnt(BOOL bName = FALSE) const;
    virtual String          Expand() const;
    virtual SwField*        Copy() const;

    // Content
    virtual const String&   GetPar1() const;
    virtual void            SetPar1(const String& rStr);

    // aPromptText
    virtual String          GetPar2() const;
    virtual void            SetPar2(const String& rStr);

    virtual String          GetHelp() const;
    virtual void            SetHelp(const String & rStr);

    virtual String          GetToolTip() const;
    virtual void            SetToolTip(const String & rStr);

    virtual BOOL            isFormField() const;

    virtual USHORT          GetSubType() const;
    virtual void            SetSubType(USHORT nSub);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

/*--------------------------------------------------------------------
    Description: Sorted list of input fields and DropDown fields
 --------------------------------------------------------------------*/

class SwInputFieldList
{
public:
    SwInputFieldList( SwEditShell* pShell, BOOL bBuildTmpLst = FALSE );
    ~SwInputFieldList();

    USHORT      Count() const;
    SwField*    GetField(USHORT nId);

    void        GotoFieldPos(USHORT nId);
    void        PushCrsr();
    void        PopCrsr();

    // vergleiche TmpLst mit akt Feldern. Alle neue kommen in die SortLst
    // damit sie geupdatet werden koennen. Returnt die Anzahl.
    // (Fuer Textbausteine: nur seine Input-Felder aktualisieren)
    USHORT      BuildSortLst();

    // Alle unselektierten Felder aus Liste entfernen
    void        RemoveUnselectedFlds();

private:
    SwEditShell*    pSh;
    _SetGetExpFlds* pSrtLst;
    SvPtrarr        aTmpLst;
};

/*--------------------------------------------------------------------
    Beschreibung: Tabellen-Formelfeld
                  (Implementierung steht in tblcalc.cxx)
 --------------------------------------------------------------------*/

class SwTblFieldType : public SwValueFieldType
{
public:
    SwTblFieldType(SwDoc* pDocPtr);
    virtual SwFieldType* Copy() const;
};

// MSC will den hier nicht
//typedef void (SwField:: *FnScanFormel)( const SwTable&, String&,
//                                   String&, String* = 0, void* = 0 );

class SwTblField : public SwValueField, public SwTableFormula
{
    String      sExpand;
    USHORT      nSubType;

    // suche den TextNode, in dem das Feld steht
    virtual const SwNode* GetNodeOfFormula() const;

public:
    SwTblField( SwTblFieldType*, const String& rFormel,
                USHORT nSubType = 0, ULONG nFmt = 0);

    virtual void        SetValue( const double& rVal );
    virtual USHORT      GetSubType() const;
    virtual void        SetSubType(USHORT nType);
    virtual String      Expand() const;
    virtual SwField*    Copy() const;

    const String&       GetExpStr() const               { return sExpand; }
    void                ChgExpStr(const String& rStr)   { sExpand = rStr; }

    // berechne sich selbst
    void                CalcField( SwTblCalcPara& rCalcPara );

    virtual String      GetCntnt(BOOL bName = FALSE) const;
    // Die Formel
    virtual String      GetPar2()   const;
    virtual void        SetPar2(const String& rStr);
    virtual BOOL        QueryValue( com::sun::star::uno::Any& rVal, USHORT nWhich ) const;
    virtual BOOL        PutValue( const com::sun::star::uno::Any& rVal, USHORT nWhich );
};

#endif // _EXPFLD_HXX
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XMemory.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/MemoryManager.hpp>
#include <assert.h>

XERCES_CPP_NAMESPACE_BEGIN

//  Calculate alignment required by platform.
//	Total size of our header must match platform
//	architecture-specific alignment, in order
//	that the returned block ptr (which follows our
//	header), maintains block/structure alignment.
inline size_t
CalculateBlockHeaderSize()
{
	//	Macro XML_NEW_BLOCK_ALIGNMENT may be defined
	//	as needed to calculate alignment on a per-architecture
	//	basis.
	#ifdef XML_NEW_BLOCK_ALIGNMENT
		size_t alignment = XML_NEW_BLOCK_ALIGNMENT;
	#else
		size_t alignment = std::max(sizeof(void*), sizeof(double));
	#endif

	size_t headerUsage = sizeof(MemoryManager*);
	return (headerUsage + (alignment - headerUsage % alignment));
}

void* XMemory::operator new(size_t size)
{
	size_t headerSize = CalculateBlockHeaderSize();
    void* const block = XMLPlatformUtils::fgMemoryManager->allocate
        (
	        headerSize + size
        );
    *(MemoryManager**)block = XMLPlatformUtils::fgMemoryManager;

    return (char*)block + headerSize;
}

void* XMemory::operator new(size_t size, MemoryManager* manager)
{
    assert(manager != 0);

	size_t headerSize = CalculateBlockHeaderSize();
    void* const block = manager->allocate(headerSize + size);
    *(MemoryManager**)block = manager;

    return (char*)block + headerSize;
}

void XMemory::operator delete(void* p)
{
    if (p != 0)
    {
		size_t headerSize = CalculateBlockHeaderSize();
        void* const block = (char*)p - headerSize;

        MemoryManager* const manager = *(MemoryManager**)block;
        assert(manager != 0);
        manager->deallocate(block);
    }
}

void XMemory::operator delete(void* p, MemoryManager* manager)
{
    assert(manager != 0);

	if (p != 0)
	{
		size_t headerSize = CalculateBlockHeaderSize();
        void* const block = (char*)p - headerSize;

		assert(*(MemoryManager**)block == manager);
		manager->deallocate(block);
	}
}

XERCES_CPP_NAMESPACE_END

<commit_msg>Removed usage of std to compile under gcc and other platforms.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XMemory.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/MemoryManager.hpp>
#include <assert.h>

XERCES_CPP_NAMESPACE_BEGIN

//  Calculate alignment required by platform.
//	Total size of our header must match platform
//	architecture-specific alignment, in order
//	that the returned block ptr (which follows our
//	header), maintains block/structure alignment.
inline size_t
CalculateBlockHeaderSize()
{
	//	Macro XML_NEW_BLOCK_ALIGNMENT may be defined
	//	as needed to calculate alignment on a per-architecture
	//	basis.
	#ifdef XML_NEW_BLOCK_ALIGNMENT
		size_t alignment = XML_NEW_BLOCK_ALIGNMENT;
	#else
        size_t alignment = sizeof(void*) > sizeof(double) ? sizeof(void*) : sizeof(double);
	#endif

	size_t headerUsage = sizeof(MemoryManager*);
	return (headerUsage + (alignment - headerUsage % alignment));
}

void* XMemory::operator new(size_t size)
{
	size_t headerSize = CalculateBlockHeaderSize();
    void* const block = XMLPlatformUtils::fgMemoryManager->allocate
        (
	        headerSize + size
        );
    *(MemoryManager**)block = XMLPlatformUtils::fgMemoryManager;

    return (char*)block + headerSize;
}

void* XMemory::operator new(size_t size, MemoryManager* manager)
{
    assert(manager != 0);

	size_t headerSize = CalculateBlockHeaderSize();
    void* const block = manager->allocate(headerSize + size);
    *(MemoryManager**)block = manager;

    return (char*)block + headerSize;
}

void XMemory::operator delete(void* p)
{
    if (p != 0)
    {
		size_t headerSize = CalculateBlockHeaderSize();
        void* const block = (char*)p - headerSize;

        MemoryManager* const manager = *(MemoryManager**)block;
        assert(manager != 0);
        manager->deallocate(block);
    }
}

void XMemory::operator delete(void* p, MemoryManager* manager)
{
    assert(manager != 0);

	if (p != 0)
	{
		size_t headerSize = CalculateBlockHeaderSize();
        void* const block = (char*)p - headerSize;

		assert(*(MemoryManager**)block == manager);
		manager->deallocate(block);
	}
}

XERCES_CPP_NAMESPACE_END

<|endoftext|>


<commit_before>/*
Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
/* hash */
#include "serv.h"
#include "net/proc.h"
#include "net/server.h"

int proc_hexists(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    const Bytes &name = req[1];
    const Bytes &key = req[2];
    std::pair<std::string, bool> val;
    int ret = serv->ssdb->hget(name, key, val);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_bool(0);
    } else {
        resp->reply_bool(val.second);
    }

    return 0;
}

int proc_hmset(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    SSDBServer *serv = (SSDBServer *) net->data;
    if (req.size() < 4 || req.size() % 2 != 0) {
        reply_errinfo_return("wrong number of arguments for 'hmset' command");
    }

    std::map<Bytes, Bytes> kvs;
    const Bytes &name = req[1];
    std::vector<Bytes>::const_iterator it = req.begin() + 2;
    for (; it != req.end(); it += 2) {
        const Bytes &key = *it;
        const Bytes &val = *(it + 1);
        kvs[key] = val;
    }

    int ret = serv->ssdb->hmset(name, kvs);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    }

    resp->reply_int(0, 1);

    return 0;
}

int proc_hdel(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    const Bytes &key = req[1];

    std::set<Bytes> fields;
    for (int j = 2; j < req.size(); ++j) {
        fields.insert(req[j]);
    }

    int deleted = 0;
    int ret = serv->ssdb->hdel(key, fields, &deleted);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    }

    resp->reply_int(0, deleted);
    return 0;
}

int proc_hmget(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    Request::const_iterator it = req.begin() + 1;
    const Bytes name = *it;
    it++;

    std::vector<std::string> reqKeys;
    std::map<std::string, std::string> resMap;

    for (; it != req.end(); it += 1) {
        const Bytes &key = *it;
        reqKeys.push_back(key.String());
    }

    int ret = serv->ssdb->hmget(name, reqKeys, resMap);
    check_key(ret);
    if (ret == 1) {
        resp->reply_list_ready();

        for (const auto &reqKey : reqKeys) {

            auto pos = resMap.find(reqKey);
            if (pos == resMap.end()) {
                //
            } else {
                resp->push_back(pos->first);
                resp->push_back(pos->second);
            }

        }

    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        reply_err_return(ret);
    }

    return 0;
}

int proc_hsize(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(2);
    SSDBServer *serv = (SSDBServer *) net->data;

    uint64_t size = 0;
    int ret = serv->ssdb->hsize(req[1], &size);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        resp->reply_int(ret, size);
    }

    return 0;
}

int proc_hset(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(4);
    SSDBServer *serv = (SSDBServer *) net->data;

    int added = 0;
    int ret = serv->ssdb->hset(req[1], req[2], req[3], &added);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_bool(ret);
    } else {
        resp->reply_bool(added);
    }

    return 0;
}

int proc_hsetnx(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(4);
    SSDBServer *serv = (SSDBServer *) net->data;

    int added = 0;
    int ret = serv->ssdb->hsetnx(req[1], req[2], req[3], &added);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_bool(ret);
    } else {
        resp->reply_bool(added);
    }

    return 0;
}

int proc_hget(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    std::pair<std::string, bool> val;
    int ret = serv->ssdb->hget(req[1], req[2], val);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        if (val.second) {
            resp->reply_get(1, &val.first);
        } else {
            resp->reply_get(0, &val.first);
        }
    }

    return 0;
}

int proc_hgetall(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(2);
    SSDBServer *serv = (SSDBServer *) net->data;

    std::map<std::string, std::string> resMap;
    int ret = serv->ssdb->hgetall(req[1], resMap);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        resp->reply_list_ready();

        for (const auto &res : resMap) {
            resp->push_back(res.first);
            resp->push_back(res.second);
        }

    }

    return 0;
}

int proc_hscan(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    int cursorIndex = 2;

    Bytes cursor = req[cursorIndex];

    cursor.Uint64();
    if (errno == EINVAL) {
        reply_err_return(INVALID_INT);
    }

    std::string pattern = "*";
    uint64_t limit = 10;

    std::vector<Bytes>::const_iterator it = req.begin() + cursorIndex + 1;
    for (; it != req.end(); it += 2) {
        std::string key = (*it).String();
        strtolower(&key);

        if (key == "match") {
            pattern = (*(it + 1)).String();
        } else if (key == "count") {
            limit = (*(it + 1)).Uint64();
            if (errno == EINVAL) {
                reply_err_return(INVALID_INT);
            }
        } else {
            reply_err_return(SYNTAX_ERR);
        }
    }
    resp->reply_scan_ready();

    int ret = serv->ssdb->hscan(req[1], cursor, pattern, limit, resp->resp);
    check_key(ret);
    if (ret < 0) {
        resp->resp.clear();
        reply_err_return(ret);
    } else if (ret == 0) {
    }

    return 0;
}

int proc_hkeys(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(5);
    SSDBServer *serv = (SSDBServer *) net->data;

//	uint64_t limit = req[4].Uint64();

    std::map<std::string, std::string> resMap;
    int ret = serv->ssdb->hgetall(req[1], resMap);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        resp->reply_list_ready();

        for (const auto &res : resMap) {
            //TODO 这里同时处理了kv 只是没有返回.
            resp->push_back(res.first);
//            resp->push_back(res.second);
        }
    }

    return 0;
}

int proc_hvals(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(5);
    SSDBServer *serv = (SSDBServer *) net->data;

//	uint64_t limit = req[4].Uint64();

    std::map<std::string, std::string> resMap;
    int ret = serv->ssdb->hgetall(req[1], resMap);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        resp->reply_list_ready();

        for (const auto &res : resMap) {
            //TODO 这里同时处理了kv 只是没有返回.
//            resp->push_back(res.first);
            resp->push_back(res.second);
        }
    }

    return 0;
}

int proc_hincrbyfloat(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    SSDBServer *serv = (SSDBServer *) net->data;
    CHECK_NUM_PARAMS(4);

    long double by = req[3].LDouble();
    if (errno == EINVAL) {
        reply_err_return(INVALID_DBL);
    }

    long double new_val;
    int ret = serv->ssdb->hincrbyfloat(req[1], req[2], by, &new_val);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        resp->reply_long_double(ret, new_val);
    }
    return 0;

}

int proc_hincr(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    SSDBServer *serv = (SSDBServer *) net->data;
    CHECK_NUM_PARAMS(4);

    int64_t by = req[3].Int64();

    if (errno == EINVAL) {
        reply_err_return(INVALID_INT);
    }

    int64_t new_val = 0;
    int ret = serv->ssdb->hincr(req[1], req[2], by, &new_val);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        resp->reply_int(ret, new_val);
    }
    return 0;

}<commit_msg>hash 附加返回值 done<commit_after>/*
Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
/* hash */
#include "serv.h"
#include "net/proc.h"
#include "net/server.h"

int proc_hexists(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    const Bytes &name = req[1];
    const Bytes &key = req[2];
    std::pair<std::string, bool> val;
    int ret = serv->ssdb->hget(name, key, val);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_bool(0);
    } else {
        resp->reply_bool(val.second);
    }

    return 0;
}

int proc_hmset(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    SSDBServer *serv = (SSDBServer *) net->data;
    if (req.size() < 4 || req.size() % 2 != 0) {
        reply_errinfo_return("wrong number of arguments for 'hmset' command");
    }

    std::map<Bytes, Bytes> kvs;
    const Bytes &name = req[1];
    std::vector<Bytes>::const_iterator it = req.begin() + 2;
    for (; it != req.end(); it += 2) {
        const Bytes &key = *it;
        const Bytes &val = *(it + 1);
        kvs[key] = val;
    }

    int ret = serv->ssdb->hmset(name, kvs);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    }

    resp->reply_int(0, 1);

    return 0;
}

int proc_hdel(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    const Bytes &key = req[1];

    std::set<Bytes> fields;
    for (int j = 2; j < req.size(); ++j) {
        fields.insert(req[j]);
    }

    int deleted = 0;
    int ret = serv->ssdb->hdel(key, fields, &deleted);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    }

    resp->reply_int(0, deleted);
    return 0;
}

int proc_hmget(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    Request::const_iterator it = req.begin() + 1;
    const Bytes name = *it;
    it++;

    std::vector<std::string> reqKeys;
    std::map<std::string, std::string> resMap;

    for (; it != req.end(); it += 1) {
        const Bytes &key = *it;
        reqKeys.push_back(key.String());
    }

    int ret = serv->ssdb->hmget(name, reqKeys, resMap);
    check_key(ret);
    if (ret == 1) {
        resp->reply_list_ready();

        for (const auto &reqKey : reqKeys) {

            auto pos = resMap.find(reqKey);
            if (pos == resMap.end()) {
                //
            } else {
                resp->push_back(pos->first);
                resp->push_back(pos->second);
            }

        }

    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        reply_err_return(ret);
    }

    return 0;
}

int proc_hsize(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(2);
    SSDBServer *serv = (SSDBServer *) net->data;

    uint64_t size = 0;
    int ret = serv->ssdb->hsize(req[1], &size);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        resp->reply_int(ret, size);
    }

    return 0;
}

int proc_hset(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(4);
    SSDBServer *serv = (SSDBServer *) net->data;

    int added = 0;
    int ret = serv->ssdb->hset(req[1], req[2], req[3], &added);
//    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_bool(ret);
    } else {
        resp->reply_bool(added);
    }

    return 0;
}

int proc_hsetnx(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(4);
    SSDBServer *serv = (SSDBServer *) net->data;

    int added = 0;
    int ret = serv->ssdb->hsetnx(req[1], req[2], req[3], &added);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_bool(ret);
    } else {
        resp->reply_bool(added);
    }

    return 0;
}

int proc_hget(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    std::pair<std::string, bool> val;
    int ret = serv->ssdb->hget(req[1], req[2], val);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        if (val.second) {
            resp->reply_get(1, &val.first);
        } else {
            resp->reply_get(0, &val.first);
        }
    }

    return 0;
}

int proc_hgetall(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(2);
    SSDBServer *serv = (SSDBServer *) net->data;

    std::map<std::string, std::string> resMap;
    int ret = serv->ssdb->hgetall(req[1], resMap);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        resp->reply_list_ready();

        for (const auto &res : resMap) {
            resp->push_back(res.first);
            resp->push_back(res.second);
        }

    }

    return 0;
}

int proc_hscan(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(3);
    SSDBServer *serv = (SSDBServer *) net->data;

    int cursorIndex = 2;

    Bytes cursor = req[cursorIndex];

    cursor.Uint64();
    if (errno == EINVAL) {
        reply_err_return(INVALID_INT);
    }

    std::string pattern = "*";
    uint64_t limit = 10;

    std::vector<Bytes>::const_iterator it = req.begin() + cursorIndex + 1;
    for (; it != req.end(); it += 2) {
        std::string key = (*it).String();
        strtolower(&key);

        if (key == "match") {
            pattern = (*(it + 1)).String();
        } else if (key == "count") {
            limit = (*(it + 1)).Uint64();
            if (errno == EINVAL) {
                reply_err_return(INVALID_INT);
            }
        } else {
            reply_err_return(SYNTAX_ERR);
        }
    }
    resp->reply_scan_ready();

    int ret = serv->ssdb->hscan(req[1], cursor, pattern, limit, resp->resp);
    check_key(ret);
    if (ret < 0) {
        resp->resp.clear();
        reply_err_return(ret);
    } else if (ret == 0) {
    }

    return 0;
}

int proc_hkeys(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(5);
    SSDBServer *serv = (SSDBServer *) net->data;

//	uint64_t limit = req[4].Uint64();

    std::map<std::string, std::string> resMap;
    int ret = serv->ssdb->hgetall(req[1], resMap);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        resp->reply_list_ready();

        for (const auto &res : resMap) {
            //TODO 这里同时处理了kv 只是没有返回.
            resp->push_back(res.first);
//            resp->push_back(res.second);
        }
    }

    return 0;
}

int proc_hvals(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    CHECK_NUM_PARAMS(5);
    SSDBServer *serv = (SSDBServer *) net->data;

//	uint64_t limit = req[4].Uint64();

    std::map<std::string, std::string> resMap;
    int ret = serv->ssdb->hgetall(req[1], resMap);
    check_key(ret);
    if (ret < 0) {
        reply_err_return(ret);
    } else if (ret == 0) {
        resp->reply_list_ready();

        //nothing
    } else {
        resp->reply_list_ready();

        for (const auto &res : resMap) {
            //TODO 这里同时处理了kv 只是没有返回.
//            resp->push_back(res.first);
            resp->push_back(res.second);
        }
    }

    return 0;
}

int proc_hincrbyfloat(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    SSDBServer *serv = (SSDBServer *) net->data;
    CHECK_NUM_PARAMS(4);

    long double by = req[3].LDouble();
    if (errno == EINVAL) {
        reply_err_return(INVALID_DBL);
    }

    long double new_val;
    int ret = serv->ssdb->hincrbyfloat(req[1], req[2], by, &new_val);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        resp->reply_long_double(ret, new_val);
    }
    return 0;

}

int proc_hincr(NetworkServer *net, Link *link, const Request &req, Response *resp) {
    SSDBServer *serv = (SSDBServer *) net->data;
    CHECK_NUM_PARAMS(4);

    int64_t by = req[3].Int64();

    if (errno == EINVAL) {
        reply_err_return(INVALID_INT);
    }

    int64_t new_val = 0;
    int ret = serv->ssdb->hincr(req[1], req[2], by, &new_val);
    if (ret < 0) {
        reply_err_return(ret);
    } else {
        resp->reply_int(ret, new_val);
    }
    return 0;

}<|endoftext|>