<commit_before>#include "Kontroller/Kontroller.h"
#include "Communicator.h"

#include <CoreMIDI/MIDIServices.h>

#include <string>

struct Kontroller::Communicator::ImplData {
   MIDIClientRef client { 0 };
   MIDIPortRef inputPort { 0 };
   MIDIPortRef outputPort { 0 };
   MIDIEndpointRef destination { 0 };

   union {
      MIDIPacketList list;
      std::array<uint8_t, 512> padding; // Ensure the list has enough space
   };
   MIDIPacket* lastPacket { nullptr };
};

namespace {

// Called on the main thread
void midiNotifyCallback(const MIDINotification *message, void *refCon) {
   if (message->messageID == kMIDIMsgObjectRemoved) {
      const MIDIObjectAddRemoveNotification* notification =
         reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
      Kontroller::Communicator* communicator = reinterpret_cast<Kontroller::Communicator*>(refCon);

      if (notification->child == communicator->getImplData().destination) {
         communicator->onConnectionLost();
      }
   }
}

// Called on a separate thread
void midiInputCallback(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon) {
   const MIDIPacket *packet = &pktlist->packet[0];
   for (UInt32 i = 0; i < pktlist->numPackets; ++i) {
      if (packet->length == 3) {
         reinterpret_cast<Kontroller::Communicator*>(readProcRefCon)->onMessageReceived(packet->data[1], packet->data[2]);
      }
      packet = MIDIPacketNext(packet);
   }
}

struct Endpoints {
   MIDIEndpointRef source;
   MIDIEndpointRef destination;
};

Endpoints findEndpoints(const char* deviceName) {
   Endpoints endpoints { 0 };
   ItemCount deviceCount = MIDIGetNumberOfDevices();

   for (ItemCount i = 0; i < deviceCount; ++i) {
      MIDIDeviceRef device = MIDIGetDevice(i);

      CFStringRef name = nullptr;
      OSStatus nameResult = MIDIObjectGetStringProperty(device, kMIDIPropertyName, &name);
      if (nameResult != noErr) {
         continue;
      }
      const char *cstr = CFStringGetCStringPtr(name, kCFStringEncodingUTF8);
      CFRelease(name);
      if (!cstr) {
         continue;
      }
      if (std::string(cstr) != deviceName) {
         continue;
      }

      ItemCount entityCount = MIDIDeviceGetNumberOfEntities(device);
      if (entityCount != 1) {
         continue;
      }

      MIDIEntityRef entity = MIDIDeviceGetEntity(device, 0);
      ItemCount sourceCount = MIDIEntityGetNumberOfSources(entity);
      if (sourceCount != 1) {
         continue;
      }
      ItemCount destinationCount = MIDIEntityGetNumberOfDestinations(entity);
      if (destinationCount != 1) {
         continue;
      }

      SInt32 offline = 0;
      MIDIObjectGetIntegerProperty(device, kMIDIPropertyOffline, &offline);
      if (offline) {
         continue;
      }

      endpoints.source = MIDIEntityGetSource(entity, 0);
      endpoints.destination = MIDIEntityGetDestination(entity, 0);
      break;
   }

   return endpoints;
}

} // namespace

Kontroller::Communicator::Communicator(Kontroller* kontroller)
   : implData(new ImplData), kontroller(kontroller) {
}

Kontroller::Communicator::~Communicator() {
   disconnect();
}

bool Kontroller::Communicator::isConnected() const {
   return implData->client && implData->inputPort && implData->outputPort && implData->destination;
}

bool Kontroller::Communicator::connect() {
   if (isConnected()) {
      return true;
   }

   bool success = false;
   do {
      Endpoints endpoints = findEndpoints(Kontroller::kDeviceName);
      if (!endpoints.source || !endpoints.destination) {
         break;
      }
      implData->destination = endpoints.destination;

      OSStatus clientResult = MIDIClientCreate(CFSTR("Kontroller client"), midiNotifyCallback, this, &implData->client);
      if (clientResult != noErr) {
         break;
      }

      OSStatus inputPortResult = MIDIInputPortCreate(implData->client, CFSTR("Kontroller input port"),
                                                     midiInputCallback, this, &implData->inputPort);
      if (inputPortResult != noErr) {
         break;
      }

      OSStatus outputPortResult = MIDIOutputPortCreate(implData->client, CFSTR("Kontroller output port"),
                                                       &implData->outputPort);
      if (outputPortResult != noErr) {
         break;
      }

      OSStatus connectResult = MIDIPortConnectSource(implData->inputPort, endpoints.source, nullptr);
      if (connectResult != noErr) {
         break;
      }

      success = true;
   } while(false);

   if (!success) {
      disconnect();
   }

   return success;
}

void Kontroller::Communicator::disconnect() {
   if (implData->client) {
      MIDIClientDispose(implData->client); // Closes the ports as well
   }

   *implData = {};
}

void Kontroller::Communicator::poll() {
   CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);

   // We will only be notified of a lost connection when the main loop is run (that is the only time the notify callback
   // is executed), so we only need to check for lost connections here
   checkForLostConnection();
}

bool Kontroller::Communicator::initializeMessage() {
   implData->lastPacket = MIDIPacketListInit(&implData->list);
   return implData->lastPacket != nullptr;
}

bool Kontroller::Communicator::appendToMessage(uint8_t* data, size_t numBytes) {
   implData->lastPacket = MIDIPacketListAdd(&implData->list, implData->padding.size(), implData->lastPacket,
                                            0, numBytes, data);
   return implData->lastPacket != nullptr;
}

bool Kontroller::Communicator::finalizeMessage() {
   OSStatus sendResult = MIDISend(implData->outputPort, implData->destination, &implData->list);
   return sendResult != noErr;
}
<commit_msg>Fix return value on OS X<commit_after>#include "Kontroller/Kontroller.h"
#include "Communicator.h"

#include <CoreMIDI/MIDIServices.h>

#include <string>

struct Kontroller::Communicator::ImplData {
   MIDIClientRef client { 0 };
   MIDIPortRef inputPort { 0 };
   MIDIPortRef outputPort { 0 };
   MIDIEndpointRef destination { 0 };

   union {
      MIDIPacketList list;
      std::array<uint8_t, 512> padding; // Ensure the list has enough space
   };
   MIDIPacket* lastPacket { nullptr };
};

namespace {

// Called on the main thread
void midiNotifyCallback(const MIDINotification *message, void *refCon) {
   if (message->messageID == kMIDIMsgObjectRemoved) {
      const MIDIObjectAddRemoveNotification* notification =
         reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
      Kontroller::Communicator* communicator = reinterpret_cast<Kontroller::Communicator*>(refCon);

      if (notification->child == communicator->getImplData().destination) {
         communicator->onConnectionLost();
      }
   }
}

// Called on a separate thread
void midiInputCallback(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon) {
   const MIDIPacket *packet = &pktlist->packet[0];
   for (UInt32 i = 0; i < pktlist->numPackets; ++i) {
      if (packet->length == 3) {
         reinterpret_cast<Kontroller::Communicator*>(readProcRefCon)->onMessageReceived(packet->data[1], packet->data[2]);
      }
      packet = MIDIPacketNext(packet);
   }
}

struct Endpoints {
   MIDIEndpointRef source;
   MIDIEndpointRef destination;
};

Endpoints findEndpoints(const char* deviceName) {
   Endpoints endpoints { 0 };
   ItemCount deviceCount = MIDIGetNumberOfDevices();

   for (ItemCount i = 0; i < deviceCount; ++i) {
      MIDIDeviceRef device = MIDIGetDevice(i);

      CFStringRef name = nullptr;
      OSStatus nameResult = MIDIObjectGetStringProperty(device, kMIDIPropertyName, &name);
      if (nameResult != noErr) {
         continue;
      }
      const char *cstr = CFStringGetCStringPtr(name, kCFStringEncodingUTF8);
      CFRelease(name);
      if (!cstr) {
         continue;
      }
      if (std::string(cstr) != deviceName) {
         continue;
      }

      ItemCount entityCount = MIDIDeviceGetNumberOfEntities(device);
      if (entityCount != 1) {
         continue;
      }

      MIDIEntityRef entity = MIDIDeviceGetEntity(device, 0);
      ItemCount sourceCount = MIDIEntityGetNumberOfSources(entity);
      if (sourceCount != 1) {
         continue;
      }
      ItemCount destinationCount = MIDIEntityGetNumberOfDestinations(entity);
      if (destinationCount != 1) {
         continue;
      }

      SInt32 offline = 0;
      MIDIObjectGetIntegerProperty(device, kMIDIPropertyOffline, &offline);
      if (offline) {
         continue;
      }

      endpoints.source = MIDIEntityGetSource(entity, 0);
      endpoints.destination = MIDIEntityGetDestination(entity, 0);
      break;
   }

   return endpoints;
}

} // namespace

Kontroller::Communicator::Communicator(Kontroller* kontroller)
   : implData(new ImplData), kontroller(kontroller) {
}

Kontroller::Communicator::~Communicator() {
   disconnect();
}

bool Kontroller::Communicator::isConnected() const {
   return implData->client && implData->inputPort && implData->outputPort && implData->destination;
}

bool Kontroller::Communicator::connect() {
   if (isConnected()) {
      return true;
   }

   bool success = false;
   do {
      Endpoints endpoints = findEndpoints(Kontroller::kDeviceName);
      if (!endpoints.source || !endpoints.destination) {
         break;
      }
      implData->destination = endpoints.destination;

      OSStatus clientResult = MIDIClientCreate(CFSTR("Kontroller client"), midiNotifyCallback, this, &implData->client);
      if (clientResult != noErr) {
         break;
      }

      OSStatus inputPortResult = MIDIInputPortCreate(implData->client, CFSTR("Kontroller input port"),
                                                     midiInputCallback, this, &implData->inputPort);
      if (inputPortResult != noErr) {
         break;
      }

      OSStatus outputPortResult = MIDIOutputPortCreate(implData->client, CFSTR("Kontroller output port"),
                                                       &implData->outputPort);
      if (outputPortResult != noErr) {
         break;
      }

      OSStatus connectResult = MIDIPortConnectSource(implData->inputPort, endpoints.source, nullptr);
      if (connectResult != noErr) {
         break;
      }

      success = true;
   } while(false);

   if (!success) {
      disconnect();
   }

   return success;
}

void Kontroller::Communicator::disconnect() {
   if (implData->client) {
      MIDIClientDispose(implData->client); // Closes the ports as well
   }

   *implData = {};
}

void Kontroller::Communicator::poll() {
   CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);

   // We will only be notified of a lost connection when the main loop is run (that is the only time the notify callback
   // is executed), so we only need to check for lost connections here
   checkForLostConnection();
}

bool Kontroller::Communicator::initializeMessage() {
   implData->lastPacket = MIDIPacketListInit(&implData->list);
   return implData->lastPacket != nullptr;
}

bool Kontroller::Communicator::appendToMessage(uint8_t* data, size_t numBytes) {
   implData->lastPacket = MIDIPacketListAdd(&implData->list, implData->padding.size(), implData->lastPacket,
                                            0, numBytes, data);
   return implData->lastPacket != nullptr;
}

bool Kontroller::Communicator::finalizeMessage() {
   OSStatus sendResult = MIDISend(implData->outputPort, implData->destination, &implData->list);
   return sendResult == noErr;
}
<|endoftext|>


<commit_before>#ifndef COMPRESS__H__
#define COMPRESS__H__

#include <utility>

// TODO everything in here

namespace iter {

    //Forward declarations of Compressed and compress
    template <typename Container, typename Selector>
    class Compressed;

    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(Container &, Selector &);

    template <typename Container, typename Selector>
    class Compressed {
        // The only thing allowed to directly instantiate an Compressed is
        // the compress function
        friend Compressed compress<Container, Selector>(
                Container &, Selector &);

        // Type of the Container::Iterator, but since the name of that
        // iterator can be anything, we have to grab it with this
        using contained_iter_type =
            decltype(((Container *)nullptr)->begin());

        // The type returned when dereferencing the Container::Iterator
        using contained_iter_ret =
            decltype(((contained_iter_type *)nullptr)->operator*());

        // Selector::Iterator type
        using selector_iter_type =
            decltype(((Selector *)nullptr)->begin());

        private:
            Container & container;
            Selector & selectors;

            // Value constructor for use only in the compress function
            Compressed(Container & container, Selector & selectors) :
                container(container),
                selectors(selectors)
            { }
            Compressed () = delete;
            Compressed & operator=(const Compressed &) = delete;

