<commit_before>//
// Created by Danni on 09.06.15.
//

#include "TweeCompiler.h"
#include "ZAssemblyGenerator.h"
#include <sstream>
#include <iostream>
#include <Passage/Body/Link.h>
#include <Passage/Body/Text.h>

using namespace std;

static const string PASSAGE_GLOB = "PASSAGE_PTR",
        JUMP_TABLE_LABEL = "JUMP_TABLE_START",
        JUMP_TABLE_END_LABEL = "JUMP_TABLE_END",
        MAIN_ROUTINE = "main",
        USER_INPUT = "USER_INPUT",
        READ_BEGIN = "READ_BEGIN";

static const unsigned int ZSCII_NUM_OFFSET = 49;

//#define ZAS_DEBUG

string routineNameForPassageName(std::string passageName) {
    stringstream ss;
    ss << "R_" << passageName;
    return ss.str();
}

string routineNameForPassage(Passage& passage) {
    return routineNameForPassageName(passage.getHead().getName());
}

string labelForPassage(Passage& passage) {
    stringstream ss;
    ss << "L_" << passage.getHead().getName();
    return ss.str();
}

void TweeCompiler::compile(TweeFile &tweeFile, std::ostream &out) {
    ZAssemblyGenerator assgen(out);
    vector<Passage> passages = tweeFile.getPassages();

    {
        int i = 0;
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            passageName2id[passage->getHead().getName()] = i;
            i++;
        }
    }

    // main routine
    {
        // globals
        assgen.addGlobal(PASSAGE_GLOB)
                .addGlobal(USER_INPUT);

        // call start routine first
        assgen.addRoutine(MAIN_ROUTINE)
                .markStart()
                .call(routineNameForPassageName("start"), PASSAGE_GLOB)
                .addLabel(JUMP_TABLE_LABEL);

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            int passageId = passageName2id.at(passage->getHead().getName());

            assgen.jumpEquals(ZAssemblyGenerator::makeArgs({std::to_string(passageId), PASSAGE_GLOB}), labelForPassage(*passage));
        }

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            assgen.addLabel(labelForPassage(*passage))
                    .call(routineNameForPassage(*passage), PASSAGE_GLOB)
                    .jump(JUMP_TABLE_LABEL);
        }

        assgen.addLabel(JUMP_TABLE_END_LABEL);

        assgen.quit();
    }

    // passage routines
    {
        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            auto bodyParts = passage->getBody().getBodyParts();

            // declare passage routine
            assgen.addRoutine(routineNameForPassage(*passage));

            assgen.println(string("***** ") + passage->getHead().getName() + string(" *****"));

            //  print passage contents
            for(auto bodyPart = bodyParts.begin(); bodyPart != bodyParts.end(); bodyPart++) {
                if(Text* text = dynamic_cast<Text*>(*bodyPart)) {
                    assgen.print(text->getContent());
                }
            }

            assgen.newline();

            vector<Link*> links;
            // get links from passage
            for(auto bodyPart = bodyParts.begin(); bodyPart != bodyParts.end();
                ++bodyPart)
            {
                if(Link* link = dynamic_cast<Link*>(*bodyPart)) {
                    links.push_back(link);
                }
            }

            // present choices to user
            assgen.println("Select one of the following options:");
            int i = 1;
            for (auto link = links.begin(); link != links.end(); link++) {
                assgen.println(string("    ") + to_string(i) + string(") ") + (*link)->getTarget() );
                i++;
            }

            assgen.addLabel(READ_BEGIN);

            // read user input
            assgen.read_char(USER_INPUT);

            // jump to according link selection
            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                assgen.jumpEquals(ZAssemblyGenerator::makeArgs({USER_INPUT, to_string(ZSCII_NUM_OFFSET + i)}), label);

                i++;
            }

            // no proper selection was made
            assgen.jump(READ_BEGIN);

            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                try {
                    int targetPassageId = passageName2id.at((*link)->getTarget());
                    assgen.addLabel(label);
                    #ifdef ZAS_DEBUG
                    assgen.print(string("selected ") + to_string(targetPassageId) );
                    #endif
                    assgen.ret(to_string(targetPassageId));
                } catch (out_of_range &err) {
                    cerr << "could not find passage for link target\"" << (*link)->getTarget() << "\"" << endl;
                    throw;
                }
                i++;
            }
        }
    }
}
<commit_msg>fixed a few compiler quirks<commit_after>//
// Created by Danni on 09.06.15.
//

#include "TweeCompiler.h"
#include "ZAssemblyGenerator.h"
#include <sstream>
#include <iostream>
#include <Passage/Body/Link.h>
#include <Passage/Body/Text.h>

using namespace std;

static const string PASSAGE_GLOB = "PASSAGE_PTR",
        JUMP_TABLE_LABEL = "JUMP_TABLE_START",
        JUMP_TABLE_END_LABEL = "JUMP_TABLE_END",
        MAIN_ROUTINE = "main",
        USER_INPUT = "USER_INPUT",
        READ_BEGIN = "READ_BEGIN";

static const unsigned int ZSCII_NUM_OFFSET = 49;

//#define ZAS_DEBUG

void maskString(std::string& string) {
    std::replace( string.begin(), string.end(), ' ', '_');
}

string routineNameForPassageName(std::string passageName) {
    stringstream ss;
    maskString(passageName);
    ss << "R_" << passageName;
    return ss.str();
}

string routineNameForPassage(Passage& passage) {
    return routineNameForPassageName(passage.getHead().getName());
}

string labelForPassage(Passage& passage) {
    stringstream ss;
    string passageName = passage.getHead().getName();
    maskString(passageName);
    ss << "L_" << passageName;
    return ss.str();
}

void TweeCompiler::compile(TweeFile &tweeFile, std::ostream &out) {
    ZAssemblyGenerator assgen(out);
    vector<Passage> passages = tweeFile.getPassages();

    {
        int i = 0;
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            passageName2id[passage->getHead().getName()] = i;
            i++;
        }
    }

    // main routine
    {
        // globals
        assgen.addGlobal(PASSAGE_GLOB)
                .addGlobal(USER_INPUT);

        // call start routine first
        assgen.addRoutine(MAIN_ROUTINE)
                .markStart()
                .call(routineNameForPassageName("start"), PASSAGE_GLOB)
                .addLabel(JUMP_TABLE_LABEL);

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            int passageId = passageName2id.at(passage->getHead().getName());

            assgen.jumpEquals(ZAssemblyGenerator::makeArgs({std::to_string(passageId), PASSAGE_GLOB}), labelForPassage(*passage));
        }

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            assgen.addLabel(labelForPassage(*passage))
                    .call(routineNameForPassage(*passage), PASSAGE_GLOB)
                    .jump(JUMP_TABLE_LABEL);
        }

        assgen.addLabel(JUMP_TABLE_END_LABEL);

        assgen.quit();
    }

    // passage routines
    {
        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            auto bodyParts = passage->getBody().getBodyParts();

            // declare passage routine
            assgen.addRoutine(routineNameForPassage(*passage));

            assgen.println(string("***** ") + passage->getHead().getName() + string(" *****"));

            //  print passage contents
            for(auto bodyPart = bodyParts.begin(); bodyPart != bodyParts.end(); bodyPart++) {
                if(Text* text = dynamic_cast<Text*>(*bodyPart)) {
                    assgen.print(text->getContent());
                }
            }

            assgen.newline();

            vector<Link*> links;
            // get links from passage
            for(auto bodyPart = bodyParts.begin(); bodyPart != bodyParts.end();
                ++bodyPart)
            {
                if(Link* link = dynamic_cast<Link*>(*bodyPart)) {
                    links.push_back(link);
                }
            }

            // present choices to user
            assgen.println("Select one of the following options:");
            int i = 1;
            for (auto link = links.begin(); link != links.end(); link++) {
                assgen.println(string("    ") + to_string(i) + string(") ") + (*link)->getTarget() );
                i++;
            }

            assgen.addLabel(READ_BEGIN);

            // read user input
            assgen.read_char(USER_INPUT);

            // jump to according link selection
            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                assgen.jumpEquals(ZAssemblyGenerator::makeArgs({USER_INPUT, to_string(ZSCII_NUM_OFFSET + i)}), label);

                i++;
            }

            // no proper selection was made
            assgen.jump(READ_BEGIN);

            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                try {
                    int targetPassageId = passageName2id.at((*link)->getTarget());
                    assgen.addLabel(label);
                    #ifdef ZAS_DEBUG
                    assgen.print(string("selected ") + to_string(targetPassageId) );
                    #endif
                    assgen.ret(to_string(targetPassageId));
                } catch (out_of_range &err) {
                    cerr << "could not find passage for link target \"" << (*link)->getTarget() << "\"" << endl;
                    throw;
                }
                i++;
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>HtcVivePlugin, event based key press event detection<commit_after><|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include <iostream>
#include <fstream>
#include <stdexcept>

#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/geom_util.hpp>

// boost
#include <boost/algorithm/string.hpp>

using std::clog;
using std::endl;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(ogr_datasource)

using mapnik::box2d;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;
using mapnik::filter_in_box;
using mapnik::filter_at_point;

ogr_datasource::ogr_datasource(parameters const& params, bool bind)
   : datasource(params),
     extent_(),
     type_(datasource::Vector),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")),
     indexed_(false)
{
   OGRRegisterAll();

   boost::optional<std::string> file = params.get<std::string>("file");
   if (!file) throw datasource_exception("missing <file> parameter");

   multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);

   boost::optional<std::string> base = params_.get<std::string>("base");
   if (base)
      dataset_name_ = *base + "/" + *file;
   else
      dataset_name_ = *file;

   if (bind)
   {
      this->bind();
   }
}