        public:
            Compressed (const Compressed &) = default;

            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;

                    selector_iter_type selector_iter;
                    const selector_iter_type selector_end;

                    void increment_iterators() {
                        ++this->sub_iter;
                        ++this->selector_iter;
                    }

                    void skip_failures() {
                        while (this->sub_iter != this->sub_end &&
                                !*this->selector_iter) {
                            this->increment_iterators();
                        }
                    }

                public:
                    Iterator (contained_iter_type cont_iter,
                              contained_iter_type cont_end,
                              selector_iter_type sel_iter,
                              selector_iter_type sel_end) :
                        sub_iter(cont_iter),
                        sub_end(cont_end),
                        selector_iter(sel_iter),
                        selector_end(sel_end)
                    {
                        this->skip_failures();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        this->increment_iterators();
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter &&
                            this->selector_iter != other.selector_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        this->container.begin(), this->container.end(),
                        this->selectors.begin(), this->selectors.end());
            }

            Iterator end() const {
                return Iterator(
                        this->container.end(), this->container.end(),
                        this->selectors.end(), this->selectors.end());
            }

    };

    // Helper function to instantiate an Compressed
    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(
            Container & container, Selector & selectors) {
        return Compressed<Container, Selector>(container, selectors);
    }

}

#endif //ifndef COMPRESS__H__
<commit_msg>Replaces ugly decltype with std::declval in compress<commit_after>#ifndef COMPRESS__H__
#define COMPRESS__H__

#include <utility>

// TODO everything in here

namespace iter {

    //Forward declarations of Compressed and compress
    template <typename Container, typename Selector>
    class Compressed;

    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(Container &, Selector &);

    template <typename Container, typename Selector>
    class Compressed {
        // The only thing allowed to directly instantiate an Compressed is
        // the compress function
        friend Compressed compress<Container, Selector>(
                Container &, Selector &);

        // Type of the Container::Iterator, but since the name of that
        // iterator can be anything, we have to grab it with this
        using contained_iter_type =
            decltype(std::declval<Container>().begin());

        // The type returned when dereferencing the Container::Iterator
        using contained_iter_ret =
            decltype(std::declval<contained_iter_type>().operator*());

        // Selector::Iterator type
        using selector_iter_type =
            decltype(std::declval<Selector>().begin());

        private:
            Container & container;
            Selector & selectors;

            // Value constructor for use only in the compress function
            Compressed(Container & container, Selector & selectors) :
                container(container),
                selectors(selectors)
            { }
            Compressed () = delete;
            Compressed & operator=(const Compressed &) = delete;

        public:
            Compressed (const Compressed &) = default;

            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;

                    selector_iter_type selector_iter;
                    const selector_iter_type selector_end;

                    void increment_iterators() {
                        ++this->sub_iter;
                        ++this->selector_iter;
                    }

                    void skip_failures() {
                        while (this->sub_iter != this->sub_end &&
                                !*this->selector_iter) {
                            this->increment_iterators();
                        }
                    }

                public:
                    Iterator (contained_iter_type cont_iter,
                              contained_iter_type cont_end,
                              selector_iter_type sel_iter,
                              selector_iter_type sel_end) :
                        sub_iter(cont_iter),
                        sub_end(cont_end),
                        selector_iter(sel_iter),
                        selector_end(sel_end)
                    {
                        this->skip_failures();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        this->increment_iterators();
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter &&
                            this->selector_iter != other.selector_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        this->container.begin(), this->container.end(),
                        this->selectors.begin(), this->selectors.end());
            }

            Iterator end() const {
                return Iterator(
                        this->container.end(), this->container.end(),
                        this->selectors.end(), this->selectors.end());
            }

    };

    // Helper function to instantiate an Compressed
    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(
            Container & container, Selector & selectors) {
        return Compressed<Container, Selector>(container, selectors);
    }

}

#endif //ifndef COMPRESS__H__
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file ContractionState.cxx
 ** Manages visibility of lines for folding and wrapping.
 **/
// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"
#include "ContractionState.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

ContractionState::ContractionState() : visible(0), expanded(0), heights(0), displayLines(0), linesInDocument(1) {
	//InsertLine(0);
}

ContractionState::~ContractionState() {
	Clear();
}

void ContractionState::EnsureData() {
	if (OneToOne()) {
		visible = new RunStyles();
		expanded = new RunStyles();
		heights = new RunStyles();
		displayLines = new Partitioning(4);
		InsertLines(0, linesInDocument);
	}
}

void ContractionState::Clear() {
	delete visible;
	visible = 0;
	delete expanded;
	expanded = 0;
	delete heights;
	heights = 0;
	delete displayLines;
	displayLines = 0;
	linesInDocument = 1;
}

int ContractionState::LinesInDoc() const {
	if (OneToOne()) {
		return linesInDocument;
	} else {
		return displayLines->Partitions() - 1;
	}
}

int ContractionState::LinesDisplayed() const {
	if (OneToOne()) {
		return linesInDocument;
	} else {
		return displayLines->PositionFromPartition(LinesInDoc());
	}
}

int ContractionState::DisplayFromDoc(int lineDoc) const {
	if (OneToOne()) {
		return lineDoc;
	} else {
		if (lineDoc > displayLines->Partitions())
			lineDoc = displayLines->Partitions();
		return displayLines->PositionFromPartition(lineDoc);
	}
}

int ContractionState::DocFromDisplay(int lineDisplay) const {
	if (OneToOne()) {
		return lineDisplay;
	} else {
		if (lineDisplay <= 0) {
			return 0;
		}
		if (lineDisplay > LinesDisplayed()) {
			return displayLines->PartitionFromPosition(LinesDisplayed());
		}
		int lineDoc = displayLines->PartitionFromPosition(lineDisplay);
		PLATFORM_ASSERT(GetVisible(lineDoc));
		return lineDoc;
	}
}

void ContractionState::InsertLine(int lineDoc) {
	if (OneToOne()) {
		linesInDocument++;
	} else {
		visible->InsertSpace(lineDoc, 1);
		visible->SetValueAt(lineDoc, 1);
		expanded->InsertSpace(lineDoc, 1);
		expanded->SetValueAt(lineDoc, 1);
		heights->InsertSpace(lineDoc, 1);
		heights->SetValueAt(lineDoc, 1);
		int lineDisplay = DisplayFromDoc(lineDoc);
		displayLines->InsertPartition(lineDoc, lineDisplay);
		displayLines->InsertText(lineDoc, 1);
	}
}

void ContractionState::InsertLines(int lineDoc, int lineCount) {
	for (int l = 0; l < lineCount; l++) {
		InsertLine(lineDoc + l);
	}
	Check();
}

void ContractionState::DeleteLine(int lineDoc) {
	if (OneToOne()) {
		linesInDocument--;
	} else {
		if (GetVisible(lineDoc)) {
			displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc));
		}
		displayLines->RemovePartition(lineDoc);
		visible->DeleteRange(lineDoc, 1);
		expanded->DeleteRange(lineDoc, 1);
		heights->DeleteRange(lineDoc, 1);
	}
}

void ContractionState::DeleteLines(int lineDoc, int lineCount) {
	for (int l = 0; l < lineCount; l++) {
		DeleteLine(lineDoc);
	}
	Check();
}

bool ContractionState::GetVisible(int lineDoc) const {
	if (OneToOne()) {
		return true;
	} else {
		if (lineDoc >= visible->Length())
			return true;
		return visible->ValueAt(lineDoc) == 1;
	}
}

bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) {
	if (OneToOne() && visible_) {
		return false;
	} else {
		EnsureData();
		int delta = 0;
		Check();
		if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) {
			for (int line = lineDocStart; line <= lineDocEnd; line++) {
				if (GetVisible(line) != visible_) {
					int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line);
					visible->SetValueAt(line, visible_ ? 1 : 0);
					displayLines->InsertText(line, difference);
					delta += difference;
				}
			}
		} else {
			return false;
		}
		Check();
		return delta != 0;
	}
}

bool ContractionState::GetExpanded(int lineDoc) const {
	if (OneToOne()) {
		return true;
	} else {
		Check();
		return expanded->ValueAt(lineDoc) == 1;
	}
}

bool ContractionState::SetExpanded(int lineDoc, bool expanded_) {
	if (OneToOne() && expanded_) {
		return false;
	} else {
		EnsureData();
		if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) {
			expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0);
			Check();
			return true;
		} else {
			Check();
			return false;
		}
	}
}

int ContractionState::GetHeight(int lineDoc) const {
	if (OneToOne()) {
		return 1;
	} else {
		return heights->ValueAt(lineDoc);
	}
}

// Set the number of display lines needed for this line.
// Return true if this is a change.
bool ContractionState::SetHeight(int lineDoc, int height) {
	if (OneToOne() && (height == 1)) {
		return false;
	} else {
		EnsureData();
		if (GetHeight(lineDoc) != height) {
			if (GetVisible(lineDoc)) {
				displayLines->InsertText(lineDoc, height - GetHeight(lineDoc));
			}
			heights->SetValueAt(lineDoc, height);
			Check();
			return true;
		} else {
			Check();
			return false;
		}
	}
}

void ContractionState::ShowAll() {
	Clear();
}

// Debugging checks

void ContractionState::Check() const {
#ifdef CHECK_CORRECTNESS
	for (int vline = 0;vline < LinesDisplayed(); vline++) {
		const int lineDoc = DocFromDisplay(vline);
		PLATFORM_ASSERT(GetVisible(lineDoc));
	}
	for (int lineDoc = 0;lineDoc < LinesInDoc(); lineDoc++) {
		const int displayThis = DisplayFromDoc(lineDoc);
		const int displayNext = DisplayFromDoc(lineDoc + 1);
		const int height = displayNext - displayThis;
		PLATFORM_ASSERT(height >= 0);
		if (GetVisible(lineDoc)) {
			PLATFORM_ASSERT(GetHeight(lineDoc) == height);
		} else {
			PLATFORM_ASSERT(0 == height);
		}
	}
#endif
}
<commit_msg>Fixed bug when ShowAll called where linesInDocument was always reset to 1 which hid most of the file.<commit_after>// Scintilla source code edit control
/** @file ContractionState.cxx
 ** Manages visibility of lines for folding and wrapping.
 **/
// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"
#include "ContractionState.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

ContractionState::ContractionState() : visible(0), expanded(0), heights(0), displayLines(0), linesInDocument(1) {
	//InsertLine(0);
}

ContractionState::~ContractionState() {
	Clear();
}

void ContractionState::EnsureData() {
	if (OneToOne()) {
		visible = new RunStyles();
		expanded = new RunStyles();
		heights = new RunStyles();
		displayLines = new Partitioning(4);
		InsertLines(0, linesInDocument);
	}
}

void ContractionState::Clear() {
	delete visible;
	visible = 0;
	delete expanded;
	expanded = 0;
	delete heights;
	heights = 0;
	delete displayLines;
	displayLines = 0;
}

int ContractionState::LinesInDoc() const {
	if (OneToOne()) {
		return linesInDocument;
	} else {
		return displayLines->Partitions() - 1;
	}
}

int ContractionState::LinesDisplayed() const {
	if (OneToOne()) {
		return linesInDocument;
	} else {
		return displayLines->PositionFromPartition(LinesInDoc());
	}
}

int ContractionState::DisplayFromDoc(int lineDoc) const {
	if (OneToOne()) {
		return lineDoc;
	} else {
		if (lineDoc > displayLines->Partitions())
			lineDoc = displayLines->Partitions();
		return displayLines->PositionFromPartition(lineDoc);
	}
}

int ContractionState::DocFromDisplay(int lineDisplay) const {
	if (OneToOne()) {
		return lineDisplay;
	} else {
		if (lineDisplay <= 0) {
			return 0;
		}
		if (lineDisplay > LinesDisplayed()) {
			return displayLines->PartitionFromPosition(LinesDisplayed());
		}
		int lineDoc = displayLines->PartitionFromPosition(lineDisplay);
		PLATFORM_ASSERT(GetVisible(lineDoc));
		return lineDoc;
	}
}

void ContractionState::InsertLine(int lineDoc) {
	if (OneToOne()) {
		linesInDocument++;
	} else {
		visible->InsertSpace(lineDoc, 1);
		visible->SetValueAt(lineDoc, 1);
		expanded->InsertSpace(lineDoc, 1);
		expanded->SetValueAt(lineDoc, 1);
		heights->InsertSpace(lineDoc, 1);
		heights->SetValueAt(lineDoc, 1);
		int lineDisplay = DisplayFromDoc(lineDoc);
		displayLines->InsertPartition(lineDoc, lineDisplay);
		displayLines->InsertText(lineDoc, 1);
	}
}

void ContractionState::InsertLines(int lineDoc, int lineCount) {
	for (int l = 0; l < lineCount; l++) {
		InsertLine(lineDoc + l);
	}
	Check();
}

void ContractionState::DeleteLine(int lineDoc) {
	if (OneToOne()) {
		linesInDocument--;
	} else {
		if (GetVisible(lineDoc)) {
			displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc));
		}
		displayLines->RemovePartition(lineDoc);
		visible->DeleteRange(lineDoc, 1);
		expanded->DeleteRange(lineDoc, 1);
		heights->DeleteRange(lineDoc, 1);
	}
}

void ContractionState::DeleteLines(int lineDoc, int lineCount) {
	for (int l = 0; l < lineCount; l++) {
		DeleteLine(lineDoc);
	}
	Check();
}

bool ContractionState::GetVisible(int lineDoc) const {
	if (OneToOne()) {
		return true;
	} else {
		if (lineDoc >= visible->Length())
			return true;
		return visible->ValueAt(lineDoc) == 1;
	}
}

bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) {
	if (OneToOne() && visible_) {
		return false;
	} else {
		EnsureData();
		int delta = 0;
		Check();
		if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) {
			for (int line = lineDocStart; line <= lineDocEnd; line++) {
				if (GetVisible(line) != visible_) {
					int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line);
					visible->SetValueAt(line, visible_ ? 1 : 0);
					displayLines->InsertText(line, difference);
					delta += difference;
				}
			}
		} else {
			return false;
		}
		Check();
		return delta != 0;
	}
}

bool ContractionState::GetExpanded(int lineDoc) const {
	if (OneToOne()) {
		return true;
	} else {
		Check();
		return expanded->ValueAt(lineDoc) == 1;
	}
}

bool ContractionState::SetExpanded(int lineDoc, bool expanded_) {
	if (OneToOne() && expanded_) {
		return false;
	} else {
		EnsureData();
		if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) {
			expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0);
			Check();
			return true;
		} else {
			Check();
			return false;
		}
	}
}

int ContractionState::GetHeight(int lineDoc) const {
	if (OneToOne()) {
		return 1;
	} else {
		return heights->ValueAt(lineDoc);
	}
}

// Set the number of display lines needed for this line.
// Return true if this is a change.
bool ContractionState::SetHeight(int lineDoc, int height) {
	if (OneToOne() && (height == 1)) {
		return false;
	} else {
		EnsureData();
		if (GetHeight(lineDoc) != height) {
			if (GetVisible(lineDoc)) {
				displayLines->InsertText(lineDoc, height - GetHeight(lineDoc));
			}
			heights->SetValueAt(lineDoc, height);
			Check();
			return true;
		} else {
			Check();
			return false;
		}
	}
}

void ContractionState::ShowAll() {
	int lines = LinesInDoc();
	Clear();
	linesInDocument = lines;
}

// Debugging checks

void ContractionState::Check() const {
#ifdef CHECK_CORRECTNESS
	for (int vline = 0;vline < LinesDisplayed(); vline++) {
		const int lineDoc = DocFromDisplay(vline);
		PLATFORM_ASSERT(GetVisible(lineDoc));
	}
	for (int lineDoc = 0;lineDoc < LinesInDoc(); lineDoc++) {
		const int displayThis = DisplayFromDoc(lineDoc);
		const int displayNext = DisplayFromDoc(lineDoc + 1);
		const int height = displayNext - displayThis;
		PLATFORM_ASSERT(height >= 0);
		if (GetVisible(lineDoc)) {
			PLATFORM_ASSERT(GetHeight(lineDoc) == height);
		} else {
			PLATFORM_ASSERT(0 == height);
		}
	}
#endif
}
<|endoftext|>


<commit_before>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "bits.hh"
#include "cpu.hh"
#include "apic.hh"
#include "pci.hh"
#include "kstream.hh"
#include <iterator>

extern "C" {
#include "acpi.h"
}

static console_stream verbose(true);

// ACPI table with a generic subtable layout.  This provides a
// convenient iterator for traversing the subtables.
template<typename Hdr>
class acpi_table
{
  Hdr *header_;

public:
  constexpr acpi_table() : header_(nullptr) { }
  constexpr acpi_table(Hdr *header) : header_(header) { }
  acpi_table(ACPI_TABLE_HEADER *header) : header_((Hdr*)header) { }

  Hdr *operator->() const
  {
    return header_;
  }

  Hdr *get() const
  {
    return header_;
  }

  class iterator
  {
    void *pos_;
  public:
    constexpr iterator(void *pos) : pos_(pos) { }

    ACPI_SUBTABLE_HEADER &operator*() const
    {
      return *(ACPI_SUBTABLE_HEADER*)pos_;
    }

    ACPI_SUBTABLE_HEADER *operator->() const
    {
      return (ACPI_SUBTABLE_HEADER*)pos_;
    }

    iterator &operator++()
    {
      pos_ = (char*)pos_ + ((ACPI_SUBTABLE_HEADER*)pos_)->Length;
      return *this;
    }

    bool operator!=(const iterator &o)
    {
      return pos_ != o.pos_;
    }
  };

  iterator begin() const
  {
    return iterator(header_ + 1);
  }

  iterator end() const
  {
    return iterator((char*)header_ + header_->Header.Length);
  }
};

static bool have_tables, have_acpi;
static acpi_table<ACPI_TABLE_MADT> madt;

void
initacpitables(void)
{
  ACPI_STATUS r;

  // ACPICA's table manager can be initialized independently of the
  // rest of ACPICA precisely so we can use these tables during early
  // boot.
  if (ACPI_FAILURE(r = AcpiInitializeTables(nullptr, 16, FALSE)))
    panic("acpi: AcpiInitializeTables failed: %s", AcpiFormatException(r));

  have_tables = true;

  // Get the MADT
  ACPI_TABLE_HEADER *madtp;
  r = AcpiGetTable((char*)ACPI_SIG_MADT, 0, &madtp);
  if (ACPI_FAILURE(r) && r != AE_NOT_FOUND)
    panic("acpi: AcpiGetTable failed: %s", AcpiFormatException(r));
  if (r == AE_OK)
    madt = acpi_table<ACPI_TABLE_MADT>(madtp);
}

bool
initcpus_acpi(void)
{
  if (!madt.get())
    return false;

  verbose.println("acpi: Initializing CPUs");

  // Reserve CPU 0 for the BSP, since we're already committed to that
  hwid_t my_apicid = lapic->id();
  ncpu = 1;

  // Create CPUs
  bool found_bsp = false;
  for (auto &sub : madt) {
    uint32_t lapicid;
    if (sub.Type == ACPI_MADT_TYPE_LOCAL_APIC) {
      auto &lapic = *(ACPI_MADT_LOCAL_APIC*)⊂
      if (!(lapic.LapicFlags & ACPI_MADT_ENABLED))
        continue;
      lapicid = lapic.Id;
    } else if (sub.Type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
      auto &lapic = *(ACPI_MADT_LOCAL_X2APIC*)⊂
      if (!(lapic.LapicFlags & ACPI_MADT_ENABLED))
        continue;
      lapicid = lapic.LocalApicId;
    } else {
      continue;
    }

    struct cpu *c;
    if (lapicid == my_apicid.num) {
      c = &cpus[0];
      found_bsp = true;
    } else {
      if (ncpu == NCPU)
        panic("initcpus_acpi: too many CPUs");
      c = &cpus[ncpu++];
    }
    c->id = c - cpus;
    c->hwid = HWID(lapicid);
    verbose.println("acpi: CPU ", c->id, " APICID ", c->hwid.num);
  }
  assert(found_bsp);

  return true;
}

static void
decode_mps_inti_flags(uint8_t bus, uint32_t intiflags, irq *out)
{
  int polarity = intiflags & ACPI_MADT_POLARITY_MASK;
  out->active_low = (polarity == ACPI_MADT_POLARITY_ACTIVE_LOW);
  if (bus != 0 && polarity == ACPI_MADT_POLARITY_CONFORMS)
    panic("decode_mps_inti_flags: Unknown bus %d", bus);
  int trigger = intiflags & ACPI_MADT_TRIGGER_MASK;
  out->level_triggered = (trigger == ACPI_MADT_TRIGGER_LEVEL);
  if (bus != 0 && trigger == ACPI_MADT_TRIGGER_CONFORMS)
    panic("decode_mps_inti_flags: Unknown bus %d", bus);
}

bool
acpi_setup_ioapic(ioapic *apic)
{
  if (!madt.get())
    return false;

  verbose.println("acpi: Initializing IOAPICs");

  bool haveioapic = false;
  for (auto &sub : madt) {
    if (sub.Type == ACPI_MADT_TYPE_IO_APIC) {
      // [ACPI5.0 5.2.12.3]
      auto &ioapic = *(ACPI_MADT_IO_APIC*)⊂
      apic->register_base(ioapic.GlobalIrqBase, ioapic.Address);
      haveioapic = true;
    } else if (sub.Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) {
      // [ACPI5.0 5.2.12.5]
      auto &intov = *(ACPI_MADT_INTERRUPT_OVERRIDE*)⊂
      irq gsi;
      gsi.gsi = intov.GlobalIrq;
      decode_mps_inti_flags(intov.Bus, intov.IntiFlags, &gsi);
      apic->register_isa_irq_override(intov.SourceIrq, gsi);
    } else if (sub.Type == ACPI_MADT_TYPE_NMI_SOURCE) {
      // [ACPI5.0 5.2.12.6]
      auto &nmisrc = *(ACPI_MADT_NMI_SOURCE*)⊂
      irq nmi;
      nmi.gsi = nmisrc.GlobalIrq;
      decode_mps_inti_flags(-1, nmisrc.IntiFlags, &nmi);
      apic->register_nmi(nmi);
    }
  }

  return haveioapic;
}

void
initacpi(void)
{
  if (!have_tables)
    return;

  // Perform the ACPICA initialization sequence [ACPICA 4.2]
  ACPI_STATUS r;

  if (ACPI_FAILURE(r = AcpiInitializeSubsystem()))
    panic("acpi: AcpiInitializeSubsystem failed: %s", AcpiFormatException(r));

  if (ACPI_FAILURE(r = AcpiLoadTables()))
    panic("acpi: AcpiLoadTables failed: %s", AcpiFormatException(r));

  if (ACPI_FAILURE(r = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION)))
    panic("acpi: AcpiEnableSubsystem failed: %s", AcpiFormatException(r));

  // XXX Install OS handlers

  if (ACPI_FAILURE(r = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION)))
    panic("acpi: AcpiInitializeObjects failed: %s", AcpiFormatException(r));

  // Inform ACPI that we're using IOAPIC mode [ACPI5.0 5.8.1]
  union acpi_object args[1] = { { ACPI_TYPE_INTEGER } };
  struct acpi_object_list arg_list = { NELEM(args), args };
  args[0].Integer.Value = 1;    // APIC IRQ model
  r = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
  if (ACPI_FAILURE(r) && (r != AE_NOT_FOUND))
    panic("acpi: Error evaluating _PIC: %s", AcpiFormatException(r));

  have_acpi = true;
}

static ACPI_STATUS
pci_root_cb(ACPI_HANDLE object, UINT32 nesting_level,
            void *context, void **return_value)
{
  auto scan = (int (*)(struct pci_bus *bus))(context);
  struct pci_bus bus = {};

  ACPI_STATUS r;
  ACPI_OBJECT out;
  ACPI_BUFFER outbuf{sizeof(out), &out};
  r = AcpiEvaluateObject(object, (char*)"_BBN", nullptr, &outbuf);
  if (ACPI_FAILURE(r) && (r != AE_NOT_FOUND))
    panic("acpi: Error evaluating _BBN: %s", AcpiFormatException(r));
  if (r == AE_OK) {
    if (outbuf.Length != sizeof(out)) {
      swarn.println("acpi: _BBN method returned void");
      return AE_OK;
    } else if (out.Type != ACPI_TYPE_INTEGER) {
      swarn.println("acpi: _BBN method returned unexpected type");
      return AE_OK;
    } else {
      bus.busno = out.Integer.Value;
    }
  }
  bus.acpi_handle = object;

  scan(&bus);
  return AE_OK;
}