void ogr_datasource::bind() const
{
   if (is_bound_) return;

   // open ogr driver
   dataset_ = OGRSFDriverRegistrar::Open ((dataset_name_).c_str(), FALSE);
   if (!dataset_)
   {
      std::string err = CPLGetLastErrorMsg();
      if( err.size() == 0 ) {
         throw datasource_exception("Connection failed: " + dataset_name_ + " was not found or is not a supported format");
      } else {
         throw datasource_exception(err);
      }
   }

   // initialize layer

   boost::optional<std::string> layer_by_name = params_.get<std::string>("layer");
   boost::optional<unsigned> layer_by_index = params_.get<unsigned>("layer_by_index");

   if (layer_by_name && layer_by_index)
       throw datasource_exception("OGR Plugin: you can only select an ogr layer by name ('layer' parameter) or by number ('layer_by_index' parameter), do not supply both parameters" );

   if (layer_by_name)
   {
       layerName_ = *layer_by_name;
       layer_ = dataset_->GetLayerByName (layerName_.c_str());
   }
   else if (layer_by_index)
   {
       unsigned num_layers = dataset_->GetLayerCount();
       if (*layer_by_index >= num_layers)
       {
           std::ostringstream s;
           s << "OGR Plugin: only ";
           s << num_layers;
           s << " layer(s) exist, cannot find layer by index '" << *layer_by_index << "'";

           throw datasource_exception(s.str());
       }
       OGRLayer  *ogr_layer = dataset_->GetLayer(*layer_by_index);
       if (ogr_layer)
       {
           OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
           if (def != 0) {
              layerName_ = def->GetName();
              layer_ = ogr_layer;
           }
       }
   }
   else
   {
      std::ostringstream s;
      s << "missing <layer> or <layer_by_index> parameter, available layers are: ";
      unsigned num_layers = dataset_->GetLayerCount();
      bool found = false;
      for (unsigned i = 0; i < num_layers; ++i )
      {
         OGRLayer  *ogr_layer = dataset_->GetLayer(i);
         OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
         if (def != 0) {
            found = true;
            s << " '" << def->GetName() << "' ";
         }
      }
      if (!found) {
          s << "None (no layers were found in dataset)";
      }
      throw datasource_exception(s.str());
   }

   if (!layer_)
   {
       std::string s("OGR Plugin: ");
       if (layer_by_name) s += "cannot find layer by name '" + *layer_by_name;
       else if (layer_by_index) s += "cannot find layer by index number '" + *layer_by_index;
       s += "' in dataset '" + dataset_name_ + "'";
       throw datasource_exception(s);
   }

   // initialize envelope
   OGREnvelope envelope;
   layer_->GetExtent (&envelope);
   extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY);

   // scan for index file
   // TODO - layer names don't match dataset name, so this will break for
   // any layer types of ogr than shapefiles, etc
   // fix here and in ogrindex
   size_t breakpoint = dataset_name_.find_last_of (".");
   if (breakpoint == std::string::npos) breakpoint = dataset_name_.length();
   index_name_ = dataset_name_.substr(0, breakpoint) + ".ogrindex";
   std::ifstream index_file (index_name_.c_str(), std::ios::in | std::ios::binary);
   if (index_file)
   {
      indexed_=true;
      index_file.close();
   }
   // enable this warning once the ogrindex tool is a bit more stable/mature
   //else
   /*{
      std::clog << "### Notice: no ogrindex file found for " + dataset_name_ + ", use the 'ogrindex' program to build an index for faster rendering\n";
   }*/

   // deal with attributes descriptions
   OGRFeatureDefn* def = layer_->GetLayerDefn ();
   if (def != 0)
   {
       int fld_count = def->GetFieldCount ();
       for (int i = 0; i < fld_count; i++)
       {
           OGRFieldDefn* fld = def->GetFieldDefn (i);

           std::string fld_name = fld->GetNameRef ();
           OGRFieldType type_oid = fld->GetType ();

           switch (type_oid)
           {
           case OFTInteger:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
               break;

           case OFTReal:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
               break;

           case OFTString:
           case OFTWideString: // deprecated
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
               break;

           case OFTBinary:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           case OFTIntegerList:
           case OFTRealList:
           case OFTStringList:
           case OFTWideStringList: // deprecated !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               break;

           case OFTDate:
           case OFTTime:
           case OFTDateTime: // unhandled !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           default: // unknown
#ifdef MAPNIK_DEBUG
               clog << "unknown type_oid=" << type_oid << endl;
#endif
               break;
           }
       }
   }

   is_bound_ = true;
}

ogr_datasource::~ogr_datasource()
{
    if (is_bound_)
    {
        OGRDataSource::DestroyDataSource (dataset_);
    }
}

std::string ogr_datasource::name()
{
   return "ogr";
}

int ogr_datasource::type() const
{
   return type_;
}

box2d<double> ogr_datasource::envelope() const
{
   if (!is_bound_) bind();
   return extent_;
}

layer_descriptor ogr_datasource::get_descriptor() const
{
   if (!is_bound_) bind();
   return desc_;
}