// Call scan for each of the PCI root buses.  Returns true if
// enumeration via ACPI was possible, or false otherwise (meaning a
// fallback mechanism should be used).
bool
acpi_pci_scan_roots(int (*scan)(struct pci_bus *bus))
{
  if (!have_acpi)
    return false;

  // See http://www.acpi.info/acpi_faq.htm for information on scanning
  // multiple roots
  verbose.println("acpi: Using ACPI for PCI root enumeration");

  AcpiGetDevices((char*)"PNP0A03", pci_root_cb, (void*)scan, nullptr);

  return true;
}

// Find the ACPI handle (if any) associated with func.
ACPI_HANDLE
acpi_pci_resolve_handle(struct pci_func *func)
{
  ACPI_STATUS r;

  if (!have_acpi || func->acpi_handle)
    return func->acpi_handle;

  // Get the parent object
  ACPI_HANDLE parent = acpi_pci_resolve_handle(func->bus);
  if (!parent)
    return nullptr;

  // Walk children of the bus, looking for func's address
  ACPI_HANDLE child = nullptr;
  ACPI_DEVICE_INFO *devinfo;
  while ((r = AcpiGetNextObject(ACPI_TYPE_DEVICE, parent, child,
                                &child)) == AE_OK) {
    if (ACPI_FAILURE(r = AcpiGetObjectInfo(child, &devinfo)))
      panic("AcpiGetObjectInfo failed: %s", AcpiFormatException(r));
    if ((devinfo->Valid & ACPI_VALID_ADR) &&
        ((devinfo->Address >> 16) == func->dev) &&
        (((devinfo->Address & 0xFFFF) == func->func ||
          (devinfo->Address & 0xFFFF) == 0xFFFF))) {
      // XXX On QEMU, one device can have multiple ACPI objects.  I
      // haven't seen this on real hardware, though.
      verbose.println("acpi: PCI device ", *func,
                      " has ACPI handle ", sacpi(child));
      func->acpi_handle = child;
    }
    AcpiOsFree(devinfo);
  }
  if (r != AE_NOT_FOUND)
    panic("AcpiGetNextObject failed: %s", AcpiFormatException(r));

  return func->acpi_handle;
}

// Find the ACPI handle (if any) associated with bus.
ACPI_HANDLE
acpi_pci_resolve_handle(struct pci_bus *bus)
{
  if (!bus->acpi_handle && bus->parent_bridge)
    bus->acpi_handle = acpi_pci_resolve_handle(bus->parent_bridge);

  return bus->acpi_handle;
}
<commit_msg>acpi: Helpers for variable-length ACPI arrays and deletion<commit_after>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "bits.hh"
#include "cpu.hh"
#include "apic.hh"
#include "pci.hh"
#include "kstream.hh"
#include <iterator>

extern "C" {
#include "acpi.h"
}

static console_stream verbose(true);

// ACPI table with a generic subtable layout.  This provides a
// convenient iterator for traversing the subtables.
template<typename Hdr>
class acpi_table
{
  Hdr *header_;

public:
  constexpr acpi_table() : header_(nullptr) { }
  constexpr acpi_table(Hdr *header) : header_(header) { }
  acpi_table(ACPI_TABLE_HEADER *header) : header_((Hdr*)header) { }

  Hdr *operator->() const
  {
    return header_;
  }

  Hdr *get() const
  {
    return header_;
  }

  class iterator
  {
    void *pos_;
  public:
    constexpr iterator(void *pos) : pos_(pos) { }

    ACPI_SUBTABLE_HEADER &operator*() const
    {
      return *(ACPI_SUBTABLE_HEADER*)pos_;
    }

    ACPI_SUBTABLE_HEADER *operator->() const
    {
      return (ACPI_SUBTABLE_HEADER*)pos_;
    }

    iterator &operator++()
    {
      pos_ = (char*)pos_ + ((ACPI_SUBTABLE_HEADER*)pos_)->Length;
      return *this;
    }

    bool operator!=(const iterator &o)
    {
      return pos_ != o.pos_;
    }
  };

  iterator begin() const
  {
    return iterator(header_ + 1);
  }

  iterator end() const
  {
    return iterator((char*)header_ + header_->Header.Length);
  }
};

// ACPI array with generic variable-size elements.  Almost, but not
// quite the same as a acpi_table.  Alas.
template<typename T>
class acpi_array
{
  T *first_;

public:
  constexpr acpi_array(T *first) : first_(first) { }
  acpi_array(const ACPI_BUFFER &buf) : first_((T*)buf.Pointer) { }

  class iterator
  {
    T *pos_;
  public:
    constexpr iterator(T *pos) : pos_(pos) { }
    constexpr iterator() : pos_(nullptr) { }

    T &operator*() const
    {
      return *pos_;
    }

    T *operator->() const
    {
      return pos_;
    }

    iterator &operator++()
    {
      pos_ = (T*)((char*)pos_ + pos_->Length);
      return *this;
    }

    bool operator==(const iterator &o)
    {
      bool isend1 = !pos_ || pos_->Length == 0;
      bool isend2 = !o.pos_ || o.pos_->Length == 0;
      if (isend1 || isend2)
        return isend1 && isend2;
      return pos_ == o.pos_;
    }

    bool operator!=(const iterator &o)
    {
      return !(*this == o);
    }
  };

  iterator begin() const
  {
    return iterator(first_);
  }

  iterator end() const
  {
    return iterator();
  }
};

class acpi_deleter
{
  void *p_;

public:
  acpi_deleter(void *p) : p_(p) { }
  ~acpi_deleter()
  {
    AcpiOsFree(p_);
  }
  acpi_deleter(acpi_deleter &&o) = delete;
};

static bool have_tables, have_acpi;
static acpi_table<ACPI_TABLE_MADT> madt;

void
initacpitables(void)
{
  ACPI_STATUS r;

  // ACPICA's table manager can be initialized independently of the
  // rest of ACPICA precisely so we can use these tables during early
  // boot.
  if (ACPI_FAILURE(r = AcpiInitializeTables(nullptr, 16, FALSE)))
    panic("acpi: AcpiInitializeTables failed: %s", AcpiFormatException(r));

  have_tables = true;

  // Get the MADT
  ACPI_TABLE_HEADER *madtp;
  r = AcpiGetTable((char*)ACPI_SIG_MADT, 0, &madtp);
  if (ACPI_FAILURE(r) && r != AE_NOT_FOUND)
    panic("acpi: AcpiGetTable failed: %s", AcpiFormatException(r));
  if (r == AE_OK)
    madt = acpi_table<ACPI_TABLE_MADT>(madtp);
}

bool
initcpus_acpi(void)
{
  if (!madt.get())
    return false;

  verbose.println("acpi: Initializing CPUs");

  // Reserve CPU 0 for the BSP, since we're already committed to that
  hwid_t my_apicid = lapic->id();
  ncpu = 1;

  // Create CPUs
  bool found_bsp = false;
  for (auto &sub : madt) {
    uint32_t lapicid;
    if (sub.Type == ACPI_MADT_TYPE_LOCAL_APIC) {
      auto &lapic = *(ACPI_MADT_LOCAL_APIC*)⊂
      if (!(lapic.LapicFlags & ACPI_MADT_ENABLED))
        continue;
      lapicid = lapic.Id;
    } else if (sub.Type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
      auto &lapic = *(ACPI_MADT_LOCAL_X2APIC*)⊂
      if (!(lapic.LapicFlags & ACPI_MADT_ENABLED))
        continue;
      lapicid = lapic.LocalApicId;
    } else {
      continue;
    }

    struct cpu *c;
    if (lapicid == my_apicid.num) {
      c = &cpus[0];
      found_bsp = true;
    } else {
      if (ncpu == NCPU)
        panic("initcpus_acpi: too many CPUs");
      c = &cpus[ncpu++];
    }
    c->id = c - cpus;
    c->hwid = HWID(lapicid);
    verbose.println("acpi: CPU ", c->id, " APICID ", c->hwid.num);
  }
  assert(found_bsp);

  return true;
}

static void
decode_mps_inti_flags(uint8_t bus, uint32_t intiflags, irq *out)
{
  int polarity = intiflags & ACPI_MADT_POLARITY_MASK;
  out->active_low = (polarity == ACPI_MADT_POLARITY_ACTIVE_LOW);
  if (bus != 0 && polarity == ACPI_MADT_POLARITY_CONFORMS)
    panic("decode_mps_inti_flags: Unknown bus %d", bus);
  int trigger = intiflags & ACPI_MADT_TRIGGER_MASK;
  out->level_triggered = (trigger == ACPI_MADT_TRIGGER_LEVEL);
  if (bus != 0 && trigger == ACPI_MADT_TRIGGER_CONFORMS)
    panic("decode_mps_inti_flags: Unknown bus %d", bus);
}

bool
acpi_setup_ioapic(ioapic *apic)
{
  if (!madt.get())
    return false;

  verbose.println("acpi: Initializing IOAPICs");

  bool haveioapic = false;
  for (auto &sub : madt) {
    if (sub.Type == ACPI_MADT_TYPE_IO_APIC) {
      // [ACPI5.0 5.2.12.3]
      auto &ioapic = *(ACPI_MADT_IO_APIC*)⊂
      apic->register_base(ioapic.GlobalIrqBase, ioapic.Address);
      haveioapic = true;
    } else if (sub.Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) {
      // [ACPI5.0 5.2.12.5]
      auto &intov = *(ACPI_MADT_INTERRUPT_OVERRIDE*)⊂
      irq gsi;
      gsi.gsi = intov.GlobalIrq;
      decode_mps_inti_flags(intov.Bus, intov.IntiFlags, &gsi);
      apic->register_isa_irq_override(intov.SourceIrq, gsi);
    } else if (sub.Type == ACPI_MADT_TYPE_NMI_SOURCE) {
      // [ACPI5.0 5.2.12.6]
      auto &nmisrc = *(ACPI_MADT_NMI_SOURCE*)⊂
      irq nmi;
      nmi.gsi = nmisrc.GlobalIrq;
      decode_mps_inti_flags(-1, nmisrc.IntiFlags, &nmi);
      apic->register_nmi(nmi);
    }
  }

  return haveioapic;
}

void
initacpi(void)
{
  if (!have_tables)
    return;

  // Perform the ACPICA initialization sequence [ACPICA 4.2]
  ACPI_STATUS r;

  if (ACPI_FAILURE(r = AcpiInitializeSubsystem()))
    panic("acpi: AcpiInitializeSubsystem failed: %s", AcpiFormatException(r));

  if (ACPI_FAILURE(r = AcpiLoadTables()))
    panic("acpi: AcpiLoadTables failed: %s", AcpiFormatException(r));

  if (ACPI_FAILURE(r = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION)))
    panic("acpi: AcpiEnableSubsystem failed: %s", AcpiFormatException(r));

  // XXX Install OS handlers

  if (ACPI_FAILURE(r = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION)))
    panic("acpi: AcpiInitializeObjects failed: %s", AcpiFormatException(r));

  // Inform ACPI that we're using IOAPIC mode [ACPI5.0 5.8.1]
  union acpi_object args[1] = { { ACPI_TYPE_INTEGER } };
  struct acpi_object_list arg_list = { NELEM(args), args };
  args[0].Integer.Value = 1;    // APIC IRQ model
  r = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
  if (ACPI_FAILURE(r) && (r != AE_NOT_FOUND))
    panic("acpi: Error evaluating _PIC: %s", AcpiFormatException(r));

  have_acpi = true;
}

static ACPI_STATUS
pci_root_cb(ACPI_HANDLE object, UINT32 nesting_level,
            void *context, void **return_value)
{
  auto scan = (int (*)(struct pci_bus *bus))(context);
  struct pci_bus bus = {};

  ACPI_STATUS r;
  ACPI_OBJECT out;
  ACPI_BUFFER outbuf{sizeof(out), &out};
  r = AcpiEvaluateObject(object, (char*)"_BBN", nullptr, &outbuf);
  if (ACPI_FAILURE(r) && (r != AE_NOT_FOUND))
    panic("acpi: Error evaluating _BBN: %s", AcpiFormatException(r));
  if (r == AE_OK) {
    if (outbuf.Length != sizeof(out)) {
      swarn.println("acpi: _BBN method returned void");
      return AE_OK;
    } else if (out.Type != ACPI_TYPE_INTEGER) {
      swarn.println("acpi: _BBN method returned unexpected type");
      return AE_OK;
    } else {
      bus.busno = out.Integer.Value;
    }
  }
  bus.acpi_handle = object;

  scan(&bus);
  return AE_OK;
}

// Call scan for each of the PCI root buses.  Returns true if
// enumeration via ACPI was possible, or false otherwise (meaning a
// fallback mechanism should be used).
bool
acpi_pci_scan_roots(int (*scan)(struct pci_bus *bus))
{
  if (!have_acpi)
    return false;

  // See http://www.acpi.info/acpi_faq.htm for information on scanning
  // multiple roots
  verbose.println("acpi: Using ACPI for PCI root enumeration");

  AcpiGetDevices((char*)"PNP0A03", pci_root_cb, (void*)scan, nullptr);

  return true;
}

// Find the ACPI handle (if any) associated with func.
ACPI_HANDLE
acpi_pci_resolve_handle(struct pci_func *func)
{
  ACPI_STATUS r;

  if (!have_acpi || func->acpi_handle)
    return func->acpi_handle;

  // Get the parent object
  ACPI_HANDLE parent = acpi_pci_resolve_handle(func->bus);
  if (!parent)
    return nullptr;

  // Walk children of the bus, looking for func's address
  ACPI_HANDLE child = nullptr;
  ACPI_DEVICE_INFO *devinfo;
  while ((r = AcpiGetNextObject(ACPI_TYPE_DEVICE, parent, child,
                                &child)) == AE_OK) {
    if (ACPI_FAILURE(r = AcpiGetObjectInfo(child, &devinfo)))
      panic("AcpiGetObjectInfo failed: %s", AcpiFormatException(r));
    if ((devinfo->Valid & ACPI_VALID_ADR) &&
        ((devinfo->Address >> 16) == func->dev) &&
        (((devinfo->Address & 0xFFFF) == func->func ||
          (devinfo->Address & 0xFFFF) == 0xFFFF))) {
      // XXX On QEMU, one device can have multiple ACPI objects.  I
      // haven't seen this on real hardware, though.
      verbose.println("acpi: PCI device ", *func,
                      " has ACPI handle ", sacpi(child));
      func->acpi_handle = child;
    }
    AcpiOsFree(devinfo);
  }
  if (r != AE_NOT_FOUND)
    panic("AcpiGetNextObject failed: %s", AcpiFormatException(r));

  return func->acpi_handle;
}

// Find the ACPI handle (if any) associated with bus.
ACPI_HANDLE
acpi_pci_resolve_handle(struct pci_bus *bus)
{
  if (!bus->acpi_handle && bus->parent_bridge)
    bus->acpi_handle = acpi_pci_resolve_handle(bus->parent_bridge);

  return bus->acpi_handle;
}
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Howard Butler, hobu.inc@gmail.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * 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.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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
* COPYRIGHT OWNER OR 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.
****************************************************************************/

#ifndef INCLUDED_BOUNDS_HPP
#define INCLUDED_BOUNDS_HPP

#include <vector>
#include <iostream>
#include <sstream>
#include <string>

#include "libpc/export.hpp"
#include "libpc/Range.hpp"
#include "libpc/Utils.hpp"

namespace libpc
{

template <typename T>
class LIBPC_DLL Bounds
{
public:
  typedef T value_type;
  typedef typename std::vector< Range<T> >::size_type size_type;
  typedef typename std::vector< Range<T> > RangeVec;

private:
  RangeVec ranges;

public:

Bounds<T>()
{
    ranges.resize(0);
}

Bounds(Bounds const& other)
    :
    ranges(other.ranges)
{
}

Bounds(RangeVec const& rngs)
    :
    ranges(rngs)
{
}

Bounds( T minx,
        T miny,
        T minz,
        T maxx,
        T maxy,
        T maxz)
{
    ranges.resize(3);

    ranges[0].minimum = minx;
    ranges[1].minimum = miny;
    ranges[2].minimum = minz;

    ranges[0].maximum = maxx;
    ranges[1].maximum = maxy;
    ranges[2].maximum = maxz;

#ifdef DEBUG
    verify();
#endif

}

Bounds( T minx,
        T miny,
        T maxx,
        T maxy)
{

    ranges.resize(2);

    ranges[0].minimum = minx;
    ranges[1].minimum = miny;

    ranges[0].maximum = maxx;
    ranges[1].maximum = maxy;

#ifdef DEBUG
    verify();
#endif

}

////Bounds( const Point& min, const Point& max)
////{
////    ranges.resize(3);
////
////    ranges[0].minimum = min.GetX();
////    ranges[1].minimum = min.GetY();
////    ranges[2].minimum = min.GetZ();
////
////    ranges[0].maximum = max.GetX();
////    ranges[1].maximum = max.GetY();
////    ranges[2].maximum = max.GetZ();
////
////#ifdef DEBUG
////    verify();
////#endif
////}

T (min)(std::size_t const& index) const
{
    if (ranges.size() <= index) {
        // std::ostringstream msg;
        // msg << "Bounds dimensions, " << ranges.size() <<", is less "
        //     << "than the given index, " << index;
        // throw std::runtime_error(msg.str());
        return 0;
    }
    return ranges[index].minimum;
}

void (min)(std::size_t const& index, T v)
{
    if (ranges.size() <= index) {
        ranges.resize(index + 1);
    }
    ranges[index].minimum = v;
}

T (max)(std::size_t const& index) const
{
    if (ranges.size() <= index) {
        // std::ostringstream msg;
        // msg << "Bounds dimensions, " << ranges.size() <<", is less "
        //     << "than the given index, " << index;
        // throw std::runtime_error(msg.str());
        return 0;
    }
    return ranges[index].maximum;
}

void (max)(std::size_t const& index, T v)
{
    if (ranges.size() <= index) {
        ranges.resize(index + 1);
    }
    ranges[index].maximum = v;
}

////liblas::Point (min)() {
////    liblas::Point p;
////    try
////    {
////        p.SetCoordinates(ranges[0].minimum, ranges[1].minimum, ranges[2].minimum);
////    }
////    catch (std::runtime_error const& e)
////    {
////        ::boost::ignore_unused_variable_warning(e);
////        p.SetCoordinates(ranges[0].minimum, ranges[1].minimum, 0);
////
////    }
////
////    return p;
////}
////
////liblas::Point (max)() {
////    liblas::Point p;
////    try
////    {
////        p.SetCoordinates(ranges[0].maximum, ranges[1].maximum, ranges[2].maximum);
////    }
////    catch (std::runtime_error const& e)
////    {
////        ::boost::ignore_unused_variable_warning(e);
////        p.SetCoordinates(ranges[0].maximum, ranges[1].maximum, 0);
////
////    }
////    return p;
////}

#if 0
// BUG: what are the semantics of these?
T minx() const { if (ranges.size() == 0) return 0; return ranges[0].minimum; }
T miny() const { if (ranges.size() < 2) return 0; return ranges[1].minimum; }
T minz() const { if (ranges.size() < 3) return 0; return ranges[2].minimum; }
T maxx() const { if (ranges.size() == 0) return 0; return ranges[0].maximum; }
T maxy() const { if (ranges.size() < 2) return 0; return ranges[1].maximum; }
T maxz() const { if (ranges.size() < 3) return 0; return ranges[2].maximum; }
#endif

inline bool operator==(Bounds<T> const& rhs) const
{
    return equal(rhs);
}

inline bool operator!=(Bounds<T> const& rhs) const
{
    return (!equal(rhs));
}

Bounds<T>& operator=(Bounds<T> const& rhs)
{
    if (&rhs != this)
    {
        ranges = rhs.ranges;
    }
    return *this;
}

/// The vector of Range<T> for the Bounds
RangeVec const& dims () const { return ranges; }

/// The number of dimensions of the Bounds
size_type dimension() const
{
    return ranges.size();
}

/// Resize the dimensionality of the Bounds to d
void dimension(size_type d)
{
    if (ranges.size() < d) {
        ranges.resize(d);
    }
}

/// Is this Bounds equal to other?
bool equal(Bounds<T> const& other) const
{
    for (size_type i = 0; i < dimension(); i++) {
        if ( ranges[i] != other.ranges[i] )
            return false;
    }
    return true;
}

/// Does this Bounds intersect other?
bool intersects(Bounds const& other) const
{

    for (size_type i = 0; i < dimension(); i++) {
        if ( ranges[i].overlaps(other.ranges[i]) )
            return true;
    }

    return false;

}

/// Synonym for intersects for now
bool overlaps(Bounds const& other) const
{
    return intersects(other);
}

/// Does this Bounds contain other?
bool contains(Bounds const& other) const
{
  // BUG: this loop only executes once, what is intended semantics?
  for (size_type i = 0; i < dimension(); i++) {
    if ( ranges[i].contains(other.ranges[i]) )
      return true;
    else // As soon as it is not contains, we're false
      return false;
  }
  return true;
}

/////// Does this Bounds this point other?
////bool contains(Point const& point) const
////{
////    // std::cout << ranges[0].length() << std::endl;
////    // std::cout << "x contain: " << ranges[0].contains(point.GetX())
////    //           << " r.x.min: " << ranges[0].min
////    //           << " r.x.max: " << ranges[0].max
////    //           << " p.x: " << point.GetX() << std::endl;
////    // std::cout << "y contain: " << ranges[1].contains(point.GetY())
////    //           << " r.y.min: " << ranges[1].min
////    //           << " r.y.max: " << ranges[1].max
////    //           << " p.y: " << point.GetY() << std::endl;
////    // std::cout << "z contain: " << ranges[2].contains(point.GetZ())
////    //           << " r.z.min: " << ranges[2].min
////    //           << " r.z.max: " << ranges[2].max
////    //           << " p.z: " << point.GetZ() << std::endl;
////    if (!ranges[0].contains(point.GetX()))
////        return false;
////    if (!ranges[1].contains(point.GetY()))
////        return false;
////
////    // If our z bounds has no length, we'll say it's contained anyway.
////    if (!ranges[2].contains(point.GetZ()))
////    {
////        if (detail::compare_distance(ranges[2].length(), 0.0))
////            return true;
////        return false;
////    }
////    return true;
////}
/// Shift each dimension by a vector of detlas
void shift(std::vector<T> deltas)
{
    typedef typename std::vector< T >::size_type size_type;

    size_type i;
    if( dimension() <= deltas.size())
    {
        std::ostringstream msg;
        msg << "liblas::Bounds::shift: Delta vector size, " << deltas.size()
            << ", is larger than the dimensionality of the bounds, "<< dimension() << ".";
        throw std::runtime_error(msg.str());
    }
    for (i = 0; i < deltas.size(); ++i){
        ranges[i].shift(deltas[i]);
    }
}

/// Scale each dimension by a vector of deltas
void scale(std::vector<T> deltas)
{
    typedef typename std::vector< T >::size_type size_type;

    size_type i;
    if( dimension() <= deltas.size())
    {
        std::ostringstream msg;
        msg << "liblas::Bounds::scale: Delta vector size, " << deltas.size()
            << ", is larger than the dimensionality of the bounds, "<< dimension() << ".";
        throw std::runtime_error(msg.str());
    }
    for (i = 0; i < deltas.size(); ++i){
        ranges[i].scale(deltas[i]);
    }
}

/// Clip this Bounds to the extent of r
void clip(Bounds const& r)
{
    RangeVec ds = r.dims();
    for (size_type i = 0; i < dimension(); ++i){
        ranges[i].clip(ds[i]);
    }
}

/// Grow to the union of two liblas::Bounds
void grow(Bounds const& r)
{
    RangeVec ds = r.dims();
    for (size_type i = 0; i < dimension(); ++i){
        ranges[i].grow(ds[i]);
    }
}

/// Expand the liblas::Bounds to include this point
////void grow(Point const& p)
////{
////    ranges[0].grow(p.GetX());
////    ranges[1].grow(p.GetY());
////    ranges[2].grow(p.GetZ());
////}

T volume() const
{
    T output = T();
    for (size_type i = 0; i < dimension(); i++) {
        output = output * ranges[i].length();
    }

    return output;
}

bool empty() const
{
    for (size_type i = 0; i < dimension(); i++) {
        if (ranges[i].empty())
            return true;
    }
    return false;
}

void verify()
{
    for (size_type d = 0; d < dimension(); ++d)
    {
        if ((min)(d) > (max)(d) )
        {
            // Check that we're not infinity either way
            if ( (Utils::compare_distance((min)(d), (std::numeric_limits<T>::max)()) ||
                  Utils::compare_distance((max)(d), -(std::numeric_limits<T>::max)()) ))
            {
                std::ostringstream msg;
                msg << "liblas::Bounds::verify: Minimum point at dimension " << d
                    << "is greater than maximum point.  Neither point is infinity.";
                throw std::runtime_error(msg.str());
            }
        }
    }
}

//friend std::ostream& operator<<(std::ostream& ostr, const Bounds<T>& bounds);

////Bounds<T> project(liblas::SpatialReference const& in_ref, liblas::SpatialReference const& out_ref)
////{
////    liblas::ReprojectionTransform trans(in_ref, out_ref);
////
////    liblas::Point minimum = (min)();
////    liblas::Point maximum = (max)();
////    trans.transform(minimum);
////    trans.transform(maximum);
////    return Bounds<T>(minimum, maximum);
////}

};

template<class T>
std::ostream& operator<<(std::ostream& ostr, const Bounds<T>& bounds)
{
  for (size_t d = 0; d < bounds.dimension(); ++d)
  {
      const Range<T>& r = bounds.dims()[d];
    ostr << "(" <<  r.minimum << "," << r.maximum << ")";
  }
  return ostr;
}

} // namespace libpc