featureset_ptr ogr_datasource::features(query const& q) const
{
   if (!is_bound_) bind();

   if (dataset_ && layer_)
   {
#if 0
        std::ostringstream s;

        s << "select ";
        std::set<std::string> const& props=q.property_names();
        std::set<std::string>::const_iterator pos=props.begin();
        std::set<std::string>::const_iterator end=props.end();
        while (pos != end)
        {
           s <<",\""<<*pos<<"\"";
           ++pos;
        }
        s << " from " << layerName_ ;

        // execute existing SQL
        OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly);

        // layer must be freed
        dataset_->ReleaseResultSet (layer);
#endif

        if (indexed_)
        {
            filter_in_box filter(q.get_bbox());

            return featureset_ptr(new ogr_index_featureset<filter_in_box> (*dataset_,
                                                                           *layer_,
                                                                           filter,
                                                                           index_name_,
                                                                           desc_.get_encoding(),
                                                                           multiple_geometries_));
        }
        else
        {
            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      q.get_bbox(),
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
{
   if (!is_bound_) bind();

   if (dataset_ && layer_)
   {
        if (indexed_)
        {
            filter_at_point filter(pt);

            return featureset_ptr(new ogr_index_featureset<filter_at_point> (*dataset_,
                                                                             *layer_,
                                                                             filter,
                                                                             index_name_,
                                                                             desc_.get_encoding(),
                                                                             multiple_geometries_));
        }
        else
        {
            OGRPoint point;
	        point.setX (pt.x);
	        point.setY (pt.y);

            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      point,
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

<commit_msg>cosmetics<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include <iostream>
#include <fstream>
#include <stdexcept>

#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/geom_util.hpp>

// boost
#include <boost/algorithm/string.hpp>

using std::clog;
using std::endl;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(ogr_datasource)

using mapnik::box2d;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;
using mapnik::filter_in_box;
using mapnik::filter_at_point;

ogr_datasource::ogr_datasource(parameters const& params, bool bind)
   : datasource(params),
     extent_(),
     type_(datasource::Vector),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")),
     indexed_(false)
{
   OGRRegisterAll();

   boost::optional<std::string> file = params.get<std::string>("file");
   if (!file) throw datasource_exception("missing <file> parameter");

   multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);

   boost::optional<std::string> base = params_.get<std::string>("base");
   if (base)
      dataset_name_ = *base + "/" + *file;
   else
      dataset_name_ = *file;

   if (bind)
   {
      this->bind();
   }
}

void ogr_datasource::bind() const
{
   if (is_bound_) return;

   // open ogr driver
   dataset_ = OGRSFDriverRegistrar::Open ((dataset_name_).c_str(), FALSE);
   if (!dataset_)
   {
      std::string err = CPLGetLastErrorMsg();
      if( err.size() == 0 ) {
         throw datasource_exception("Connection failed: " + dataset_name_ + " was not found or is not a supported format");
      } else {
         throw datasource_exception(err);
      }
   }

   // initialize layer

   boost::optional<std::string> layer_by_name = params_.get<std::string>("layer");
   boost::optional<unsigned> layer_by_index = params_.get<unsigned>("layer_by_index");

   if (layer_by_name && layer_by_index)
       throw datasource_exception("OGR Plugin: you can only select an ogr layer by name ('layer' parameter) or by number ('layer_by_index' parameter), do not supply both parameters" );

   if (layer_by_name)
   {
       layerName_ = *layer_by_name;
       layer_ = dataset_->GetLayerByName (layerName_.c_str());
   }
   else if (layer_by_index)
   {
       unsigned num_layers = dataset_->GetLayerCount();
       if (*layer_by_index >= num_layers)
       {
           std::ostringstream s;
           s << "OGR Plugin: only ";
           s << num_layers;
           s << " layer(s) exist, cannot find layer by index '" << *layer_by_index << "'";

           throw datasource_exception(s.str());
       }
       OGRLayer  *ogr_layer = dataset_->GetLayer(*layer_by_index);
       if (ogr_layer)
       {
           OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
           if (def != 0) {
              layerName_ = def->GetName();
              layer_ = ogr_layer;
           }
       }
   }
   else
   {
      std::ostringstream s;
      s << "missing <layer> or <layer_by_index> parameter, available layers are: ";
      unsigned num_layers = dataset_->GetLayerCount();
      bool found = false;
      for (unsigned i = 0; i < num_layers; ++i )
      {
         OGRLayer  *ogr_layer = dataset_->GetLayer(i);
         OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
         if (def != 0) {
            found = true;
            s << " '" << def->GetName() << "' ";
         }
      }
      if (!found) {
          s << "None (no layers were found in dataset)";
      }
      throw datasource_exception(s.str());
   }

   if (!layer_)
   {
       std::string s("OGR Plugin: ");
       if (layer_by_name) s += "cannot find layer by name '" + *layer_by_name;
       else if (layer_by_index) s += "cannot find layer by index number '" + *layer_by_index;
       s += "' in dataset '" + dataset_name_ + "'";
       throw datasource_exception(s);
   }

   // initialize envelope
   OGREnvelope envelope;
   layer_->GetExtent (&envelope);
   extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY);

   // scan for index file
   // TODO - layer names don't match dataset name, so this will break for
   // any layer types of ogr than shapefiles, etc
   // fix here and in ogrindex
   size_t breakpoint = dataset_name_.find_last_of (".");
   if (breakpoint == std::string::npos) breakpoint = dataset_name_.length();
   index_name_ = dataset_name_.substr(0, breakpoint) + ".ogrindex";
   std::ifstream index_file (index_name_.c_str(), std::ios::in | std::ios::binary);
   if (index_file)
   {
      indexed_=true;
      index_file.close();
   }
   // enable this warning once the ogrindex tool is a bit more stable/mature
   //else
   /*{
      std::clog << "### Notice: no ogrindex file found for " + dataset_name_ + ", use the 'ogrindex' program to build an index for faster rendering\n";
   }*/

   // deal with attributes descriptions
   OGRFeatureDefn* def = layer_->GetLayerDefn ();
   if (def != 0)
   {
       int fld_count = def->GetFieldCount ();
       for (int i = 0; i < fld_count; i++)
       {
           OGRFieldDefn* fld = def->GetFieldDefn (i);

           std::string fld_name = fld->GetNameRef ();
           OGRFieldType type_oid = fld->GetType ();

           switch (type_oid)
           {
           case OFTInteger:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
               break;

           case OFTReal:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
               break;

           case OFTString:
           case OFTWideString: // deprecated
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
               break;

           case OFTBinary:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           case OFTIntegerList:
           case OFTRealList:
           case OFTStringList:
           case OFTWideStringList: // deprecated !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               break;

           case OFTDate:
           case OFTTime:
           case OFTDateTime: // unhandled !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           default: // unknown
#ifdef MAPNIK_DEBUG
               clog << "unknown type_oid=" << type_oid << endl;
#endif
               break;
           }
       }
   }

   is_bound_ = true;
}

ogr_datasource::~ogr_datasource()
{
    if (is_bound_)
    {
        OGRDataSource::DestroyDataSource (dataset_);
    }
}

std::string ogr_datasource::name()
{
   return "ogr";
}

int ogr_datasource::type() const
{
   return type_;
}

box2d<double> ogr_datasource::envelope() const
{
   if (!is_bound_) bind();
   return extent_;
}

layer_descriptor ogr_datasource::get_descriptor() const
{
   if (!is_bound_) bind();
   return desc_;
}

featureset_ptr ogr_datasource::features(query const& q) const
{
   if (!is_bound_) bind();

   if (dataset_ && layer_)
   {
#if 0
        std::ostringstream s;

        s << "select ";
        std::set<std::string> const& props=q.property_names();
        std::set<std::string>::const_iterator pos=props.begin();
        std::set<std::string>::const_iterator end=props.end();
        while (pos != end)
        {
           s <<",\""<<*pos<<"\"";
           ++pos;
        }
        s << " from " << layerName_ ;

        // execute existing SQL
        OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly);

        // layer must be freed
        dataset_->ReleaseResultSet (layer);
#endif

        if (indexed_)
        {
            filter_in_box filter(q.get_bbox());

            return featureset_ptr(new ogr_index_featureset<filter_in_box> (*dataset_,
                                                                           *layer_,
                                                                           filter,
                                                                           index_name_,
                                                                           desc_.get_encoding(),
                                                                           multiple_geometries_));
        }
        else
        {
            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      q.get_bbox(),
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
{
   if (!is_bound_) bind();

   if (dataset_ && layer_)
   {
        if (indexed_)
        {
            filter_at_point filter(pt);

            return featureset_ptr(new ogr_index_featureset<filter_at_point> (*dataset_,
                                                                             *layer_,
                                                                             filter,
                                                                             index_name_,
                                                                             desc_.get_encoding(),
                                                                             multiple_geometries_));
        }
        else
        {
            OGRPoint point;
	        point.setX (pt.x);
	        point.setY (pt.y);

            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      point,
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include <iostream>
#include <fstream>
#include <stdexcept>

#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/geom_util.hpp>

// boost
#include <boost/algorithm/string.hpp>

using std::clog;
using std::endl;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(ogr_datasource)

using mapnik::box2d;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;
using mapnik::filter_in_box;
using mapnik::filter_at_point;

ogr_datasource::ogr_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     type_(datasource::Vector),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")),
     indexed_(false)
{
   OGRRegisterAll();

   boost::optional<std::string> file = params.get<std::string>("file");
   if (!file) throw datasource_exception("missing <file> parameter");

   multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);

   boost::optional<std::string> base = params.get<std::string>("base");
   if (base)
      dataset_name_ = *base + "/" + *file;
   else
      dataset_name_ = *file;

   // open ogr driver
   dataset_ = OGRSFDriverRegistrar::Open ((dataset_name_).c_str(), FALSE);
   if (!dataset_)
   {
      std::string err = CPLGetLastErrorMsg();
      if( err.size() == 0 ) {
         throw datasource_exception("Connection failed: " + dataset_name_ + " was not found or is not a supported format");
      } else {
         throw datasource_exception(err);
      }
   }

   // initialize layer

   boost::optional<std::string> layer_by_name = params.get<std::string>("layer");
   boost::optional<unsigned> layer_by_index = params.get<unsigned>("layer_by_index");

   if (layer_by_name && layer_by_index)
       throw datasource_exception("OGR Plugin: you can only select an ogr layer by name ('layer' parameter) or by number ('layer_by_index' parameter), do not supply both parameters" );

   if (layer_by_name)
   {
       layerName_ = *layer_by_name;
       layer_ = dataset_->GetLayerByName (layerName_.c_str());
   }
   else if (layer_by_index)
   {
       OGRLayer  *ogr_layer = dataset_->GetLayer(*layer_by_index);
       if (ogr_layer)
       {
           OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
           if (def != 0) {
              layerName_ = def->GetName();
              layer_ = ogr_layer;
           }
       }
   }
   else
   {
      std::ostringstream s;
      s << "missing <layer> or <layer_by_index> parameter, available layers are: ";
      unsigned num_layers = dataset_->GetLayerCount();
      bool found = false;
      for (unsigned i = 0; i < num_layers; ++i )
      {
         OGRLayer  *ogr_layer = dataset_->GetLayer(i);
         OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
         if (def != 0) {
            found = true;
            s << " '" << def->GetName() << "' ";
         }
      }
      if (!found) {
          s << "None (no layers were found in dataset)";
      }
      throw datasource_exception(s.str());
   }

   if (!layer_)
   {
       std::string s("OGR Plugin: ");
       if (layer_by_name) s += "cannot find layer by name '" + *layer_by_name;
       else if (layer_by_index) s += "cannot find layer by index number '" + *layer_by_index;
       s += "' in dataset '" + dataset_name_ + "'";
       throw datasource_exception(s);
   }

   // initialize envelope
   OGREnvelope envelope;
   layer_->GetExtent (&envelope);
   extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY);

   // scan for index file
   // TODO - layer names don't match dataset name, so this will break for
   // any layer types of ogr than shapefiles, etc
   // fix here and in ogrindex
   size_t breakpoint = dataset_name_.find_last_of (".");
   if (breakpoint == std::string::npos) breakpoint = dataset_name_.length();
   index_name_ = dataset_name_.substr(0, breakpoint) + ".ogrindex";
   std::ifstream index_file (index_name_.c_str(), std::ios::in | std::ios::binary);
   if (index_file)
   {
      indexed_=true;
      index_file.close();
   }
   // enable this warning once the ogrindex tool is a bit more stable/mature
   //else
   /*{
      std::clog << "### Notice: no ogrindex file found for " + dataset_name_ + ", use the 'ogrindex' program to build an index for faster rendering\n";
   }*/

   // deal with attributes descriptions
   OGRFeatureDefn* def = layer_->GetLayerDefn ();
   if (def != 0)
   {
       int fld_count = def->GetFieldCount ();
       for (int i = 0; i < fld_count; i++)
       {
           OGRFieldDefn* fld = def->GetFieldDefn (i);

           std::string fld_name = fld->GetNameRef ();
           OGRFieldType type_oid = fld->GetType ();

           switch (type_oid)
           {
           case OFTInteger:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
               break;

           case OFTReal:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
               break;

           case OFTString:
           case OFTWideString: // deprecated
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
               break;

           case OFTBinary:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           case OFTIntegerList:
           case OFTRealList:
           case OFTStringList:
           case OFTWideStringList: // deprecated !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               break;

           case OFTDate:
           case OFTTime:
           case OFTDateTime: // unhandled !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           default: // unknown
#ifdef MAPNIK_DEBUG
               clog << "unknown type_oid=" << type_oid << endl;
#endif
               break;
           }
       }
   }
}

ogr_datasource::~ogr_datasource()
{
    OGRDataSource::DestroyDataSource (dataset_);
}

std::string ogr_datasource::name()
{
   return "ogr";
}

int ogr_datasource::type() const
{
   return type_;
}

box2d<double> ogr_datasource::envelope() const
{
   return extent_;
}

layer_descriptor ogr_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr ogr_datasource::features(query const& q) const
{
   if (dataset_ && layer_)
   {
#if 0
        std::ostringstream s;

        s << "select ";
        std::set<std::string> const& props=q.property_names();
        std::set<std::string>::const_iterator pos=props.begin();
        std::set<std::string>::const_iterator end=props.end();
        while (pos != end)
        {
           s <<",\""<<*pos<<"\"";
           ++pos;
        }
        s << " from " << layerName_ ;

        // execute existing SQL
        OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly);

        // layer must be freed
        dataset_->ReleaseResultSet (layer);
#endif

        if (indexed_)
        {
            filter_in_box filter(q.get_bbox());

            return featureset_ptr(new ogr_index_featureset<filter_in_box> (*dataset_,
                                                                           *layer_,
                                                                           filter,
                                                                           index_name_,
                                                                           desc_.get_encoding(),
                                                                           multiple_geometries_));
        }
        else
        {
            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      q.get_bbox(),
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
{
   if (dataset_ && layer_)
   {
        if (indexed_)
        {
            filter_at_point filter(pt);

            return featureset_ptr(new ogr_index_featureset<filter_at_point> (*dataset_,
                                                                             *layer_,
                                                                             filter,
                                                                             index_name_,
                                                                             desc_.get_encoding(),
                                                                             multiple_geometries_));
        }
        else
        {
            OGRPoint point;
	        point.setX (pt.x);
	        point.setY (pt.y);

            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      point,
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

<commit_msg>make sure the user does not request a layer by index greater than exists in the dataset<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include <iostream>
#include <fstream>
#include <stdexcept>

#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/geom_util.hpp>

// boost
#include <boost/algorithm/string.hpp>

using std::clog;
using std::endl;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(ogr_datasource)

using mapnik::box2d;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;
using mapnik::filter_in_box;
using mapnik::filter_at_point;

ogr_datasource::ogr_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     type_(datasource::Vector),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")),
     indexed_(false)
{
   OGRRegisterAll();

   boost::optional<std::string> file = params.get<std::string>("file");
   if (!file) throw datasource_exception("missing <file> parameter");

   multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);

   boost::optional<std::string> base = params.get<std::string>("base");
   if (base)
      dataset_name_ = *base + "/" + *file;
   else
      dataset_name_ = *file;

   // open ogr driver
   dataset_ = OGRSFDriverRegistrar::Open ((dataset_name_).c_str(), FALSE);
   if (!dataset_)
   {
      std::string err = CPLGetLastErrorMsg();
      if( err.size() == 0 ) {
         throw datasource_exception("Connection failed: " + dataset_name_ + " was not found or is not a supported format");
      } else {
         throw datasource_exception(err);
      }
   }

   // initialize layer

   boost::optional<std::string> layer_by_name = params.get<std::string>("layer");
   boost::optional<unsigned> layer_by_index = params.get<unsigned>("layer_by_index");

   if (layer_by_name && layer_by_index)
       throw datasource_exception("OGR Plugin: you can only select an ogr layer by name ('layer' parameter) or by number ('layer_by_index' parameter), do not supply both parameters" );

   if (layer_by_name)
   {
       layerName_ = *layer_by_name;
       layer_ = dataset_->GetLayerByName (layerName_.c_str());
   }
   else if (layer_by_index)
   {
       unsigned num_layers = dataset_->GetLayerCount();
       if (*layer_by_index >= num_layers)
       {
           std::ostringstream s;
           s << "OGR Plugin: only ";
           s << num_layers;
           s << " layer(s) exist, cannot find layer by index '" << *layer_by_index << "'";

           throw datasource_exception(s.str());
       }
       OGRLayer  *ogr_layer = dataset_->GetLayer(*layer_by_index);
       if (ogr_layer)
       {
           OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
           if (def != 0) {
              layerName_ = def->GetName();
              layer_ = ogr_layer;
           }
       }
   }
   else
   {
      std::ostringstream s;
      s << "missing <layer> or <layer_by_index> parameter, available layers are: ";
      unsigned num_layers = dataset_->GetLayerCount();
      bool found = false;
      for (unsigned i = 0; i < num_layers; ++i )
      {
         OGRLayer  *ogr_layer = dataset_->GetLayer(i);
         OGRFeatureDefn* def = ogr_layer->GetLayerDefn();
         if (def != 0) {
            found = true;
            s << " '" << def->GetName() << "' ";
         }
      }
      if (!found) {
          s << "None (no layers were found in dataset)";
      }
      throw datasource_exception(s.str());
   }

   if (!layer_)
   {
       std::string s("OGR Plugin: ");
       if (layer_by_name) s += "cannot find layer by name '" + *layer_by_name;
       else if (layer_by_index) s += "cannot find layer by index number '" + *layer_by_index;
       s += "' in dataset '" + dataset_name_ + "'";
       throw datasource_exception(s);
   }

   // initialize envelope
   OGREnvelope envelope;
   layer_->GetExtent (&envelope);
   extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY);

   // scan for index file
   // TODO - layer names don't match dataset name, so this will break for
   // any layer types of ogr than shapefiles, etc
   // fix here and in ogrindex
   size_t breakpoint = dataset_name_.find_last_of (".");
   if (breakpoint == std::string::npos) breakpoint = dataset_name_.length();
   index_name_ = dataset_name_.substr(0, breakpoint) + ".ogrindex";
   std::ifstream index_file (index_name_.c_str(), std::ios::in | std::ios::binary);
   if (index_file)
   {
      indexed_=true;
      index_file.close();
   }
   // enable this warning once the ogrindex tool is a bit more stable/mature
   //else
   /*{
      std::clog << "### Notice: no ogrindex file found for " + dataset_name_ + ", use the 'ogrindex' program to build an index for faster rendering\n";
   }*/

   // deal with attributes descriptions
   OGRFeatureDefn* def = layer_->GetLayerDefn ();
   if (def != 0)
   {
       int fld_count = def->GetFieldCount ();
       for (int i = 0; i < fld_count; i++)
       {
           OGRFieldDefn* fld = def->GetFieldDefn (i);

           std::string fld_name = fld->GetNameRef ();
           OGRFieldType type_oid = fld->GetType ();

           switch (type_oid)
           {
           case OFTInteger:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
               break;

           case OFTReal:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
               break;

           case OFTString:
           case OFTWideString: // deprecated
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
               break;

           case OFTBinary:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           case OFTIntegerList:
           case OFTRealList:
           case OFTStringList:
           case OFTWideStringList: // deprecated !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               break;

           case OFTDate:
           case OFTTime:
           case OFTDateTime: // unhandled !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           default: // unknown
#ifdef MAPNIK_DEBUG
               clog << "unknown type_oid=" << type_oid << endl;
#endif
               break;
           }
       }
   }
}

ogr_datasource::~ogr_datasource()
{
    OGRDataSource::DestroyDataSource (dataset_);
}

std::string ogr_datasource::name()
{
   return "ogr";
}

int ogr_datasource::type() const
{
   return type_;
}

box2d<double> ogr_datasource::envelope() const
{
   return extent_;
}

layer_descriptor ogr_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr ogr_datasource::features(query const& q) const
{
   if (dataset_ && layer_)
   {
#if 0
        std::ostringstream s;

        s << "select ";
        std::set<std::string> const& props=q.property_names();
        std::set<std::string>::const_iterator pos=props.begin();
        std::set<std::string>::const_iterator end=props.end();
        while (pos != end)
        {
           s <<",\""<<*pos<<"\"";
           ++pos;
        }
        s << " from " << layerName_ ;

        // execute existing SQL
        OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly);

        // layer must be freed
        dataset_->ReleaseResultSet (layer);
#endif

        if (indexed_)
        {
            filter_in_box filter(q.get_bbox());

            return featureset_ptr(new ogr_index_featureset<filter_in_box> (*dataset_,
                                                                           *layer_,
                                                                           filter,
                                                                           index_name_,
                                                                           desc_.get_encoding(),
                                                                           multiple_geometries_));
        }
        else
        {
            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      q.get_bbox(),
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
{
   if (dataset_ && layer_)
   {
        if (indexed_)
        {
            filter_at_point filter(pt);

            return featureset_ptr(new ogr_index_featureset<filter_at_point> (*dataset_,
                                                                             *layer_,
                                                                             filter,
                                                                             index_name_,
                                                                             desc_.get_encoding(),
                                                                             multiple_geometries_));
        }
        else
        {
            OGRPoint point;
	        point.setX (pt.x);
	        point.setY (pt.y);

            return featureset_ptr(new ogr_featureset (*dataset_,
                                                      *layer_,
                                                      point,
                                                      desc_.get_encoding(),
                                                      multiple_geometries_));
        }
   }
   return featureset_ptr();
}

<|endoftext|>


<commit_before>#include <list>
#include <set>

#include "boost/asio.hpp"

#include "vtrc-thread-pool.h"
#include "vtrc-mutex-typedefs.h"
#include "vtrc-memory.h"
#include "vtrc-bind.h"
#include "vtrc-thread.h"

///// TODO: need some fix here
namespace vtrc { namespace common {

    namespace basio = boost::asio;

    typedef vtrc::unique_ptr<vtrc::thread> thread_ptr;

    struct thread_context {
        typedef vtrc::shared_ptr<thread_context> shared_type;
        thread_ptr thread_;
    };

    inline bool operator < ( const thread_context &l, const thread_context &r )
    {
        return  l.thread_.get( ) < r.thread_.get( );
    }

    typedef std::set<thread_context::shared_type>  thread_set_type;

    struct thread_pool::impl {

        basio::io_service       *ios_;
        basio::io_service::work *wrk_;
        bool                     own_ios_;

        thread_set_type          threads_;
        thread_set_type          stopped_threads_;

        mutable shared_mutex     threads_lock_;

        struct interrupt {
            static void raise ( ) { throw interrupt( ); }
        };

        impl( basio::io_service *ios, bool own_ios )
            :ios_(ios)
            ,wrk_(new basio::io_service::work(*ios_))
            ,own_ios_(own_ios)
        { }

        ~impl( )
        {
            try {
                stop( );
                join_all( );
            } catch( ... ) {
                ;;;
            }

            if( own_ios_ ) {
                delete ios_;
            }
        }

        void move_to_stopped( thread_context::shared_type &thread )
        {
            unique_shared_lock lck(threads_lock_);

            stopped_threads_.insert( thread );
            threads_.erase( thread );
        }

        void add( size_t count )
        {
            std::list<thread_context::shared_type> tmp;
            while( count-- ) {
                tmp.push_back(create_thread( ));
            }
            unique_shared_lock lck(threads_lock_);
            threads_.insert( tmp.begin( ), tmp.end( ) );
            stopped_threads_.clear( );
        }

        void inc( )
        {
            thread_context::shared_type n(create_thread( ));
            unique_shared_lock lck( threads_lock_ );
            threads_.insert( n );
            stopped_threads_.clear( );
        }

        thread_context::shared_type create_thread(  )
        {

            thread_context::shared_type new_inst(
                        vtrc::make_shared<thread_context>( ));

            new_inst->thread_.reset(
                     new vtrc::thread(vtrc::bind(&impl::run, this, new_inst)));

            return new_inst;
        }

        void interrupt_one( )
        {
            ios_->post( interrupt::raise );
        }

        size_t size( ) const
        {
            shared_lock lck(threads_lock_);
            return threads_.size( );
        }

        static bool is_this_id( const  thread_ptr &th )
        {
            return vtrc::this_thread::get_id( ) == th->get_id( );
        }

        void join_all( )
        {
            typedef thread_set_type::iterator iterator;
            thread_set_type tmp;
            {
                /// own threads
                unique_shared_lock lck(threads_lock_);
                tmp.swap( threads_ );
            }

            /// join
            for(iterator b(tmp.begin( )), e(tmp.end( )); b!=e; ++b ) {
                if( (*b)->thread_->joinable( ) && !is_this_id( (*b)->thread_) )
                    (*b)->thread_->join( );
            }

            /// clean stopped
            unique_shared_lock lck(threads_lock_);
            stopped_threads_.clear( );
        }

        void stop( )
        {

            delete wrk_;
            wrk_ = NULL;

            ios_->stop( );
            unique_shared_lock lck(threads_lock_);
            stopped_threads_.clear( );
        }

        void run( thread_context::shared_type thread )
        {
            run_impl( thread.get( ) );
            move_to_stopped( thread ); /// must not remove it here;
                                       /// moving to stopped_thread_
        }

        bool run_impl( thread_context * /*context*/ )
        {
            while ( true  ) {
                try {
                    while ( true ) {
                        const size_t count = ios_->run_one( );
                        if( !count ) return true; /// stopped;
                    }
                } catch( const interrupt & ) {
                    break;
                } catch( const boost::thread_interrupted & ) {
                    break;
                } catch( const std::exception &) {
                    ;;;
                }
            }
            return false; /// interruped by interrupt::raise or
                          ///               boost::thread_interrupted
        }

        bool attach( )
        {
            return run_impl( NULL );
        }

    };

    thread_pool::thread_pool( )
        :impl_(new impl(new basio::io_service, true))
    { }

    thread_pool::thread_pool( size_t init_count )
        :impl_(new impl(new basio::io_service, true))
    {
        impl_->add( init_count );
    }

    thread_pool::thread_pool( boost::asio::io_service &ios, size_t init_count )
        :impl_(new impl(&ios, false))
    {
        impl_->add( init_count );
    }

    thread_pool::thread_pool( boost::asio::io_service &ios )
        :impl_(new impl(&ios, false))
    { }

    thread_pool::~thread_pool( )
    {
        delete impl_;
    }

    size_t thread_pool::size( ) const
    {
        return impl_->size( );
    }

    void thread_pool::interrupt_one( )
    {
        impl_->interrupt_one( );
    }

    void thread_pool::stop( )
    {
        impl_->stop( );
    }

    void thread_pool::join_all( )
    {
        impl_->join_all( );
    }

    bool thread_pool::attach( )
    {
        return impl_->attach( );
    }

    void thread_pool::add_thread( )
    {
        impl_->inc( );
    }

    void thread_pool::add_threads( size_t count )
    {
        impl_->add(count);
    }

    boost::asio::io_service &thread_pool::get_io_service( )
    {
        return *impl_->ios_;
    }

    const boost::asio::io_service &thread_pool::get_io_service( ) const
    {
        return *impl_->ios_;
    }
}}
<commit_msg>stress<commit_after>#include <list>
#include <set>

#include "boost/asio.hpp"

#include "vtrc-thread-pool.h"
#include "vtrc-mutex-typedefs.h"
#include "vtrc-memory.h"
#include "vtrc-bind.h"
#include "vtrc-thread.h"

///// TODO: need some fix here
namespace vtrc { namespace common {

    namespace basio = boost::asio;

    typedef vtrc::unique_ptr<vtrc::thread> thread_ptr;

    struct thread_context {
        typedef vtrc::shared_ptr<thread_context> shared_type;
        thread_ptr thread_;
    };

    inline bool operator < ( const thread_context &l, const thread_context &r )
    {
        return  l.thread_.get( ) < r.thread_.get( );
    }

    typedef std::set<thread_context::shared_type>  thread_set_type;

    struct thread_pool::impl {

        basio::io_service       *ios_;
        basio::io_service::work *wrk_;
        bool                     own_ios_;

        thread_set_type          threads_;
        thread_set_type          stopped_threads_;

        mutable shared_mutex     threads_lock_;

        struct interrupt {
            static void raise ( ) { throw interrupt( ); }
        };

        impl( basio::io_service *ios, bool own_ios )
            :ios_(ios)
            ,wrk_(new basio::io_service::work(*ios_))
            ,own_ios_(own_ios)
        { }

        ~impl( )
        {
            try {
                stop( );
                join_all( );
            } catch( ... ) {
                ;;;
            }

            if( own_ios_ ) {
                delete ios_;
            }
        }

        void add( size_t count )
        {
            std::list<thread_context::shared_type> tmp;
            while( count-- ) {
                tmp.push_back(create_thread( ));
            }
            unique_shared_lock lck(threads_lock_);
            threads_.insert( tmp.begin( ), tmp.end( ) );
            stopped_threads_.clear( );
        }

        void inc( )
        {
            thread_context::shared_type n(create_thread( ));
            unique_shared_lock lck( threads_lock_ );
            threads_.insert( n );
            stopped_threads_.clear( );
        }

        thread_context::shared_type create_thread(  )
        {

            thread_context::shared_type new_inst(
                        vtrc::make_shared<thread_context>( ));

            new_inst->thread_.reset(
                     new vtrc::thread(vtrc::bind(&impl::run, this, new_inst)));

            return new_inst;
        }

        void interrupt_one( )
        {
            ios_->post( interrupt::raise );
        }

        size_t size( ) const
        {
            shared_lock lck(threads_lock_);
            return threads_.size( );
        }

        static bool is_this_id( const  thread_ptr &th )
        {
            return vtrc::this_thread::get_id( ) == th->get_id( );
        }

        void join_all( )
        {
            typedef thread_set_type::iterator iterator;
            thread_set_type tmp;
            {
                /// own threads
                unique_shared_lock lck(threads_lock_);
                tmp.swap( threads_ );
            }

            /// join
            for(iterator b(tmp.begin( )), e(tmp.end( )); b!=e; ++b ) {
                if( (*b)->thread_->joinable( ) && !is_this_id( (*b)->thread_) )
                    (*b)->thread_->join( );
            }

            /// clean stopped
            unique_shared_lock lck(threads_lock_);
            stopped_threads_.clear( );
        }

        void stop( )
        {

            delete wrk_;
            wrk_ = NULL;

            ios_->stop( );
            unique_shared_lock lck(threads_lock_);
            stopped_threads_.clear( );
        }

        void move_to_stopped( thread_context::shared_type &thread )
        {
            unique_shared_lock lck(threads_lock_);

            stopped_threads_.insert( thread );
            threads_.erase( thread );
        }

        void run( thread_context::shared_type thread )
        {
            run_impl( thread.get( ) );
//            move_to_stopped( thread ); /// must not remove it here;
//                                       /// moving to stopped_thread_
        }

        bool run_impl( thread_context * /*context*/ )
        {
            while ( true  ) {
                try {
                    while ( true ) {
                        const size_t count = ios_->run_one( );
                        if( !count ) return true; /// stopped;
                    }
                } catch( const interrupt & ) {
                    break;
                } catch( const boost::thread_interrupted & ) {
                    break;
                } catch( const std::exception &) {
                    ;;;
                }
            }
            return false; /// interruped by interrupt::raise or
                          ///               boost::thread_interrupted
        }

        bool attach( )
        {
            return run_impl( NULL );
        }

    };

    thread_pool::thread_pool( )
        :impl_(new impl(new basio::io_service, true))
    { }

    thread_pool::thread_pool( size_t init_count )
        :impl_(new impl(new basio::io_service, true))
    {
        impl_->add( init_count );
    }

    thread_pool::thread_pool( boost::asio::io_service &ios, size_t init_count )
        :impl_(new impl(&ios, false))
    {
        impl_->add( init_count );
    }

    thread_pool::thread_pool( boost::asio::io_service &ios )
        :impl_(new impl(&ios, false))
    { }

    thread_pool::~thread_pool( )
    {
        delete impl_;
    }

    size_t thread_pool::size( ) const
    {
        return impl_->size( );
    }

    void thread_pool::interrupt_one( )
    {
        impl_->interrupt_one( );
    }

    void thread_pool::stop( )
    {
        impl_->stop( );
    }

    void thread_pool::join_all( )
    {
        impl_->join_all( );
    }

    bool thread_pool::attach( )
    {
        return impl_->attach( );
    }

    void thread_pool::add_thread( )
    {
        impl_->inc( );
    }

    void thread_pool::add_threads( size_t count )
    {
        impl_->add(count);
    }

    boost::asio::io_service &thread_pool::get_io_service( )
    {
        return *impl_->ios_;
    }

    const boost::asio::io_service &thread_pool::get_io_service( ) const
    {
        return *impl_->ios_;
    }
}}
<|endoftext|>


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

#include "google/cloud/bigtable/row_range.h"

namespace google {
namespace cloud {
namespace bigtable {
inline namespace BIGTABLE_CLIENT_NS {
namespace btproto = ::google::bigtable::v2;

namespace {

/// Returns true iff a < b and there is no string c such that a < c < b.
inline bool Consecutive(std::string const& a, std::string const& b) {
  // The only way for two strings to be consecutive is for the
  // second to be equal to the first with an appended zero char.
  if (b.length() != a.length() + 1) {
    return false;
  }
  if (b.back() != '\0') {
    return false;
  }
  return b.compare(0, a.length(), a) == 0;
}

}  // anonymous namespace

bool RowRange::IsEmpty() const {
  std::string unused;
  // We do not want to copy the strings unnecessarily, so initialize a reference
  // pointing to *_key_closed() or *_key_open(), as needed.
  std::string const* start = &unused;
  bool start_open = false;
  switch (row_range_.start_key_case()) {
    case btproto::RowRange::kStartKeyClosed:
      start = &row_range_.start_key_closed();
      break;
    case btproto::RowRange::kStartKeyOpen:
      start = &row_range_.start_key_open();
      start_open = true;
      break;
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
  }
  // We need to initialize this to something to make g++ happy, but it cannot
  // be a value that is discarded in all switch() cases to make Clang happy.
  std::string const* end = &row_range_.end_key_closed();
  bool end_open = false;
  switch (row_range_.end_key_case()) {
    case btproto::RowRange::kEndKeyClosed:
      // Already initialized.
      break;
    case btproto::RowRange::kEndKeyOpen:
      end = &row_range_.end_key_open();
      end_open = true;
      break;
    case btproto::RowRange::END_KEY_NOT_SET:
      // A range ending at +infinity is never empty.
      return false;
  }

  // Special case of an open interval of two consecutive strings.
  if (start_open and end_open and Consecutive(*start, *end)) {
    return true;
  }

  // Compare the strings as byte vectors (careful with unsigned chars).
  int cmp = start->compare(*end);
  if (cmp == 0) {
    return start_open or end_open;
  }
  return cmp > 0;
}

bool RowRange::Contains(std::string const& key) const {
  return not BelowStart(key) and not AboveEnd(key);
}

bool RowRange::BelowStart(std::string const& key) const {
  switch (row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
    case btproto::RowRange::kStartKeyClosed:
      return key < row_range_.start_key_closed();
    case btproto::RowRange::kStartKeyOpen:
      return key <= row_range_.start_key_open();
  }
  return false;
}

bool RowRange::AboveEnd(std::string const& key) const {
  switch (row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      break;
    case btproto::RowRange::kEndKeyClosed:
      return key > row_range_.end_key_closed();
    case btproto::RowRange::kEndKeyOpen:
      return key >= row_range_.end_key_open();
  }
  return false;
}

std::pair<bool, RowRange> RowRange::Intersect(RowRange const& range) const {
  if (range.IsEmpty()) {
    return std::make_pair(false, RowRange::Empty());
  }
  std::string empty;

  // The algorithm is simple: start with *this as a the resulting range.  Update
  // both endpoints based on the value of @p range.  If the resulting range is
  // empty there is no intersection.
  RowRange intersection(*this);

  switch (range.row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
    case btproto::RowRange::kStartKeyClosed: {
      auto const& start = range.row_range_.start_key_closed();
      // If `range` starts above the current range then there is no
      // intersection.
      if (intersection.AboveEnd(start)) {
        return std::make_pair(false, Empty());
      }
      // If `start` is inside the intersection (as computed so far), then the
      // intersection must start at `start`, and it would be closed if `range`
      // is closed at the start.
      if (intersection.Contains(start)) {
        intersection.row_range_.set_start_key_closed(start);
      }
    } break;
    case btproto::RowRange::kStartKeyOpen: {
      // The case where `range` is open on the start point is analogous.
      auto const& start = range.row_range_.start_key_open();
      if (intersection.AboveEnd(start)) {
        return std::make_pair(false, Empty());
      }
      if (intersection.Contains(start)) {
        intersection.row_range_.set_start_key_open(start);
      }
    } break;
  }

  // Then check if the end limit of @p range is below *this.
  switch (range.row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      break;
    case btproto::RowRange::kEndKeyClosed: {
      // If `range` ends before the start of the intersection there is no
      // intersection and we can return immediately.
      auto const& end = range.row_range_.end_key_closed();
      if (intersection.BelowStart(end)) {
        return std::make_pair(false, Empty());
      }
      // If `end` is inside the intersection as computed so far, then the
      // intersection must end at `end` and it is closed if `range` is closed
      // at the end.
      if (intersection.Contains(end)) {
        intersection.row_range_.set_end_key_closed(end);
      }
    } break;
    case btproto::RowRange::kEndKeyOpen: {
      // Do the analogous thing for `end` being a open endpoint.
      auto const& end = range.row_range_.end_key_open();
      if (intersection.BelowStart(end)) {
        return std::make_pair(false, Empty());
      }
      if (intersection.Contains(end)) {
        intersection.row_range_.set_end_key_open(end);
      }
    } break;
  }

  bool is_empty = intersection.IsEmpty();
  return std::make_pair(not is_empty, std::move(intersection));
}

bool RowRange::operator==(RowRange const& rhs) const {
  if (row_range_.start_key_case() != rhs.row_range_.start_key_case()) {
    return false;
  }
  switch (row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
    case btproto::RowRange::kStartKeyClosed:
      if (row_range_.start_key_closed() != rhs.row_range_.start_key_closed()) {
        return false;
      }
    case btproto::RowRange::kStartKeyOpen:
      if (row_range_.start_key_open() != rhs.row_range_.start_key_open()) {
        return false;
      }
  }

  if (row_range_.end_key_case() != rhs.row_range_.end_key_case()) {
    return false;
  }
  switch (row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      break;
    case btproto::RowRange::kEndKeyClosed:
      if (row_range_.end_key_closed() != rhs.row_range_.end_key_closed()) {
        return false;
      }
    case btproto::RowRange::kEndKeyOpen:
      if (row_range_.end_key_open() != rhs.row_range_.end_key_open()) {
        return false;
      }
  }

  return true;
}

std::ostream& operator<<(std::ostream& os, RowRange const& x) {
  switch (x.row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      os << "['', ";
      break;
    case btproto::RowRange::kStartKeyClosed:
      os << "['" << x.row_range_.start_key_closed() << "', ";
      break;
    case btproto::RowRange::kStartKeyOpen:
      os << "('" << x.row_range_.start_key_open() << "', ";
  }

  switch (x.row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      os << "'')";
      break;
    case btproto::RowRange::kEndKeyClosed:
      os << "'" << x.row_range_.end_key_closed() << "']";
      break;
    case btproto::RowRange::kEndKeyOpen:
      os << "'" << x.row_range_.end_key_open() << "')";
      break;
  }
  return os;
}

}  // namespace BIGTABLE_CLIENT_NS
}  // namespace bigtable
}  // namespace cloud
}  // namespace google
<commit_msg>Add breaks in switch statement. (#1822)<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/bigtable/row_range.h"

namespace google {
namespace cloud {
namespace bigtable {
inline namespace BIGTABLE_CLIENT_NS {
namespace btproto = ::google::bigtable::v2;

namespace {

/// Returns true iff a < b and there is no string c such that a < c < b.
inline bool Consecutive(std::string const& a, std::string const& b) {
  // The only way for two strings to be consecutive is for the
  // second to be equal to the first with an appended zero char.
  if (b.length() != a.length() + 1) {
    return false;
  }
  if (b.back() != '\0') {
    return false;
  }
  return b.compare(0, a.length(), a) == 0;
}

}  // anonymous namespace

bool RowRange::IsEmpty() const {
  std::string unused;
  // We do not want to copy the strings unnecessarily, so initialize a reference
  // pointing to *_key_closed() or *_key_open(), as needed.
  std::string const* start = &unused;
  bool start_open = false;
  switch (row_range_.start_key_case()) {
    case btproto::RowRange::kStartKeyClosed:
      start = &row_range_.start_key_closed();
      break;
    case btproto::RowRange::kStartKeyOpen:
      start = &row_range_.start_key_open();
      start_open = true;
      break;
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
  }
  // We need to initialize this to something to make g++ happy, but it cannot
  // be a value that is discarded in all switch() cases to make Clang happy.
  std::string const* end = &row_range_.end_key_closed();
  bool end_open = false;
  switch (row_range_.end_key_case()) {
    case btproto::RowRange::kEndKeyClosed:
      // Already initialized.
      break;
    case btproto::RowRange::kEndKeyOpen:
      end = &row_range_.end_key_open();
      end_open = true;
      break;
    case btproto::RowRange::END_KEY_NOT_SET:
      // A range ending at +infinity is never empty.
      return false;
  }

  // Special case of an open interval of two consecutive strings.
  if (start_open and end_open and Consecutive(*start, *end)) {
    return true;
  }

  // Compare the strings as byte vectors (careful with unsigned chars).
  int cmp = start->compare(*end);
  if (cmp == 0) {
    return start_open or end_open;
  }
  return cmp > 0;
}

bool RowRange::Contains(std::string const& key) const {
  return not BelowStart(key) and not AboveEnd(key);
}

bool RowRange::BelowStart(std::string const& key) const {
  switch (row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
    case btproto::RowRange::kStartKeyClosed:
      return key < row_range_.start_key_closed();
    case btproto::RowRange::kStartKeyOpen:
      return key <= row_range_.start_key_open();
  }
  return false;
}

bool RowRange::AboveEnd(std::string const& key) const {
  switch (row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      break;
    case btproto::RowRange::kEndKeyClosed:
      return key > row_range_.end_key_closed();
    case btproto::RowRange::kEndKeyOpen:
      return key >= row_range_.end_key_open();
  }
  return false;
}

std::pair<bool, RowRange> RowRange::Intersect(RowRange const& range) const {
  if (range.IsEmpty()) {
    return std::make_pair(false, RowRange::Empty());
  }
  std::string empty;

  // The algorithm is simple: start with *this as a the resulting range.  Update
  // both endpoints based on the value of @p range.  If the resulting range is
  // empty there is no intersection.
  RowRange intersection(*this);

  switch (range.row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
    case btproto::RowRange::kStartKeyClosed: {
      auto const& start = range.row_range_.start_key_closed();
      // If `range` starts above the current range then there is no
      // intersection.
      if (intersection.AboveEnd(start)) {
        return std::make_pair(false, Empty());
      }
      // If `start` is inside the intersection (as computed so far), then the
      // intersection must start at `start`, and it would be closed if `range`
      // is closed at the start.
      if (intersection.Contains(start)) {
        intersection.row_range_.set_start_key_closed(start);
      }
    } break;
    case btproto::RowRange::kStartKeyOpen: {
      // The case where `range` is open on the start point is analogous.
      auto const& start = range.row_range_.start_key_open();
      if (intersection.AboveEnd(start)) {
        return std::make_pair(false, Empty());
      }
      if (intersection.Contains(start)) {
        intersection.row_range_.set_start_key_open(start);
      }
    } break;
  }

  // Then check if the end limit of @p range is below *this.
  switch (range.row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      break;
    case btproto::RowRange::kEndKeyClosed: {
      // If `range` ends before the start of the intersection there is no
      // intersection and we can return immediately.
      auto const& end = range.row_range_.end_key_closed();
      if (intersection.BelowStart(end)) {
        return std::make_pair(false, Empty());
      }
      // If `end` is inside the intersection as computed so far, then the
      // intersection must end at `end` and it is closed if `range` is closed
      // at the end.
      if (intersection.Contains(end)) {
        intersection.row_range_.set_end_key_closed(end);
      }
    } break;
    case btproto::RowRange::kEndKeyOpen: {
      // Do the analogous thing for `end` being a open endpoint.
      auto const& end = range.row_range_.end_key_open();
      if (intersection.BelowStart(end)) {
        return std::make_pair(false, Empty());
      }
      if (intersection.Contains(end)) {
        intersection.row_range_.set_end_key_open(end);
      }
    } break;
  }

  bool is_empty = intersection.IsEmpty();
  return std::make_pair(not is_empty, std::move(intersection));
}

bool RowRange::operator==(RowRange const& rhs) const {
  if (row_range_.start_key_case() != rhs.row_range_.start_key_case()) {
    return false;
  }
  switch (row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      break;
    case btproto::RowRange::kStartKeyClosed:
      if (row_range_.start_key_closed() != rhs.row_range_.start_key_closed()) {
        return false;
      }
      break;
    case btproto::RowRange::kStartKeyOpen:
      if (row_range_.start_key_open() != rhs.row_range_.start_key_open()) {
        return false;
      }
      break;
  }

  if (row_range_.end_key_case() != rhs.row_range_.end_key_case()) {
    return false;
  }
  switch (row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      break;
    case btproto::RowRange::kEndKeyClosed:
      if (row_range_.end_key_closed() != rhs.row_range_.end_key_closed()) {
        return false;
      }
      break;
    case btproto::RowRange::kEndKeyOpen:
      if (row_range_.end_key_open() != rhs.row_range_.end_key_open()) {
        return false;
      }
      break;
  }

  return true;
}

std::ostream& operator<<(std::ostream& os, RowRange const& x) {
  switch (x.row_range_.start_key_case()) {
    case btproto::RowRange::START_KEY_NOT_SET:
      os << "['', ";
      break;
    case btproto::RowRange::kStartKeyClosed:
      os << "['" << x.row_range_.start_key_closed() << "', ";
      break;
    case btproto::RowRange::kStartKeyOpen:
      os << "('" << x.row_range_.start_key_open() << "', ";
  }

  switch (x.row_range_.end_key_case()) {
    case btproto::RowRange::END_KEY_NOT_SET:
      os << "'')";
      break;
    case btproto::RowRange::kEndKeyClosed:
      os << "'" << x.row_range_.end_key_closed() << "']";
      break;
    case btproto::RowRange::kEndKeyOpen:
      os << "'" << x.row_range_.end_key_open() << "')";
      break;
  }
  return os;
}

}  // namespace BIGTABLE_CLIENT_NS
}  // namespace bigtable
}  // namespace cloud
}  // namespace google
<|endoftext|>


<commit_before>#pragma once

#include "geometry/point2d.hpp"

#include "base/base.hpp"

#include "geometry/latlon.hpp"

#include "routing/turns.hpp"
#include "routing/turns_sound_settings.hpp"

#include "std/cmath.hpp"
#include "std/function.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"

namespace location
{
  /// @note Do not change values of this constants.
  enum TLocationError
  {
    ENoError = 0,
    ENotSupported,
    EDenied,
    EGPSIsOff
  };

  enum TLocationSource
  {
    EAppleNative,
    EWindowsNative,
    EAndroidNative,
    EGoogle,
    ETizen,
    EPredictor
  };

  /// Our structure ALWAYS has valid lat, lon and horizontal accuracy.
  /// We filter out location events without lat/lon/acc in native code as we don't need them.
  class GpsInfo
  {
  public:
    GpsInfo()
      : m_horizontalAccuracy(100.0),  // use as a default accuracy
        m_altitude(0.0), m_verticalAccuracy(-1.0), m_bearing(-1.0), m_speed(-1.0)
    {
    }

    TLocationSource m_source;
    double m_timestamp;           //!< seconds from 1st Jan 1970
    double m_latitude;            //!< degrees
    double m_longitude;           //!< degrees
    double m_horizontalAccuracy;  //!< metres
    double m_altitude;            //!< metres
    double m_verticalAccuracy;    //!< metres
    double m_bearing;             //!< positive degrees from the true North
    double m_speed;               //!< metres per second

    //bool HasAltitude() const { return m_verticalAccuracy >= 0.0; }
    bool HasBearing() const  { return m_bearing >= 0.0; }
    bool HasSpeed() const    { return m_speed >= 0.0; }
  };

  /// GpsTrackInfo struct describes a point for GPS tracking
  /// It is similar to the GpsInfo but contains only needed fields.
  struct GpsTrackInfo
  {
    double m_timestamp; //!< seconds from 1st Jan 1970
    double m_latitude;  //!< degrees
    double m_longitude; //!< degrees
    double m_speed;     //!< meters per second
  };

  class CompassInfo
  {
  public:
    //double m_timestamp;           //!< seconds from 1st Jan 1970
    //double m_magneticHeading;     //!< positive radians from the magnetic North
    //double m_trueHeading;         //!< positive radians from the true North
    //double m_accuracy;            //!< offset from the magnetic to the true North in radians
    double m_bearing;             //!< positive radians from the true North
  };

  static inline bool IsLatValid(double lat)
  {
    return lat != 0. && lat < 90. && lat > -90.;
  }
  static inline bool IsLonValid(double lon)
  {
    return lon != 0. && lon < 180. && lon > -180.;
  }

  // Convert angle (in degrees counterclockwise from X) to bearing ([0, 360) clockwise from the north)
  static inline double AngleToBearing(double a)
  {
    double reverseAng = fmod(-a + 90, 360.);
    if (reverseAng < 0)
      reverseAng += 360.;
    return reverseAng;
  }

  // Convert bearing (in degrees clockwise from the north) to angle ([0, 360) counterclockwise from X)
  static inline double BearingToAngle(double a)
  {
    return AngleToBearing(a);
  }

  class FollowingInfo
  {
  public:
    FollowingInfo()
        : m_turn(routing::turns::TurnDirection::NoTurn),
          m_nextTurn(routing::turns::TurnDirection::NoTurn),
          m_exitNum(0),
          m_time(0),
          m_completionPercent(0),
          m_speedWarningSignal(false),
          m_pedestrianTurn(routing::turns::PedestrianDirection::None),
          m_pedestrianDirectionPos(0., 0.)
    {
    }

    // SingleLaneInfoClient is used for passing information about a lane to client platforms such as
    // Android, iOS and so on.
    struct SingleLaneInfoClient
    {
      vector<int8_t> m_lane;  // Possible directions for the lane.
      bool m_isRecommended;   // m_isRecommended is true if the lane is recommended for a user.

      SingleLaneInfoClient(routing::turns::SingleLaneInfo const & singleLaneInfo)
          : m_isRecommended(singleLaneInfo.m_isRecommended)
      {
        routing::turns::TSingleLane const & lane = singleLaneInfo.m_lane;
        m_lane.resize(lane.size());
        transform(lane.cbegin(), lane.cend(), m_lane.begin(), [](routing::turns::LaneWay l)
        {
          return static_cast<int8_t>(l);
        });
      }
    };

    /// @name Formatted covered distance with measurement units suffix.
    //@{
    string m_distToTarget;
    string m_targetUnitsSuffix;
    //@}

    /// @name Formated distance to next turn with measurement unit suffix
    //@{
    string m_distToTurn;
    string m_turnUnitsSuffix;
    routing::turns::TurnDirection m_turn;
    /// Turn after m_turn. Returns NoTurn if there is no turns after.
    routing::turns::TurnDirection m_nextTurn;
    uint32_t m_exitNum;
    //@}
    int m_time;
    // m_lanes contains lane information on the edge before the turn.
    vector<SingleLaneInfoClient> m_lanes;
    // m_turnNotifications contains information about the next turn notifications.
    // If there is nothing to pronounce m_turnNotifications is empty.
    // If there is something to pronounce the size of m_turnNotifications may be one or even more
    // depends on the number of notifications to prononce.
    vector<string> m_turnNotifications;
    // Current street name.
    string m_sourceName;
    // The next street name.
    string m_targetName;

    // Percentage of the route completion.
    double m_completionPercent;

    // Speed cam warning signal.
    bool m_speedWarningSignal;

    /// @name Pedestrian direction information
    //@{
    routing::turns::PedestrianDirection m_pedestrianTurn;
    ms::LatLon m_pedestrianDirectionPos;
    //@}

    bool IsValid() const { return !m_distToTarget.empty(); }
  };

  class RouteMatchingInfo
  {
    m2::PointD m_matchedPosition;
    size_t m_indexInRoute;
    bool m_isPositionMatched;
    bool m_hasDistanceFromBegin;
    double m_distanceFromBegin;

  public:
    RouteMatchingInfo()
      : m_matchedPosition(0., 0.)
      , m_indexInRoute(0)
      , m_isPositionMatched(false)
      , m_hasDistanceFromBegin(false)
      , m_distanceFromBegin(0.0)
    {}

    void Set(m2::PointD const & matchedPosition, size_t indexInRoute, double distanceFromBegin)
    {
      m_matchedPosition = matchedPosition;
      m_indexInRoute = indexInRoute;
      m_isPositionMatched = true;

      m_distanceFromBegin = distanceFromBegin;
      m_hasDistanceFromBegin = true;
    }

    void Reset() { m_isPositionMatched = false; }
    bool IsMatched() const { return m_isPositionMatched; }
    size_t GetIndexInRoute() const { return m_indexInRoute; }
    m2::PointD GetPosition() const { return m_matchedPosition; }
    bool HasDistanceFromBegin() const { return m_hasDistanceFromBegin; }
    double GetDistanceFromBegin() const { return m_distanceFromBegin; }
  };

  // Do not change the order and values
  enum EMyPositionMode
  {
    MODE_UNKNOWN_POSITION = 0x0,
    MODE_PENDING_POSITION = 0x1,
    MODE_NOT_FOLLOW = 0x2,
    MODE_FOLLOW = 0x3,
    MODE_ROTATE_AND_FOLLOW = 0x4,
  };

  using TMyPositionModeChanged = function<void (location::EMyPositionMode)>;

} // namespace location
<commit_msg>Init GpsTrackInfo from GpsInfo<commit_after>#pragma once

#include "geometry/point2d.hpp"

#include "base/base.hpp"

#include "geometry/latlon.hpp"

#include "routing/turns.hpp"
#include "routing/turns_sound_settings.hpp"

#include "std/cmath.hpp"
#include "std/function.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"

namespace location
{
  /// @note Do not change values of this constants.
  enum TLocationError
  {
    ENoError = 0,
    ENotSupported,
    EDenied,
    EGPSIsOff
  };

  enum TLocationSource
  {
    EAppleNative,
    EWindowsNative,
    EAndroidNative,
    EGoogle,
    ETizen,
    EPredictor
  };

  /// Our structure ALWAYS has valid lat, lon and horizontal accuracy.
  /// We filter out location events without lat/lon/acc in native code as we don't need them.
  class GpsInfo
  {
  public:
    GpsInfo()
      : m_horizontalAccuracy(100.0),  // use as a default accuracy
        m_altitude(0.0), m_verticalAccuracy(-1.0), m_bearing(-1.0), m_speed(-1.0)
    {
    }

    TLocationSource m_source;
    double m_timestamp;           //!< seconds from 1st Jan 1970
    double m_latitude;            //!< degrees
    double m_longitude;           //!< degrees
    double m_horizontalAccuracy;  //!< metres
    double m_altitude;            //!< metres
    double m_verticalAccuracy;    //!< metres
    double m_bearing;             //!< positive degrees from the true North
    double m_speed;               //!< metres per second

    //bool HasAltitude() const { return m_verticalAccuracy >= 0.0; }
    bool HasBearing() const  { return m_bearing >= 0.0; }
    bool HasSpeed() const    { return m_speed >= 0.0; }
  };

  /// GpsTrackInfo struct describes a point for GPS tracking
  /// It is similar to the GpsInfo but contains only needed fields.
  struct GpsTrackInfo
  {
    double m_timestamp; //!< seconds from 1st Jan 1970
    double m_latitude;  //!< degrees
    double m_longitude; //!< degrees
    double m_speed;     //!< meters per second

    GpsTrackInfo() = default;
    GpsTrackInfo(GpsTrackInfo const &) = default;
    GpsTrackInfo & operator=(GpsTrackInfo const &) = default;
    GpsTrackInfo(GpsInfo const & info)
      : m_timestamp(info.m_timestamp)
      , m_latitude(info.m_latitude)
      , m_longitude(info.m_longitude)
      , m_speed(info.m_speed)
    {}
    GpsTrackInfo & operator=(GpsInfo const & info)
    {
      return operator=(GpsTrackInfo(info));
    }
  };

  class CompassInfo
  {
  public:
    //double m_timestamp;           //!< seconds from 1st Jan 1970
    //double m_magneticHeading;     //!< positive radians from the magnetic North
    //double m_trueHeading;         //!< positive radians from the true North
    //double m_accuracy;            //!< offset from the magnetic to the true North in radians
    double m_bearing;             //!< positive radians from the true North
  };

  static inline bool IsLatValid(double lat)
  {
    return lat != 0. && lat < 90. && lat > -90.;
  }
  static inline bool IsLonValid(double lon)
  {
    return lon != 0. && lon < 180. && lon > -180.;
  }

  // Convert angle (in degrees counterclockwise from X) to bearing ([0, 360) clockwise from the north)
  static inline double AngleToBearing(double a)
  {
    double reverseAng = fmod(-a + 90, 360.);
    if (reverseAng < 0)
      reverseAng += 360.;
    return reverseAng;
  }

  // Convert bearing (in degrees clockwise from the north) to angle ([0, 360) counterclockwise from X)
  static inline double BearingToAngle(double a)
  {
    return AngleToBearing(a);
  }

  class FollowingInfo
  {
  public:
    FollowingInfo()
        : m_turn(routing::turns::TurnDirection::NoTurn),
          m_nextTurn(routing::turns::TurnDirection::NoTurn),
          m_exitNum(0),
          m_time(0),
          m_completionPercent(0),
          m_speedWarningSignal(false),
          m_pedestrianTurn(routing::turns::PedestrianDirection::None),
          m_pedestrianDirectionPos(0., 0.)
    {
    }

    // SingleLaneInfoClient is used for passing information about a lane to client platforms such as
    // Android, iOS and so on.
    struct SingleLaneInfoClient
    {
      vector<int8_t> m_lane;  // Possible directions for the lane.
      bool m_isRecommended;   // m_isRecommended is true if the lane is recommended for a user.

      SingleLaneInfoClient(routing::turns::SingleLaneInfo const & singleLaneInfo)
          : m_isRecommended(singleLaneInfo.m_isRecommended)
      {
        routing::turns::TSingleLane const & lane = singleLaneInfo.m_lane;
        m_lane.resize(lane.size());
        transform(lane.cbegin(), lane.cend(), m_lane.begin(), [](routing::turns::LaneWay l)
        {
          return static_cast<int8_t>(l);
        });
      }
    };

    /// @name Formatted covered distance with measurement units suffix.
    //@{
    string m_distToTarget;
    string m_targetUnitsSuffix;
    //@}

    /// @name Formated distance to next turn with measurement unit suffix
    //@{
    string m_distToTurn;
    string m_turnUnitsSuffix;
    routing::turns::TurnDirection m_turn;
    /// Turn after m_turn. Returns NoTurn if there is no turns after.
    routing::turns::TurnDirection m_nextTurn;
    uint32_t m_exitNum;
    //@}
    int m_time;
    // m_lanes contains lane information on the edge before the turn.
    vector<SingleLaneInfoClient> m_lanes;
    // m_turnNotifications contains information about the next turn notifications.
    // If there is nothing to pronounce m_turnNotifications is empty.
    // If there is something to pronounce the size of m_turnNotifications may be one or even more
    // depends on the number of notifications to prononce.
    vector<string> m_turnNotifications;
    // Current street name.
    string m_sourceName;
    // The next street name.
    string m_targetName;

    // Percentage of the route completion.
    double m_completionPercent;

    // Speed cam warning signal.
    bool m_speedWarningSignal;

    /// @name Pedestrian direction information
    //@{
    routing::turns::PedestrianDirection m_pedestrianTurn;
    ms::LatLon m_pedestrianDirectionPos;
    //@}

    bool IsValid() const { return !m_distToTarget.empty(); }
  };

  class RouteMatchingInfo
  {
    m2::PointD m_matchedPosition;
    size_t m_indexInRoute;
    bool m_isPositionMatched;
    bool m_hasDistanceFromBegin;
    double m_distanceFromBegin;

  public:
    RouteMatchingInfo()
      : m_matchedPosition(0., 0.)
      , m_indexInRoute(0)
      , m_isPositionMatched(false)
      , m_hasDistanceFromBegin(false)
      , m_distanceFromBegin(0.0)
    {}

    void Set(m2::PointD const & matchedPosition, size_t indexInRoute, double distanceFromBegin)
    {
      m_matchedPosition = matchedPosition;
      m_indexInRoute = indexInRoute;
      m_isPositionMatched = true;

      m_distanceFromBegin = distanceFromBegin;
      m_hasDistanceFromBegin = true;
    }

    void Reset() { m_isPositionMatched = false; }
    bool IsMatched() const { return m_isPositionMatched; }
    size_t GetIndexInRoute() const { return m_indexInRoute; }
    m2::PointD GetPosition() const { return m_matchedPosition; }
    bool HasDistanceFromBegin() const { return m_hasDistanceFromBegin; }
    double GetDistanceFromBegin() const { return m_distanceFromBegin; }
  };

  // Do not change the order and values
  enum EMyPositionMode
  {
    MODE_UNKNOWN_POSITION = 0x0,
    MODE_PENDING_POSITION = 0x1,
    MODE_NOT_FOLLOW = 0x2,
    MODE_FOLLOW = 0x3,
    MODE_ROTATE_AND_FOLLOW = 0x4,
  };

  using TMyPositionModeChanged = function<void (location::EMyPositionMode)>;

} // namespace location
<|endoftext|>