// Needed for C++ DLL exports
#ifdef _MSC_VER
template class LIBPC_DLL libpc::Range<double>;
template class LIBPC_DLL libpc::Bounds<double>;
#endif

#endif
<commit_msg>don't replace header for liblas::Bounds<commit_after>/******************************************************************************
 * $Id$
 *
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 * Purpose:  LAS bounds class
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following
 * conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of the Martin Isenburg or Iowa Department
 *       of Natural Resources nor the names of its contributors may be
 *       used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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
 * COPYRIGHT OWNER OR 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.
 ****************************************************************************/

#ifndef INCLUDED_BOUNDS_HPP
#define INCLUDED_BOUNDS_HPP

#include <vector>
#include <iostream>
#include <sstream>
#include <string>

#include "libpc/export.hpp"
#include "libpc/Range.hpp"
#include "libpc/Utils.hpp"

namespace libpc
{

template <typename T>
class LIBPC_DLL Bounds
{
public:
  typedef T value_type;
  typedef typename std::vector< Range<T> >::size_type size_type;
  typedef typename std::vector< Range<T> > RangeVec;

private:
  RangeVec ranges;

public:

Bounds<T>()
{
    ranges.resize(0);
}

Bounds(Bounds const& other)
    :
    ranges(other.ranges)
{
}

Bounds(RangeVec const& rngs)
    :
    ranges(rngs)
{
}

Bounds( T minx,
        T miny,
        T minz,
        T maxx,
        T maxy,
        T maxz)
{
    ranges.resize(3);

    ranges[0].minimum = minx;
    ranges[1].minimum = miny;
    ranges[2].minimum = minz;

    ranges[0].maximum = maxx;
    ranges[1].maximum = maxy;
    ranges[2].maximum = maxz;

#ifdef DEBUG
    verify();
#endif

}

Bounds( T minx,
        T miny,
        T maxx,
        T maxy)
{

    ranges.resize(2);

    ranges[0].minimum = minx;
    ranges[1].minimum = miny;

    ranges[0].maximum = maxx;
    ranges[1].maximum = maxy;

#ifdef DEBUG
    verify();
#endif

}

////Bounds( const Point& min, const Point& max)
////{
////    ranges.resize(3);
////
////    ranges[0].minimum = min.GetX();
////    ranges[1].minimum = min.GetY();
////    ranges[2].minimum = min.GetZ();
////
////    ranges[0].maximum = max.GetX();
////    ranges[1].maximum = max.GetY();
////    ranges[2].maximum = max.GetZ();
////
////#ifdef DEBUG
////    verify();
////#endif
////}

T (min)(std::size_t const& index) const
{
    if (ranges.size() <= index) {
        // std::ostringstream msg;
        // msg << "Bounds dimensions, " << ranges.size() <<", is less "
        //     << "than the given index, " << index;
        // throw std::runtime_error(msg.str());
        return 0;
    }
    return ranges[index].minimum;
}

void (min)(std::size_t const& index, T v)
{
    if (ranges.size() <= index) {
        ranges.resize(index + 1);
    }
    ranges[index].minimum = v;
}

T (max)(std::size_t const& index) const
{
    if (ranges.size() <= index) {
        // std::ostringstream msg;
        // msg << "Bounds dimensions, " << ranges.size() <<", is less "
        //     << "than the given index, " << index;
        // throw std::runtime_error(msg.str());
        return 0;
    }
    return ranges[index].maximum;
}

void (max)(std::size_t const& index, T v)
{
    if (ranges.size() <= index) {
        ranges.resize(index + 1);
    }
    ranges[index].maximum = v;
}

////liblas::Point (min)() {
////    liblas::Point p;
////    try
////    {
////        p.SetCoordinates(ranges[0].minimum, ranges[1].minimum, ranges[2].minimum);
////    }
////    catch (std::runtime_error const& e)
////    {
////        ::boost::ignore_unused_variable_warning(e);
////        p.SetCoordinates(ranges[0].minimum, ranges[1].minimum, 0);
////
////    }
////
////    return p;
////}
////
////liblas::Point (max)() {
////    liblas::Point p;
////    try
////    {
////        p.SetCoordinates(ranges[0].maximum, ranges[1].maximum, ranges[2].maximum);
////    }
////    catch (std::runtime_error const& e)
////    {
////        ::boost::ignore_unused_variable_warning(e);
////        p.SetCoordinates(ranges[0].maximum, ranges[1].maximum, 0);
////
////    }
////    return p;
////}

#if 0
// BUG: what are the semantics of these?
T minx() const { if (ranges.size() == 0) return 0; return ranges[0].minimum; }
T miny() const { if (ranges.size() < 2) return 0; return ranges[1].minimum; }
T minz() const { if (ranges.size() < 3) return 0; return ranges[2].minimum; }
T maxx() const { if (ranges.size() == 0) return 0; return ranges[0].maximum; }
T maxy() const { if (ranges.size() < 2) return 0; return ranges[1].maximum; }
T maxz() const { if (ranges.size() < 3) return 0; return ranges[2].maximum; }
#endif

inline bool operator==(Bounds<T> const& rhs) const
{
    return equal(rhs);
}

inline bool operator!=(Bounds<T> const& rhs) const
{
    return (!equal(rhs));
}

Bounds<T>& operator=(Bounds<T> const& rhs)
{
    if (&rhs != this)
    {
        ranges = rhs.ranges;
    }
    return *this;
}

/// The vector of Range<T> for the Bounds
RangeVec const& dims () const { return ranges; }

/// The number of dimensions of the Bounds
size_type dimension() const
{
    return ranges.size();
}

/// Resize the dimensionality of the Bounds to d
void dimension(size_type d)
{
    if (ranges.size() < d) {
        ranges.resize(d);
    }
}

/// Is this Bounds equal to other?
bool equal(Bounds<T> const& other) const
{
    for (size_type i = 0; i < dimension(); i++) {
        if ( ranges[i] != other.ranges[i] )
            return false;
    }
    return true;
}

/// Does this Bounds intersect other?
bool intersects(Bounds const& other) const
{

    for (size_type i = 0; i < dimension(); i++) {
        if ( ranges[i].overlaps(other.ranges[i]) )
            return true;
    }

    return false;

}

/// Synonym for intersects for now
bool overlaps(Bounds const& other) const
{
    return intersects(other);
}

/// Does this Bounds contain other?
bool contains(Bounds const& other) const
{
  // BUG: this loop only executes once, what is intended semantics?
  for (size_type i = 0; i < dimension(); i++) {
    if ( ranges[i].contains(other.ranges[i]) )
      return true;
    else // As soon as it is not contains, we're false
      return false;
  }
  return true;
}

/////// Does this Bounds this point other?
////bool contains(Point const& point) const
////{
////    // std::cout << ranges[0].length() << std::endl;
////    // std::cout << "x contain: " << ranges[0].contains(point.GetX())
////    //           << " r.x.min: " << ranges[0].min
////    //           << " r.x.max: " << ranges[0].max
////    //           << " p.x: " << point.GetX() << std::endl;
////    // std::cout << "y contain: " << ranges[1].contains(point.GetY())
////    //           << " r.y.min: " << ranges[1].min
////    //           << " r.y.max: " << ranges[1].max
////    //           << " p.y: " << point.GetY() << std::endl;
////    // std::cout << "z contain: " << ranges[2].contains(point.GetZ())
////    //           << " r.z.min: " << ranges[2].min
////    //           << " r.z.max: " << ranges[2].max
////    //           << " p.z: " << point.GetZ() << std::endl;
////    if (!ranges[0].contains(point.GetX()))
////        return false;
////    if (!ranges[1].contains(point.GetY()))
////        return false;
////
////    // If our z bounds has no length, we'll say it's contained anyway.
////    if (!ranges[2].contains(point.GetZ()))
////    {
////        if (detail::compare_distance(ranges[2].length(), 0.0))
////            return true;
////        return false;
////    }
////    return true;
////}
/// Shift each dimension by a vector of detlas
void shift(std::vector<T> deltas)
{
    typedef typename std::vector< T >::size_type size_type;

    size_type i;
    if( dimension() <= deltas.size())
    {
        std::ostringstream msg;
        msg << "liblas::Bounds::shift: Delta vector size, " << deltas.size()
            << ", is larger than the dimensionality of the bounds, "<< dimension() << ".";
        throw std::runtime_error(msg.str());
    }
    for (i = 0; i < deltas.size(); ++i){
        ranges[i].shift(deltas[i]);
    }
}

/// Scale each dimension by a vector of deltas
void scale(std::vector<T> deltas)
{
    typedef typename std::vector< T >::size_type size_type;

    size_type i;
    if( dimension() <= deltas.size())
    {
        std::ostringstream msg;
        msg << "liblas::Bounds::scale: Delta vector size, " << deltas.size()
            << ", is larger than the dimensionality of the bounds, "<< dimension() << ".";
        throw std::runtime_error(msg.str());
    }
    for (i = 0; i < deltas.size(); ++i){
        ranges[i].scale(deltas[i]);
    }
}

/// Clip this Bounds to the extent of r
void clip(Bounds const& r)
{
    RangeVec ds = r.dims();
    for (size_type i = 0; i < dimension(); ++i){
        ranges[i].clip(ds[i]);
    }
}

/// Grow to the union of two liblas::Bounds
void grow(Bounds const& r)
{
    RangeVec ds = r.dims();
    for (size_type i = 0; i < dimension(); ++i){
        ranges[i].grow(ds[i]);
    }
}

/// Expand the liblas::Bounds to include this point
////void grow(Point const& p)
////{
////    ranges[0].grow(p.GetX());
////    ranges[1].grow(p.GetY());
////    ranges[2].grow(p.GetZ());
////}

T volume() const
{
    T output = T();
    for (size_type i = 0; i < dimension(); i++) {
        output = output * ranges[i].length();
    }

    return output;
}

bool empty() const
{
    for (size_type i = 0; i < dimension(); i++) {
        if (ranges[i].empty())
            return true;
    }
    return false;
}

void verify()
{
    for (size_type d = 0; d < dimension(); ++d)
    {
        if ((min)(d) > (max)(d) )
        {
            // Check that we're not infinity either way
            if ( (Utils::compare_distance((min)(d), (std::numeric_limits<T>::max)()) ||
                  Utils::compare_distance((max)(d), -(std::numeric_limits<T>::max)()) ))
            {
                std::ostringstream msg;
                msg << "liblas::Bounds::verify: Minimum point at dimension " << d
                    << "is greater than maximum point.  Neither point is infinity.";
                throw std::runtime_error(msg.str());
            }
        }
    }
}

//friend std::ostream& operator<<(std::ostream& ostr, const Bounds<T>& bounds);

////Bounds<T> project(liblas::SpatialReference const& in_ref, liblas::SpatialReference const& out_ref)
////{
////    liblas::ReprojectionTransform trans(in_ref, out_ref);
////
////    liblas::Point minimum = (min)();
////    liblas::Point maximum = (max)();
////    trans.transform(minimum);
////    trans.transform(maximum);
////    return Bounds<T>(minimum, maximum);
////}

};

template<class T>
std::ostream& operator<<(std::ostream& ostr, const Bounds<T>& bounds)
{
  for (size_t d = 0; d < bounds.dimension(); ++d)
  {
      const Range<T>& r = bounds.dims()[d];
    ostr << "(" <<  r.minimum << "," << r.maximum << ")";
  }
  return ostr;
}

} // namespace libpc

// Needed for C++ DLL exports
#ifdef _MSC_VER
template class LIBPC_DLL libpc::Range<double>;
template class LIBPC_DLL libpc::Bounds<double>;
#endif

#endif
<|endoftext|>


<commit_before>#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/system/error_code.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>

#include <libport/thread.hh>
#include <libport/lockable.hh>

namespace libport {
namespace netdetail {

  typedef ::libport::Socket::SocketFactory SocketFactory;
  class SocketImplBase: public BaseSocket, private libport::Lockable
  {
    public:
      SocketImplBase(): current_(-1), pending_(false) {}
      /// Start an asynchronous read operation.
      virtual void startReader() = 0;
    protected:
      /// Write double-buffer.
      boost::asio::streambuf buffers_[2];
      /// Read buffer.
      boost::asio::streambuf readBuffer_;
      /// Buffer id currently engaged in an async write, -1 for none
      int current_;
      /// Second buffer has data to write.
      bool pending_;
      friend class Socket;
      template<class Stream> friend class SocketImpl;
  };
  template<class Stream> class SocketImpl
    : public SocketImplBase
  {
    public:
      SocketImpl():base_(0) {}
      ~SocketImpl() { delete base_;}
      void write(const void* data, unsigned int length);
      void close();
      bool isConnected();
      template<typename Acceptor, typename BaseFactory> static void
        onAccept(Stream* s, SocketFactory fact, Acceptor *a, BaseFactory bf);
      template<typename Acceptor, typename BaseFactory> static void
        acceptOne(SocketFactory fact, Acceptor *a, BaseFactory bf);
      static BaseSocket* create(Stream* base);
      void startReader();
    private:
      Stream* base_;
      void continueWrite(DestructionLock lock, boost::system::error_code erc, size_t sz);
      void onReadDemux(DestructionLock lock, boost::system::error_code erc);
      friend class Socket;
    };

#ifndef LIBPORT_NO_SSL
  struct SSLSettings
  {
    boost::asio::ssl::context_base::method context;
    boost::asio::ssl::context::options options;
    std::string privateKeyFile;
    std::string certChainFile;
    std::string tmpDHFile;
    std::string cipherList;
  };
#endif

  // FIXME: use the delete_ptr in boost::lambda.
  template<class T> void deletor(T* ptr)
  {
    delete ptr;
  }

  inline void
  runIoService(boost::asio::io_service* io)
  {
    // Trick to have io->run() never return.
    boost::asio::io_service::work work(*io);
    io->run();
  }

  inline boost::asio::io_service&
  get_io_service()
  {
    static boost::asio::io_service* io = 0;
    if (!io)
    {
      io = new boost::asio::io_service;
      libport::startThread(boost::bind(&runIoService, io));
    }
    return *io;
  }

  template<typename Stream> void
  SocketImpl<Stream>::close()
  {
    base_->lowest_layer().close();
  }

  template<typename Stream> bool
  SocketImpl<Stream>::isConnected()
  {
    return base_->lowest_layer().is_open();
  }

  template<typename Stream> void
  SocketImpl<Stream>::write(const void* buffer, unsigned int length)
  {
    libport::BlockLock bl(this);
    std::ostream stream(&buffers_[current_==-1 ? 0:1-current_]);
    stream.write((const char*)buffer, length);
    pending_ = true;
    if (current_ == -1)
    {
      current_ = 1; // We wrote on 0, continueWrite will swap.
      continueWrite(getDestructionLock(), boost::system::error_code(), 0 );
    }
  }

  template<typename Stream> void
  SocketImpl<Stream>::continueWrite(DestructionLock lock, boost::system::error_code er, size_t sz)
  {
    if (er)
    {
      if (onErrorFunc)
	onErrorFunc(er);
      close();
      return;
    }
    libport::BlockLock bl(this);
    current_ = 1 - current_;
    if (pending_)
      boost::asio::async_write(*base_, buffers_[current_],
	  boost::bind(&SocketImpl<Stream>::continueWrite, this, lock,  _1, _2));
    else
    {
      current_ = -1;
    }
    pending_ = false;
  }

  template<typename Stream> void
  SocketImpl<Stream>::onReadDemux(DestructionLock lock, boost::system::error_code erc)
  {
    if (erc)
    {
      if (onErrorFunc)
	onErrorFunc(erc);
      close();
    }
    else
    {
      if (onReadFunc)
	onReadFunc(readBuffer_);
      if (isConnected())
	boost::asio::async_read(*base_, readBuffer_,  boost::asio::transfer_at_least(1),
	    boost::bind(&SocketImpl<Stream>::onReadDemux,this, lock, _1));
    }
  }

  template<typename Stream> void
  SocketImpl<Stream>::startReader()
  {
    boost::asio::async_read(*base_, readBuffer_,  boost::asio::transfer_at_least(1),
       	boost::bind(&SocketImpl<Stream>::onReadDemux,this, getDestructionLock(), _1));
  }

  template<typename Stream>
  template<typename Acceptor, typename BaseFactory> void
  SocketImpl<Stream>::onAccept(Stream* s, SocketFactory fact, Acceptor *a, BaseFactory bf)
  {
    SocketImplBase* wrapper = dynamic_cast<SocketImplBase*>(bf(s));
    if (!wrapper)
    { // Failure.
      delete s;
    }
    else
    {
      // This is now connected.
      Socket* s = fact();
      s->setBase(wrapper);
      // Start reading.
      wrapper->startReader();
    }
    acceptOne(fact, a, bf);
  }

  template<typename Stream>
  template<typename Acceptor, typename BaseFactory> void
  SocketImpl<Stream>::acceptOne(SocketFactory fact, Acceptor *a, BaseFactory bf)
  {
    Stream* s = new Stream(get_io_service());
    a->async_accept(*s,
	boost::bind(&SocketImpl<Stream>::template onAccept<Acceptor, BaseFactory>
	  , s, fact, a, bf));
  }

  template<typename Stream>BaseSocket*
  SocketImpl<Stream>::create(Stream*s)
  {
    SocketImpl<Stream>* bs = new SocketImpl<Stream>;
    bs->base_ = s;
    return bs;
  }

#ifndef LIBPORT_NO_SSL
  template<typename Stream>
  BaseSocket* SSLLayer(SSLSettings settings, Stream* s)
  {
    using namespace boost::asio;
    boost::system::error_code erc;
    ssl::context context(s->get_io_service(),
	boost::asio::ssl::context::sslv23_server);
    context.set_options(settings.options);
    if (!settings.cipherList.empty())
    {
      SSL_CTX* ctx = context.impl();
      if (!SSL_CTX_set_cipher_list(ctx, settings.cipherList.c_str()))
	throw std::runtime_error("SSL_CTX_set_cipher_list failed");
    }

#define comma ,
#define CHECK_CALL(param, call, args)  do \
    if (!param.empty()) { call(param, args erc); if (erc) throw erc;} while(0)

    CHECK_CALL(settings.tmpDHFile, context.use_tmp_dh_file, );
    CHECK_CALL(settings.certChainFile, context.use_certificate_chain_file, );
    CHECK_CALL(settings.privateKeyFile, context.use_private_key_file,
       	ssl::context_base::pem comma);
#undef CHECK_CALL

    // Create a SSL stream taking its underlying stream by ref.
    typedef boost::asio::ssl::stream<Stream&> SSLStream;
    SSLStream *sslStream = new SSLStream(*s, context);
    sslStream->handshake(sslStream->server, erc);
    if (erc)
    {
      delete sslStream;
      return 0;
    }
    BaseSocket* bs = SocketImpl<SSLStream>::create(sslStream);
    // s ownership is taken: mark for deletion when bs dies.
    bs->deletor << boost::bind(deletor<Stream>, s);
    return bs;
  }
#endif
} //namespace netdetail

inline void
Socket::setBase(BaseSocket* b)
{
  base_ = b;
  base_-> onReadFunc = boost::bind(&Socket::onRead_, this, _1);
  base_->onErrorFunc = boost::bind(&Socket::onError, this, _1);

}

inline bool
Socket::onRead_(boost::asio::streambuf& buf)
{
  // Dump the stream in our linear buffer
  std::istream is(&buf);
  while (true)
  {
    int c = is.get();
    if (!is.good())
      break;
    buffer += (char)c;
  }
  // Call unread until it eats 0 characters.
  int r;
  do
  {
    r = onRead(buffer.c_str(), buffer.length());
    if (r)
      buffer = buffer.substr(r, buffer.npos);
  }
  while(r && !buffer.empty());
  return true;
}

template<class Proto, class BaseFactory> boost::system::error_code
Socket::connectProto(const std::string& host, const std::string& port, BaseFactory bf)
{
  using namespace netdetail;
  boost::system::error_code erc;
  typename Proto::resolver::query query(host, port);
  typename Proto::resolver resolver(netdetail::get_io_service());
  typename Proto::resolver::iterator iter = resolver.resolve(query,erc);
  if (erc)
    return erc;
  typename Proto::socket* s = new typename Proto::socket(get_io_service());
  s->connect(*iter, erc);
  if (erc)
    return erc;
  SocketImplBase* newS = dynamic_cast<SocketImplBase*>(bf(s));
  if (!newS)
  {
    delete s;
#if BOOST_VERSION >= 103600
    return boost::system::errc::make_error_code(boost::system::errc::operation_canceled);
#else
    return boost::system::posix_error::make_error_code(boost::system::posix_error::operation_canceled);
#endif
}
  setBase(newS);
  // Start reading.
  newS->startReader();
  return erc;
}

inline boost::system::error_code
Socket::connect(const std::string& host, const std::string& port, bool udp)
{
  assert(!udp);
  /*
  if (udp)
    return connectProto<boost::asio::ip::udp>(host, port,
	&netdetail::SocketImpl<boost::asio::ip::udp::socket>::create);
  else
  */
    return connectProto<boost::asio::ip::tcp>(host, port,
	&netdetail::SocketImpl<boost::asio::ip::tcp::socket>::create);
}

template<typename Proto, typename BaseFactory> boost::system::error_code
Socket::listenProto(SocketFactory f, const std::string& host,
    const std::string& port, BaseFactory bf)
{
  boost::system::error_code erc;
  typename Proto::resolver::query query(host, port);
  typename Proto::resolver resolver(netdetail::get_io_service());
  typename Proto::resolver::iterator iter = resolver.resolve(query, erc);
  if (erc)
    return erc;
  typename Proto::acceptor* a = new typename Proto::acceptor(netdetail::get_io_service(), *iter);
  netdetail::SocketImpl<typename Proto::socket>::acceptOne(f, a, bf);
  return erc;
}

inline Socket::Handle
Socket::listen(SocketFactory f, const std::string& host,
    const std::string& port, boost::system::error_code & erc, bool udp)
{
  assert(!udp);
  erc = Socket::listenProto<boost::asio::ip::tcp>(f, host, port,
      &netdetail::SocketImpl<boost::asio::ip::tcp::socket>::create);
  return Handle();
}

#ifndef LIBPORT_NO_SSL
inline Socket::Handle
Socket::listenSSL(SocketFactory f, const std::string& host, const std::string&  port,
    boost::system::error_code& erc,
    boost::asio::ssl::context_base::method ctx,
    boost::asio::ssl::context::options options,
    const std::string& privateKeyFile,
    const std::string& certChainFile,
    const std::string& tmpDHFile,
    const std::string& cipherList)
{
  netdetail::SSLSettings settings;
  settings.context = ctx;
  settings.options = options;
  settings.privateKeyFile = privateKeyFile;
  settings.certChainFile = certChainFile;
  settings.tmpDHFile = tmpDHFile;
  settings.cipherList = cipherList;
  erc = Socket::listenProto<boost::asio::ip::tcp>(f, host, port,
      (boost::function1<BaseSocket*, boost::asio::ip::tcp::socket*>)boost::bind(&netdetail::SSLLayer<boost::asio::ip::tcp::socket>, settings, _1));
  return Handle();
}
#endif

inline
Socket::~Socket()
{
  close();
  base_->destroy();
  base_->onReadFunc = 0;
  base_->onErrorFunc = 0;
  base_ = 0;
}

inline void
Socket::destroy()
{
  close();
  AsioDestructible::destroy();
}

inline void
AsioDestructible::doDestroy()
{
  netdetail::get_io_service().post(boost::bind(
	netdetail::deletor<AsioDestructible>, this));
}

}
<commit_msg>asio: Copy streambuf to our buffer by blocks.<commit_after>#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/system/error_code.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>

#include <libport/thread.hh>
#include <libport/lockable.hh>

namespace libport {
namespace netdetail {

  typedef ::libport::Socket::SocketFactory SocketFactory;
  class SocketImplBase: public BaseSocket, private libport::Lockable
  {
    public:
      SocketImplBase(): current_(-1), pending_(false) {}
      /// Start an asynchronous read operation.
      virtual void startReader() = 0;
    protected:
      /// Write double-buffer.
      boost::asio::streambuf buffers_[2];
      /// Read buffer.
      boost::asio::streambuf readBuffer_;
      /// Buffer id currently engaged in an async write, -1 for none
      int current_;
      /// Second buffer has data to write.
      bool pending_;
      friend class Socket;
      template<class Stream> friend class SocketImpl;
  };
  template<class Stream> class SocketImpl
    : public SocketImplBase
  {
    public:
      SocketImpl():base_(0) {}
      ~SocketImpl() { delete base_;}
      void write(const void* data, unsigned int length);
      void close();
      bool isConnected();
      template<typename Acceptor, typename BaseFactory> static void
        onAccept(Stream* s, SocketFactory fact, Acceptor *a, BaseFactory bf);
      template<typename Acceptor, typename BaseFactory> static void
        acceptOne(SocketFactory fact, Acceptor *a, BaseFactory bf);
      static BaseSocket* create(Stream* base);
      void startReader();
    private:
      Stream* base_;
      void continueWrite(DestructionLock lock, boost::system::error_code erc, size_t sz);
      void onReadDemux(DestructionLock lock, boost::system::error_code erc);
      friend class Socket;
    };

#ifndef LIBPORT_NO_SSL
  struct SSLSettings
  {
    boost::asio::ssl::context_base::method context;
    boost::asio::ssl::context::options options;
    std::string privateKeyFile;
    std::string certChainFile;
    std::string tmpDHFile;
    std::string cipherList;
  };
#endif

  // FIXME: use the delete_ptr in boost::lambda.
  template<class T> void deletor(T* ptr)
  {
    delete ptr;
  }

  inline void
  runIoService(boost::asio::io_service* io)
  {
    // Trick to have io->run() never return.
    boost::asio::io_service::work work(*io);
    io->run();
  }

  inline boost::asio::io_service&
  get_io_service()
  {
    static boost::asio::io_service* io = 0;
    if (!io)
    {
      io = new boost::asio::io_service;
      libport::startThread(boost::bind(&runIoService, io));
    }
    return *io;
  }

  template<typename Stream> void
  SocketImpl<Stream>::close()
  {
    base_->lowest_layer().close();
  }

  template<typename Stream> bool
  SocketImpl<Stream>::isConnected()
  {
    return base_->lowest_layer().is_open();
  }

  template<typename Stream> void
  SocketImpl<Stream>::write(const void* buffer, unsigned int length)
  {
    libport::BlockLock bl(this);
    std::ostream stream(&buffers_[current_==-1 ? 0:1-current_]);
    stream.write((const char*)buffer, length);
    pending_ = true;
    if (current_ == -1)
    {
      current_ = 1; // We wrote on 0, continueWrite will swap.
      continueWrite(getDestructionLock(), boost::system::error_code(), 0 );
    }
  }

  template<typename Stream> void
  SocketImpl<Stream>::continueWrite(DestructionLock lock, boost::system::error_code er, size_t sz)
  {
    if (er)
    {
      if (onErrorFunc)
	onErrorFunc(er);
      close();
      return;
    }
    libport::BlockLock bl(this);
    current_ = 1 - current_;
    if (pending_)
      boost::asio::async_write(*base_, buffers_[current_],
	  boost::bind(&SocketImpl<Stream>::continueWrite, this, lock,  _1, _2));
    else
    {
      current_ = -1;
    }
    pending_ = false;
  }

  template<typename Stream> void
  SocketImpl<Stream>::onReadDemux(DestructionLock lock, boost::system::error_code erc)
  {
    if (erc)
    {
      if (onErrorFunc)
	onErrorFunc(erc);
      close();
    }
    else
    {
      if (onReadFunc)
	onReadFunc(readBuffer_);
      if (isConnected())
	boost::asio::async_read(*base_, readBuffer_,  boost::asio::transfer_at_least(1),
	    boost::bind(&SocketImpl<Stream>::onReadDemux,this, lock, _1));
    }
  }

  template<typename Stream> void
  SocketImpl<Stream>::startReader()
  {
    boost::asio::async_read(*base_, readBuffer_,  boost::asio::transfer_at_least(1),
       	boost::bind(&SocketImpl<Stream>::onReadDemux,this, getDestructionLock(), _1));
  }

  template<typename Stream>
  template<typename Acceptor, typename BaseFactory> void
  SocketImpl<Stream>::onAccept(Stream* s, SocketFactory fact, Acceptor *a, BaseFactory bf)
  {
    SocketImplBase* wrapper = dynamic_cast<SocketImplBase*>(bf(s));
    if (!wrapper)
    { // Failure.
      delete s;
    }
    else
    {
      // This is now connected.
      Socket* s = fact();
      s->setBase(wrapper);
      // Start reading.
      wrapper->startReader();
    }
    acceptOne(fact, a, bf);
  }

  template<typename Stream>
  template<typename Acceptor, typename BaseFactory> void
  SocketImpl<Stream>::acceptOne(SocketFactory fact, Acceptor *a, BaseFactory bf)
  {
    Stream* s = new Stream(get_io_service());
    a->async_accept(*s,
	boost::bind(&SocketImpl<Stream>::template onAccept<Acceptor, BaseFactory>
	  , s, fact, a, bf));
  }

  template<typename Stream>BaseSocket*
  SocketImpl<Stream>::create(Stream*s)
  {
    SocketImpl<Stream>* bs = new SocketImpl<Stream>;
    bs->base_ = s;
    return bs;
  }

#ifndef LIBPORT_NO_SSL
  template<typename Stream>
  BaseSocket* SSLLayer(SSLSettings settings, Stream* s)
  {
    using namespace boost::asio;
    boost::system::error_code erc;
    ssl::context context(s->get_io_service(),
	boost::asio::ssl::context::sslv23_server);
    context.set_options(settings.options);
    if (!settings.cipherList.empty())
    {
      SSL_CTX* ctx = context.impl();
      if (!SSL_CTX_set_cipher_list(ctx, settings.cipherList.c_str()))
	throw std::runtime_error("SSL_CTX_set_cipher_list failed");
    }

#define comma ,
#define CHECK_CALL(param, call, args)  do \
    if (!param.empty()) { call(param, args erc); if (erc) throw erc;} while(0)

    CHECK_CALL(settings.tmpDHFile, context.use_tmp_dh_file, );
    CHECK_CALL(settings.certChainFile, context.use_certificate_chain_file, );
    CHECK_CALL(settings.privateKeyFile, context.use_private_key_file,
       	ssl::context_base::pem comma);
#undef CHECK_CALL

    // Create a SSL stream taking its underlying stream by ref.
    typedef boost::asio::ssl::stream<Stream&> SSLStream;
    SSLStream *sslStream = new SSLStream(*s, context);
    sslStream->handshake(sslStream->server, erc);
    if (erc)
    {
      delete sslStream;
      return 0;
    }
    BaseSocket* bs = SocketImpl<SSLStream>::create(sslStream);
    // s ownership is taken: mark for deletion when bs dies.
    bs->deletor << boost::bind(deletor<Stream>, s);
    return bs;
  }
#endif
} //namespace netdetail

inline void
Socket::setBase(BaseSocket* b)
{
  base_ = b;
  base_-> onReadFunc = boost::bind(&Socket::onRead_, this, _1);
  base_->onErrorFunc = boost::bind(&Socket::onError, this, _1);

}

inline bool
Socket::onRead_(boost::asio::streambuf& buf)
{
  // Dump the stream in our linear buffer
  std::istream is(&buf);
  static const int blockSize = 1024;
  while (is.good())
  {
    int oldBufferLength = buffer.length();
    buffer.resize(oldBufferLength + blockSize);
    is.read(&buffer[0] + oldBufferLength, blockSize);
    long len = is.gcount();
    buffer.resize(oldBufferLength + len);
  }
  // Call onRead until it eats 0 characters.
  int r;
  do
  {
    r = onRead(buffer.c_str(), buffer.length());
    if (r)
      buffer = buffer.substr(r, buffer.npos);
  }
  while(r && !buffer.empty());
  return true;
}

template<class Proto, class BaseFactory> boost::system::error_code
Socket::connectProto(const std::string& host, const std::string& port, BaseFactory bf)
{
  using namespace netdetail;
  boost::system::error_code erc;
  typename Proto::resolver::query query(host, port);
  typename Proto::resolver resolver(netdetail::get_io_service());
  typename Proto::resolver::iterator iter = resolver.resolve(query,erc);
  if (erc)
    return erc;
  typename Proto::socket* s = new typename Proto::socket(get_io_service());
  s->connect(*iter, erc);
  if (erc)
    return erc;
  SocketImplBase* newS = dynamic_cast<SocketImplBase*>(bf(s));
  if (!newS)
  {
    delete s;
#if BOOST_VERSION >= 103600
    return boost::system::errc::make_error_code(boost::system::errc::operation_canceled);
#else
    return boost::system::posix_error::make_error_code(boost::system::posix_error::operation_canceled);
#endif
}
  setBase(newS);
  // Start reading.
  newS->startReader();
  return erc;
}

inline boost::system::error_code
Socket::connect(const std::string& host, const std::string& port, bool udp)
{
  assert(!udp);
  /*
  if (udp)
    return connectProto<boost::asio::ip::udp>(host, port,
	&netdetail::SocketImpl<boost::asio::ip::udp::socket>::create);
  else
  */
    return connectProto<boost::asio::ip::tcp>(host, port,
	&netdetail::SocketImpl<boost::asio::ip::tcp::socket>::create);
}

template<typename Proto, typename BaseFactory> boost::system::error_code
Socket::listenProto(SocketFactory f, const std::string& host,
    const std::string& port, BaseFactory bf)
{
  boost::system::error_code erc;
  typename Proto::resolver::query query(host, port);
  typename Proto::resolver resolver(netdetail::get_io_service());
  typename Proto::resolver::iterator iter = resolver.resolve(query, erc);
  if (erc)
    return erc;
  typename Proto::acceptor* a = new typename Proto::acceptor(netdetail::get_io_service(), *iter);
  netdetail::SocketImpl<typename Proto::socket>::acceptOne(f, a, bf);
  return erc;
}

inline Socket::Handle
Socket::listen(SocketFactory f, const std::string& host,
    const std::string& port, boost::system::error_code & erc, bool udp)
{
  assert(!udp);
  erc = Socket::listenProto<boost::asio::ip::tcp>(f, host, port,
      &netdetail::SocketImpl<boost::asio::ip::tcp::socket>::create);
  return Handle();
}

#ifndef LIBPORT_NO_SSL
inline Socket::Handle
Socket::listenSSL(SocketFactory f, const std::string& host, const std::string&  port,
    boost::system::error_code& erc,
    boost::asio::ssl::context_base::method ctx,
    boost::asio::ssl::context::options options,
    const std::string& privateKeyFile,
    const std::string& certChainFile,
    const std::string& tmpDHFile,
    const std::string& cipherList)
{
  netdetail::SSLSettings settings;
  settings.context = ctx;
  settings.options = options;
  settings.privateKeyFile = privateKeyFile;
  settings.certChainFile = certChainFile;
  settings.tmpDHFile = tmpDHFile;
  settings.cipherList = cipherList;
  erc = Socket::listenProto<boost::asio::ip::tcp>(f, host, port,
      (boost::function1<BaseSocket*, boost::asio::ip::tcp::socket*>)boost::bind(&netdetail::SSLLayer<boost::asio::ip::tcp::socket>, settings, _1));
  return Handle();
}
#endif

inline
Socket::~Socket()
{
  close();
  base_->destroy();
  base_->onReadFunc = 0;
  base_->onErrorFunc = 0;
  base_ = 0;
}

inline void
Socket::destroy()
{
  close();
  AsioDestructible::destroy();
}

inline void
AsioDestructible::doDestroy()
{
  netdetail::get_io_service().post(boost::bind(
	netdetail::deletor<AsioDestructible>, this));
}

}
<|endoftext|>