<commit_before>/*
===============================================================================

  FILE    laszippertest.cpp

  CONTENTS

  This tool reads and writes point data in the LAS 1.X format compressed
  or uncompressed to test the laszipper and lasunzipper interfaces.

  PROGRAMMERS

  martin isenburg@cs.unc.edu

  COPYRIGHT

  copyright (C) 2010 martin isenburg@cs.unc.edu

  This software 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.

  CHANGE HISTORY

  13 December 2010 -- created to test the remodularized laszip compressor

===============================================================================
*/

#include "laszipper.hpp"
#include "lasunzipper.hpp"

#ifdef LZ_WIN32_VC6
#include <fstream.h>
#else
#include <istream>
#include <fstream>
using namespace std;
#endif

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

//---------------------------------------------------------------------------

static double taketime()
{
  return (double)(clock())/CLOCKS_PER_SEC;
}

//---------------------------------------------------------------------------
// abstractions for doing I/O, which support VC6 streams, modern streams, and FILE*

class OStream
{
public:
  OStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ofile(NULL),
    streamo(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ofb.open(filename, ios::out);
      ofb.setmode(filebuf::binary);
      streamo = new ostream(&ofb);
#else
      streamo = new ofstream();
      streamo->open(filename, std::ios::out | std::ios::binary );
#endif
    }
    else
    {
      ofile = fopen(filename, "wb");
    }
  };

  ~OStream()
  {
    if (m_use_iostream)
    {
      delete streamo;
#ifdef LZ_WIN32_VC6
      ofb.close();
#endif
    }
    else
    {
      if (ofile)
        fclose(ofile);
    }
  };

  bool m_use_iostream;
  const char* m_filename;
  FILE* ofile;
  filebuf ofb;
#ifdef LZ_WIN32_VC6
  ostream* streamo;
#else
  ofstream* streamo;
#endif
};

//---------------------------------------------------------------------------

struct IStream
{
public:
  IStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ifile(NULL),
    streami(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ifb.open(filename, ios::in);
      ifb.setmode(filebuf::binary);
      streami = new istream(&ifb);
#else
      streami = new ifstream();
      streami->open(filename, std::ios::in | std::ios::binary);
#endif
    }
    else
    {
      ifile = fopen(filename, "rb");
    }
  };

  ~IStream()
  {
    if (m_use_iostream)
    {
      delete streami;
#ifdef LZ_WIN32_VC6
      ifb.close();
#endif
    }
    else
    {
      if (ifile)
        fclose(ifile);
    }
  };

  const char* m_filename;
  bool m_use_iostream;
  FILE* ifile;
  filebuf ifb;
#ifdef LZ_WIN32_VC6
  istream* streami;
#else
  ifstream* streami;
#endif
};

//---------------------------------------------------------------------------

#define NUM_ITEMS 5

class PointData
{
public:
  PointData()
  {
    num_items = NUM_ITEMS;

    items[0].type = LASitem::POINT10;
    items[0].size = 20;
    items[0].version = 0;

    items[1].type = LASitem::GPSTIME11;
    items[1].size = 8;
    items[1].version = 0;

    items[2].type = LASitem::RGB12;
    items[2].size = 6;
    items[2].version = 0;

    items[3].type = LASitem::WAVEPACKET13;
    items[3].size = 29;
    items[3].version = 0;

    items[4].type = LASitem::BYTE;
    items[4].size = 7;
    items[4].version = 0;

    unsigned int i;

    // compute the point size
    point_size = 0;
    for (i = 0; i < num_items; i++) point_size += items[i].size;

    // create the point data
    unsigned int point_offset = 0;
    point = new unsigned char*[num_items];
    point_data = new unsigned char[point_size];
    for (i = 0; i < num_items; i++)
    {
      point[i] = &(point_data[point_offset]);
      point_offset += items[i].size;
    }

    return;
  }

  ~PointData()
  {
    delete[] point;
    delete[] point_data;
    return;
  }

  unsigned int num_items;
  LASitem items[NUM_ITEMS];
  unsigned int point_size;
  unsigned char* point_data;
  unsigned char** point;
};

//---------------------------------------------------------------------------

class Settings
{
public:
  Settings(unsigned int num_pts, bool random, bool use_stream) :
    num_points(num_pts),
    use_random(random),
    use_iostream(use_stream)
  {
    logfile = fopen("zippertest.log","w");
    return;
  }

  ~Settings()
  {
    fclose(logfile);
    return;
  }

  unsigned num_points;
  bool use_random;
  unsigned int seed;
  bool use_iostream;
  FILE* logfile;
};

static Settings* settings = NULL; // singleton

//---------------------------------------------------------------------------

static void log(const char* format, ...)
{
  va_list args;

  va_start(args, format);
  vfprintf(stderr, format, args);
  va_end(args);
  fflush(stderr);

  va_start(args, format);
  vfprintf(settings->logfile, format, args);
  va_end(args);
  fflush(settings->logfile);

  return;
}

//---------------------------------------------------------------------------

static LASzipper* make_zipper(OStream* ost, PointData& data, LASzip::Algorithm alg)
{
  LASzipper* zipper = new LASzipper();

  int stat = 0;
  if (ost->m_use_iostream)
    stat = zipper->open(*ost->streamo, data.num_items, data.items, alg);
  else
    stat = zipper->open(ost->ofile, data.num_items, data.items, alg);

  if (stat != 0)
  {
    log("ERROR: could not open laszipper with %s\n", ost->m_filename);
    exit(1);
  }

  return zipper;
}

//---------------------------------------------------------------------------

static LASunzipper* make_unzipper(IStream* ist, PointData& data, LASzip::Algorithm alg)
{
  LASunzipper* unzipper = new LASunzipper();

  int stat = 0;
  if (ist->m_use_iostream)
    stat = unzipper->open(*ist->streami, data.num_items, data.items, alg);
  else
    stat = unzipper->open(ist->ifile, data.num_items, data.items, alg);

  if (stat != 0)
  {
    log("ERROR: could not open lasunzipper with %s\n", ist->m_filename);
    exit(1);
  }

  return unzipper;
}

//---------------------------------------------------------------------------

static void write_points(LASzipper* zipper, PointData& data)
{
  if (zipper==NULL) // range coder test
    return;

  double start_time, end_time;
  unsigned char c;
  unsigned int i,j;
  unsigned int num_bytes;

  // the two branches of this IF are the same, except for the use of a random number;
  // we keep the random case separate, so that we can get fastest timing tests w/o random data
  if (settings->use_random)
  {
    srand(settings->seed);
    start_time = taketime();
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c = rand() % 256;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }
  else
  {
    start_time = taketime();
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c++;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }

  log("laszipper wrote %d bytes in %g seconds\n", num_bytes, end_time-start_time);

  return;
}

//---------------------------------------------------------------------------

static void read_points(LASunzipper* unzipper, PointData& data)
{
  if (unzipper==NULL) // range coder test
    return;

  unsigned char c;
  unsigned int i,j;
  unsigned int num_errors, num_bytes;
  double start_time, end_time;

  start_time = taketime();
  num_errors = 0;

  if (settings->use_random)
  {
    srand(settings->seed);
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c = rand() % 256;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }
  else
  {
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c++;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }

  if (num_errors)
  {
    log("ERROR: with lasunzipper %d\n", num_errors);
  }
  else
  {
    log("SUCCESS: lasunzipper read %d bytes in %g seconds\n", num_bytes, end_time-start_time);
  }

  return;
}

//---------------------------------------------------------------------------

static void run_test(const char* filename, PointData& data, LASzip::Algorithm alg)
{
  OStream* ost = new OStream(settings->use_iostream, filename);
  LASzipper* laszipper = make_zipper(ost, data, alg);
  write_points(laszipper, data);
  delete laszipper;
  delete ost;

  IStream* ist = new IStream(settings->use_iostream, filename);
  LASunzipper* lasunzipper = make_unzipper(ist, data, alg);
  read_points(lasunzipper, data);
  delete lasunzipper;
  delete ist;

  return;
}

//---------------------------------------------------------------------------

int main(int argc, char *argv[])
{
  unsigned int num_points = 100000;
  bool use_iostream = false;
  bool run_forever = false;
  bool use_random = false;

  for (int i=1; i<argc; i++)
  {
    const char* p = argv[i];
    if (strcmp(p,"-n")==0)
    {
      ++i;
      num_points = atoi(argv[i]);
    }
    else if (strcmp(p,"-s")==0)
    {
      use_iostream = true;
    }
    else if (strcmp(p,"-f")==0)
    {
      run_forever = true;
    }
    else if (strcmp(p,"-r")==0)
    {
      use_random = true;
    }
    else
    {
      fprintf(stderr, "Usage   ziptest [-n NUMBER] [-s] [-f] [-r]\n");
      fprintf(stderr, "   -n    number of points to process (default   100000)\n");
      fprintf(stderr, "   -s    use C++ stream I/O (default   use FILE* I/O)\n");
      fprintf(stderr, "   -f    run forever (default   run just one pass)\n");
      fprintf(stderr, "   -r    use random input data (default   use fixed data)\n");
      exit(1);
    }
  }

  settings = new Settings(num_points, use_random, use_iostream);

  log("Settings:\n");
  log("  num_points=%d, use_iostream=%s, run_forever=%s, use_random=%s\n",
    num_points, use_iostream?"true":"false", run_forever?"true":"false", use_random?"true":"false");

  unsigned int run = 1;
  do
  {
  PointData data;

  // use a seed based on the current time
  settings->seed = (unsigned int)time(NULL);
  if (settings->use_random)
  {
    log("Seed: %u\n", settings->seed);
  }

  run_test("test1.lax", data, LASzip::POINT_BY_POINT_RAW);
  run_test("test2.lax", data, LASzip::POINT_BY_POINT_ARITHMETIC);
  log("Finished %u runs\n\n", run);
  ++run;
  } while (run_forever);

  return 0;
}
<commit_msg>fixed messed up licensing comments<commit_after>/*
===============================================================================

  FILE    laszippertest.cpp

  CONTENTS

    This tool reads and writes point data in the LAS 1.X format compressed
    or uncompressed to test the laszipper and lasunzipper interfaces.

  PROGRAMMERS:

    martin.isenburg@gmail.com

  COPYRIGHT:

    (c) 2010-2011, Martin Isenburg, LASSO - tools to catch reality

    This is free software; you can redistribute and/or modify it under the
    terms of the GNU Lesser General Licence as published by the Free Software
    Foundation. See the COPYING file for more information.

    This software is distributed WITHOUT ANY WARRANTY and without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    14 January 2011 -- mpg@flaxen.com adds randomness and commandline controls
    10 January 2011 -- licensing change for LGPL release and liblas integration
    13 December 2010 -- created to test the remodularized laszip compressor

===============================================================================
*/

#include "laszipper.hpp"
#include "lasunzipper.hpp"

#ifdef LZ_WIN32_VC6
#include <fstream.h>
#else
#include <istream>
#include <fstream>
using namespace std;
#endif

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

//---------------------------------------------------------------------------

static double taketime()
{
  return (double)(clock())/CLOCKS_PER_SEC;
}

//---------------------------------------------------------------------------
// abstractions for doing I/O, which support VC6 streams, modern streams, and FILE*

class OStream
{
public:
  OStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ofile(NULL),
    streamo(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ofb.open(filename, ios::out);
      ofb.setmode(filebuf::binary);
      streamo = new ostream(&ofb);
#else
      streamo = new ofstream();
      streamo->open(filename, std::ios::out | std::ios::binary );
#endif
    }
    else
    {
      ofile = fopen(filename, "wb");
    }
  };

  ~OStream()
  {
    if (m_use_iostream)
    {
      delete streamo;
#ifdef LZ_WIN32_VC6
      ofb.close();
#endif
    }
    else
    {
      if (ofile)
        fclose(ofile);
    }
  };

  bool m_use_iostream;
  const char* m_filename;
  FILE* ofile;
  filebuf ofb;
#ifdef LZ_WIN32_VC6
  ostream* streamo;
#else
  ofstream* streamo;
#endif
};

//---------------------------------------------------------------------------

struct IStream
{
public:
  IStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ifile(NULL),
    streami(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ifb.open(filename, ios::in);
      ifb.setmode(filebuf::binary);
      streami = new istream(&ifb);
#else
      streami = new ifstream();
      streami->open(filename, std::ios::in | std::ios::binary);
#endif
    }
    else
    {
      ifile = fopen(filename, "rb");
    }
  };

  ~IStream()
  {
    if (m_use_iostream)
    {
      delete streami;
#ifdef LZ_WIN32_VC6
      ifb.close();
#endif
    }
    else
    {
      if (ifile)
        fclose(ifile);
    }
  };

  const char* m_filename;
  bool m_use_iostream;
  FILE* ifile;
  filebuf ifb;
#ifdef LZ_WIN32_VC6
  istream* streami;
#else
  ifstream* streami;
#endif
};

//---------------------------------------------------------------------------

#define NUM_ITEMS 5

class PointData
{
public:
  PointData()
  {
    num_items = NUM_ITEMS;

    items[0].type = LASitem::POINT10;
    items[0].size = 20;
    items[0].version = 0;

    items[1].type = LASitem::GPSTIME11;
    items[1].size = 8;
    items[1].version = 0;

    items[2].type = LASitem::RGB12;
    items[2].size = 6;
    items[2].version = 0;

    items[3].type = LASitem::WAVEPACKET13;
    items[3].size = 29;
    items[3].version = 0;

    items[4].type = LASitem::BYTE;
    items[4].size = 7;
    items[4].version = 0;

    unsigned int i;

    // compute the point size
    point_size = 0;
    for (i = 0; i < num_items; i++) point_size += items[i].size;

    // create the point data
    unsigned int point_offset = 0;
    point = new unsigned char*[num_items];
    point_data = new unsigned char[point_size];
    for (i = 0; i < num_items; i++)
    {
      point[i] = &(point_data[point_offset]);
      point_offset += items[i].size;
    }

    return;
  }

  ~PointData()
  {
    delete[] point;
    delete[] point_data;
    return;
  }

  unsigned int num_items;
  LASitem items[NUM_ITEMS];
  unsigned int point_size;
  unsigned char* point_data;
  unsigned char** point;
};

//---------------------------------------------------------------------------

class Settings
{
public:
  Settings(unsigned int num_pts, bool random, bool use_stream) :
    num_points(num_pts),
    use_random(random),
    use_iostream(use_stream)
  {
    logfile = fopen("zippertest.log","w");
    return;
  }

  ~Settings()
  {
    fclose(logfile);
    return;
  }

  unsigned num_points;
  bool use_random;
  unsigned int seed;
  bool use_iostream;
  FILE* logfile;
};

static Settings* settings = NULL; // singleton

//---------------------------------------------------------------------------

static void log(const char* format, ...)
{
  va_list args;

  va_start(args, format);
  vfprintf(stderr, format, args);
  va_end(args);
  fflush(stderr);

  va_start(args, format);
  vfprintf(settings->logfile, format, args);
  va_end(args);
  fflush(settings->logfile);

  return;
}

//---------------------------------------------------------------------------

static LASzipper* make_zipper(OStream* ost, PointData& data, LASzip::Algorithm alg)
{
  LASzipper* zipper = new LASzipper();

  int stat = 0;
  if (ost->m_use_iostream)
    stat = zipper->open(*ost->streamo, data.num_items, data.items, alg);
  else
    stat = zipper->open(ost->ofile, data.num_items, data.items, alg);

  if (stat != 0)
  {
    log("ERROR: could not open laszipper with %s\n", ost->m_filename);
    exit(1);
  }

  return zipper;
}

//---------------------------------------------------------------------------

static LASunzipper* make_unzipper(IStream* ist, PointData& data, LASzip::Algorithm alg)
{
  LASunzipper* unzipper = new LASunzipper();

  int stat = 0;
  if (ist->m_use_iostream)
    stat = unzipper->open(*ist->streami, data.num_items, data.items, alg);
  else
    stat = unzipper->open(ist->ifile, data.num_items, data.items, alg);

  if (stat != 0)
  {
    log("ERROR: could not open lasunzipper with %s\n", ist->m_filename);
    exit(1);
  }

  return unzipper;
}

//---------------------------------------------------------------------------

static void write_points(LASzipper* zipper, PointData& data)
{
  if (zipper==NULL) // range coder test
    return;

  double start_time, end_time;
  unsigned char c;
  unsigned int i,j;
  unsigned int num_bytes;

  // the two branches of this IF are the same, except for the use of a random number;
  // we keep the random case separate, so that we can get fastest timing tests w/o random data
  if (settings->use_random)
  {
    srand(settings->seed);
    start_time = taketime();
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c = rand() % 256;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }
  else
  {
    start_time = taketime();
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c++;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }

  log("laszipper wrote %d bytes in %g seconds\n", num_bytes, end_time-start_time);

  return;
}

//---------------------------------------------------------------------------

static void read_points(LASunzipper* unzipper, PointData& data)
{
  if (unzipper==NULL) // range coder test
    return;

  unsigned char c;
  unsigned int i,j;
  unsigned int num_errors, num_bytes;
  double start_time, end_time;

  start_time = taketime();
  num_errors = 0;

  if (settings->use_random)
  {
    srand(settings->seed);
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c = rand() % 256;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }
  else
  {
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c++;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }

  if (num_errors)
  {
    log("ERROR: with lasunzipper %d\n", num_errors);
  }
  else
  {
    log("SUCCESS: lasunzipper read %d bytes in %g seconds\n", num_bytes, end_time-start_time);
  }

  return;
}

//---------------------------------------------------------------------------

static void run_test(const char* filename, PointData& data, LASzip::Algorithm alg)
{
  OStream* ost = new OStream(settings->use_iostream, filename);
  LASzipper* laszipper = make_zipper(ost, data, alg);
  write_points(laszipper, data);
  delete laszipper;
  delete ost;

  IStream* ist = new IStream(settings->use_iostream, filename);
  LASunzipper* lasunzipper = make_unzipper(ist, data, alg);
  read_points(lasunzipper, data);
  delete lasunzipper;
  delete ist;

  return;
}

//---------------------------------------------------------------------------

int main(int argc, char *argv[])
{
  unsigned int num_points = 100000;
  bool use_iostream = false;
  bool run_forever = false;
  bool use_random = false;

  for (int i=1; i<argc; i++)
  {
    const char* p = argv[i];
    if (strcmp(p,"-n")==0)
    {
      ++i;
      num_points = atoi(argv[i]);
    }
    else if (strcmp(p,"-s")==0)
    {
      use_iostream = true;
    }
    else if (strcmp(p,"-f")==0)
    {
      run_forever = true;
    }
    else if (strcmp(p,"-r")==0)
    {
      use_random = true;
    }
    else
    {
      fprintf(stderr, "Usage   ziptest [-n NUMBER] [-s] [-f] [-r]\n");
      fprintf(stderr, "   -n    number of points to process (default   100000)\n");
      fprintf(stderr, "   -s    use C++ stream I/O (default   use FILE* I/O)\n");
      fprintf(stderr, "   -f    run forever (default   run just one pass)\n");
      fprintf(stderr, "   -r    use random input data (default   use fixed data)\n");
      exit(1);
    }
  }

  settings = new Settings(num_points, use_random, use_iostream);

  log("Settings:\n");
  log("  num_points=%d, use_iostream=%s, run_forever=%s, use_random=%s\n",
    num_points, use_iostream?"true":"false", run_forever?"true":"false", use_random?"true":"false");

  unsigned int run = 1;
  do
  {
  PointData data;

  // use a seed based on the current time
  settings->seed = (unsigned int)time(NULL);
  if (settings->use_random)
  {
    log("Seed: %u\n", settings->seed);
  }

  run_test("test1.lax", data, LASzip::POINT_BY_POINT_RAW);
  run_test("test2.lax", data, LASzip::POINT_BY_POINT_ARITHMETIC);
  log("Finished %u runs\n\n", run);
  ++run;
  } while (run_forever);

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>SubMesh::_intersectTriangles:  if (position.empty() => early return<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "CodeReport/AnnotateDisassembly.h"

#include <absl/strings/str_split.h>
#include <stdint.h>

namespace orbit_code_report {

static std::vector<std::string_view> SplitIntoLines(std::string_view source_file_contents) {
  std::vector<std::string_view> source_file_lines = absl::StrSplit(source_file_contents, '\n');
  for (auto& line : source_file_lines) {
    if (!line.empty() && line.back() == '\r') line = line.substr(0, line.size() - 1);
  }

  return source_file_lines;
}

[[nodiscard]] std::vector<AnnotatingLine> AnnotateDisassemblyWithSourceCode(
    const orbit_client_data::FunctionInfo& function_info,
    const orbit_grpc_protos::LineInfo& location_info, std::string_view source_file_contents,
    orbit_object_utils::ElfFile* elf, const DisassemblyReport& report) {
  const std::vector<std::string_view> source_file_lines = SplitIntoLines(source_file_contents);

  // We will show each source code line above the first related instruction
  absl::flat_hash_map<size_t, uint64_t> source_line_to_first_instruction_offset;

  for (uint64_t current_offset = 0; current_offset < function_info.size(); ++current_offset) {
    const auto line_info_or_error = elf->GetLineInfo(current_offset + function_info.address());
    if (line_info_or_error.has_error()) continue;
    if (line_info_or_error.value().source_file() != location_info.source_file()) continue;
    if (line_info_or_error.value().source_line() == 0) continue;

    const auto source_line = line_info_or_error.value().source_line() - 1;
    if (source_line >= static_cast<size_t>(source_file_lines.size())) continue;

    source_line_to_first_instruction_offset.emplace(source_line, current_offset);
  }

  std::vector<AnnotatingLine> annotating_lines{};
  annotating_lines.reserve(source_line_to_first_instruction_offset.size());

  for (const auto& [source_line, offset] : source_line_to_first_instruction_offset) {
    const auto disassembly_line_number =
        report.GetLineAtAddress(report.GetAbsoluteFunctionAddress() + offset);
    if (!disassembly_line_number.has_value()) continue;

    AnnotatingLine annotating_line{};
    annotating_line.reference_line = disassembly_line_number.value() + 1;
    annotating_line.line_number = source_line + 1;
    annotating_line.line_contents = std::string{source_file_lines[static_cast<int>(source_line)]};
    annotating_lines.emplace_back(std::move(annotating_line));
  }

  const auto by_disassembly_line_number = [](const AnnotatingLine& lhs, const AnnotatingLine& rhs) {
    return lhs.reference_line < rhs.reference_line;
  };

  std::sort(annotating_lines.begin(), annotating_lines.end(), by_disassembly_line_number);

  return annotating_lines;
}
}  // namespace orbit_code_report<commit_msg>Use orbit_base::sort to sort `AnnotatingLines` (#3926)<commit_after>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "CodeReport/AnnotateDisassembly.h"

#include <absl/strings/str_split.h>
#include <stdint.h>

#include "OrbitBase/Sort.h"

namespace orbit_code_report {

static std::vector<std::string_view> SplitIntoLines(std::string_view source_file_contents) {
  std::vector<std::string_view> source_file_lines = absl::StrSplit(source_file_contents, '\n');
  for (auto& line : source_file_lines) {
    if (!line.empty() && line.back() == '\r') line = line.substr(0, line.size() - 1);
  }

  return source_file_lines;
}

[[nodiscard]] std::vector<AnnotatingLine> AnnotateDisassemblyWithSourceCode(
    const orbit_client_data::FunctionInfo& function_info,
    const orbit_grpc_protos::LineInfo& location_info, std::string_view source_file_contents,
    orbit_object_utils::ElfFile* elf, const DisassemblyReport& report) {
  const std::vector<std::string_view> source_file_lines = SplitIntoLines(source_file_contents);

  // We will show each source code line above the first related instruction
  absl::flat_hash_map<size_t, uint64_t> source_line_to_first_instruction_offset;

  for (uint64_t current_offset = 0; current_offset < function_info.size(); ++current_offset) {
    const auto line_info_or_error = elf->GetLineInfo(current_offset + function_info.address());
    if (line_info_or_error.has_error()) continue;
    if (line_info_or_error.value().source_file() != location_info.source_file()) continue;
    if (line_info_or_error.value().source_line() == 0) continue;

    const auto source_line = line_info_or_error.value().source_line() - 1;
    if (source_line >= static_cast<size_t>(source_file_lines.size())) continue;

    source_line_to_first_instruction_offset.emplace(source_line, current_offset);
  }

  std::vector<AnnotatingLine> annotating_lines{};
  annotating_lines.reserve(source_line_to_first_instruction_offset.size());

  for (const auto& [source_line, offset] : source_line_to_first_instruction_offset) {
    const auto disassembly_line_number =
        report.GetLineAtAddress(report.GetAbsoluteFunctionAddress() + offset);
    if (!disassembly_line_number.has_value()) continue;

    AnnotatingLine annotating_line{};
    annotating_line.reference_line = disassembly_line_number.value() + 1;
    annotating_line.line_number = source_line + 1;
    annotating_line.line_contents = std::string{source_file_lines[static_cast<int>(source_line)]};
    annotating_lines.emplace_back(std::move(annotating_line));
  }

  orbit_base::sort(annotating_lines.begin(), annotating_lines.end(),
                   &AnnotatingLine::reference_line);

  return annotating_lines;
}
}  // namespace orbit_code_report<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//      $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2008, 2009 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <base/index_set.h>

DEAL_II_NAMESPACE_OPEN

void
IndexSet::compress () const
{
				   // first see if any of the
				   // individual entries can be merged
				   // to form contiguous ranges
  {
    std::set<unsigned int>::iterator p = individual_indices.begin();
    while (p != individual_indices.end())
      {
	unsigned int n = 0;
	std::set<unsigned int>::iterator q = p;
	++q;
	while ((q != individual_indices.end())
	       &&
	       (*q == *p+n+1))
	  {
	    ++q;
	    ++n;
	  }

	if (n>0)
	  {
	    const unsigned int range_end = *q;

					     // add the new range,
					     // delete the elements of
					     // the range from the set
					     // of individual indices
	    contiguous_ranges.insert (ContiguousRange(*p, *p+n+1));
	    individual_indices.erase (p, q);

					     // reset p to the element
					     // past the last
	    p = individual_indices.lower_bound (range_end);
	  }
	else
	  ++p;
      }
  }

				   // next see if we can roll any of
				   // the individual entries into the
				   // contiguous ranges
  {
    std::set<ContiguousRange, RangeComparison>::iterator
      next_range            = contiguous_ranges.begin();
    std::set<unsigned int>::iterator
      next_individual_index = individual_indices.begin();

    while ((next_range != contiguous_ranges.end())
	   &&
	   (next_individual_index != individual_indices.end()))
      {
					 // if the next individual
					 // index is beyond the upper
					 // bound of the next range,
					 // then we need to inspect
					 // the next range
	if (*next_individual_index > next_range->second)
	  {
	    ++next_range;
	    continue;
	  }

					 // if, on the other hand, the
					 // next individual index is
					 // below the lower bound of
					 // the next range, then we
					 // need to inspect the next
					 // index
	if (*next_individual_index < next_range->first-1)
	  {
	    ++next_individual_index;
	    continue;
	  }

					 // now we know that the
					 // individual index is within
					 // the next range, or
					 // possibly one element
					 // before, or one element
					 // after. so they can be
					 // merged. note that ranges
					 // are half open, so in the
					 // upper bound we have to
					 // consider the next index+1
	ContiguousRange new_range (std::min (*next_individual_index,
					     next_range->first),
				   std::max (*next_individual_index+1,
					     next_range->second));

					 // erase old index and range,
					 // and reset iterators
					 //
					 // note that the following
					 // index can't possibly be
					 // *next_index+1, since we
					 // have merged contiguous
					 // sets of individual indices
					 // above. however, there may
					 // be more individual indices
					 // that lie within the
					 // current range, so we'll
					 // delete all of them
	const unsigned int old_index = *next_individual_index;
	individual_indices.erase (next_individual_index);
	next_individual_index = individual_indices.lower_bound (old_index);

	contiguous_ranges.erase (next_range);
	contiguous_ranges.insert (new_range);

	next_range = contiguous_ranges.lower_bound (new_range);
      }
  }

				   // finally see if any of the
				   // contiguous ranges can be
				   // merged. since they are sorted by
				   // their first index, determining
				   // overlap isn't all that hard
  for (std::set<ContiguousRange, RangeComparison>::iterator
	 i = contiguous_ranges.begin();
       i != contiguous_ranges.end();
       ++i)
    {
      std::set<ContiguousRange, RangeComparison>::const_iterator
	next = i;
      ++next;

      if (next != contiguous_ranges.end())
	if (next->first <= i->second)
	  {
	    const unsigned int first_index = i->first;
	    const unsigned int last_index  = next->second;

					     // delete the two old
					     // ranges and insert the
					     // new range
	    contiguous_ranges.erase (i, ++next);
	    contiguous_ranges.insert (ContiguousRange(first_index,
						      last_index));

					     // then set iterator to
					     // the same position as
					     // before
	    i = contiguous_ranges.lower_bound (ContiguousRange(first_index,
							       last_index));
	  }
    }
}

DEAL_II_NAMESPACE_CLOSE
<commit_msg>Optimize construction of compressed index sets.<commit_after>//---------------------------------------------------------------------------
//      $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2008, 2009 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <base/index_set.h>

DEAL_II_NAMESPACE_OPEN

void
IndexSet::compress () const
{
				   // first see if any of the
				   // individual entries can be merged
				   // to form contiguous ranges
  {
    std::set<unsigned int>::iterator p = individual_indices.begin();
    while (p != individual_indices.end())
      {
	unsigned int n = 0;
	std::set<unsigned int>::iterator q = p;
	++q;
	while ((q != individual_indices.end())
	       &&
	       (*q == *p+n+1))
	  {
	    ++q;
	    ++n;
	  }

	if (n>0)
	  {
	    const unsigned int range_end = *q;

					     // add the new range,
					     // delete the elements of
					     // the range from the set
					     // of individual indices
	    contiguous_ranges.insert (ContiguousRange(*p, *p+n+1));
	    individual_indices.erase (p, q);

					     // reset p to the element
					     // past the last
	    p = individual_indices.lower_bound (range_end);
	  }
	else
	  ++p;
      }
  }

				   // next see if we can roll any of
				   // the individual entries into the
				   // contiguous ranges
  {
    std::set<ContiguousRange, RangeComparison>::iterator
      next_range            = contiguous_ranges.begin();
    std::set<unsigned int>::iterator
      next_individual_index = individual_indices.begin();

    while ((next_range != contiguous_ranges.end())
	   &&
	   (next_individual_index != individual_indices.end()))
      {
					 // if the next individual
					 // index is beyond the upper
					 // bound of the next range,
					 // then we need to inspect
					 // the next range
	if (*next_individual_index > next_range->second)
	  {
	    ++next_range;
	    continue;
	  }

					 // if, on the other hand, the
					 // next individual index is
					 // below the lower bound of
					 // the next range, then we
					 // need to inspect the next
					 // index
	if (*next_individual_index < next_range->first-1)
	  {
	    ++next_individual_index;
	    continue;
	  }

					 // now we know that the
					 // individual index is within
					 // the next range, or
					 // possibly one element
					 // before, or one element
					 // after. so they can be
					 // merged. note that ranges
					 // are half open, so in the
					 // upper bound we have to
					 // consider the next index+1
	ContiguousRange new_range (std::min (*next_individual_index,
					     next_range->first),
				   std::max (*next_individual_index+1,
					     next_range->second));

					 // erase old index and range,
					 // and reset iterators
					 //
					 // note that the following
					 // index can't possibly be
					 // *next_index+1, since we
					 // have merged contiguous
					 // sets of individual indices
					 // above. however, there may
					 // be more individual indices
					 // that lie within the
					 // current range, so we'll
					 // delete all of them
	const unsigned int old_index = *next_individual_index;

	{
	  std::set<unsigned int>::iterator
	    last_index = next_individual_index;
	  ++last_index;
	  while ((last_index != individual_indices.end())
		 &&
		 (*last_index < new_range.second))
	    ++last_index;

	  individual_indices.erase (next_individual_index,
				    last_index);
	}
	next_individual_index = individual_indices.lower_bound (old_index);

	contiguous_ranges.erase (next_range);
	contiguous_ranges.insert (new_range);

	next_range = contiguous_ranges.lower_bound (new_range);
      }
  }

				   // finally see if any of the
				   // contiguous ranges can be
				   // merged. since they are sorted by
				   // their first index, determining
				   // overlap isn't all that hard
  for (std::set<ContiguousRange, RangeComparison>::iterator
	 i = contiguous_ranges.begin();
       i != contiguous_ranges.end();
       ++i)
    {
      std::set<ContiguousRange, RangeComparison>::const_iterator
	next = i;
      ++next;

      if (next != contiguous_ranges.end())
	if (next->first <= i->second)
	  {
	    const unsigned int first_index = i->first;
	    const unsigned int last_index  = next->second;

					     // delete the two old
					     // ranges and insert the
					     // new range
	    contiguous_ranges.erase (i, ++next);
	    contiguous_ranges.insert (ContiguousRange(first_index,
						      last_index));

					     // then set iterator to
					     // the same position as
					     // before
	    i = contiguous_ranges.lower_bound (ContiguousRange(first_index,
							       last_index));
	  }
    }
}

DEAL_II_NAMESPACE_CLOSE
<|endoftext|>


<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "BMFont.h"
#include "Engine.h"
#include "FileSystem.h"
#include "Vertex.h"
#include "Cache.h"
#include "Utils.h"

namespace ouzel
{
    BMFont::BMFont()
    {

    }

    BMFont::~BMFont()
    {

    }

    bool BMFont::parseFont(const std::string& filename)
    {
        std::ifstream stream(sharedEngine->getFileSystem()->getPath(filename));
        std::string line;
        std::string read, key, value;
        std::size_t i;

        if (!stream)
        {
            log("Failed to open font file %s", filename.c_str());
            return false;
        }

        KerningInfo k;
        CharDescriptor c;

        while (!stream.eof())
        {
            std::getline(stream, line);

            std::stringstream lineStream;
            lineStream << line;

            lineStream >> read;

            if (read == "page")
            {
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "file")
                    {
                        // trim quotes
                        if (value.length() && value[0] == '"' && value[value.length() - 1] == '"')
                        {
                            value = value.substr(1, value.length() - 2);
                        }

                        texture = sharedEngine->getCache()->getTexture(value, false, true);
                    }
                }
            }
            else if (read == "common")
            {
                //this holds common data
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "lineHeight") converter >> lineHeight;
                    else if (key == "base") converter >> base;
                    else if (key == "scaleW") converter >> width;
                    else if (key == "scaleH") converter >> height;
                    else if (key == "pages") converter >> pages;
                    else if (key == "outline") converter >> outline;
                }
            }
            else if (read == "char")
            {
                //This is data for each specific character.
                int32_t charId = 0;

                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //Assign the correct value
                    converter << value;
                    if (key == "id") converter >> charId;
                    else if (key == "x") converter >> c.x;
                    else if (key == "y") converter >> c.y;
                    else if (key == "width") converter >> c.width;
                    else if (key == "height") converter >> c.height;
                    else if (key == "xoffset") converter >> c.xOffset;
                    else if (key == "yoffset") converter >> c.yOffset;
                    else if (key == "xadvance") converter >> c.xAdvance;
                    else if (key == "page") converter >> c.page;
                }

                chars.insert(std::map<int32_t, CharDescriptor>::value_type(charId, c));
            }
            else if (read == "kernings")
            {
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "count") converter >> kernCount;
                }
            }
            else if (read == "kerning")
            {
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "first") converter >> k.first;
                    else if (key == "second") converter >> k.second;
                    else if (key == "amount") converter >> k.amount;
                }
                kern[std::make_pair(k.first, k.second)] = k;
            }
        }

        stream.close();

        return true;
    }

    int32_t BMFont::getKerningPair(int32_t first, int32_t second)
    {
        std::map<std::pair<int32_t, int32_t>, KerningInfo>::iterator i = kern.find(std::make_pair(first, second));

        if (i != kern.end())
        {
            return i->second.amount;
        }

        return 0;
    }

    float BMFont::getStringWidth(const std::string& text)
    {
        float total = 0;
        CharDescriptor* f;

        for (uint32_t i = 0; i < static_cast<uint32_t>(text.length()); ++i)
        {
            std::map<int32_t, CharDescriptor>::iterator iter = chars.find(text[i]);

            if (iter == chars.end())
            {
                continue;
            }

            f = &iter->second;
            total += f->xAdvance;
        }

        return total;
    }

    bool BMFont::loadFont(const std::string& filename)
    {
        if (!parseFont(filename))
        {
            log("Failed to parse font %s",filename.c_str());
            return false;
        }

        if (!texture)
        {
            return false;
        }

        kernCount = static_cast<uint16_t>(kern.size());

        return true;
    }

    void BMFont::getVertices(const std::string& text, const graphics::Color& color, const Vector2& anchor, std::vector<uint16_t>& indices, std::vector<graphics::VertexPCT>& vertices)
    {
        uint32_t flen;

        CharDescriptor  *f;

        float x = 0.0f;
        float y = lineHeight * (1.0f - anchor.y);

        flen = static_cast<uint32_t>(text.length());

        indices.clear();
        vertices.clear();

        indices.reserve(flen * 6);
        vertices.reserve(flen * 4);

        Vector2 textCoords[4];

        for (uint32_t i = 0; i != flen; ++i)
        {
            std::map<int32_t, CharDescriptor>::iterator iter = chars.find(text[i]);

            if (iter == chars.end())
            {
                continue;
            }
            else
            {
                f = &iter->second;
            }

            uint16_t startIndex = static_cast<uint16_t>(vertices.size());
            indices.push_back(startIndex + 0);
            indices.push_back(startIndex + 1);
            indices.push_back(startIndex + 2);

            indices.push_back(startIndex + 1);
            indices.push_back(startIndex + 3);
            indices.push_back(startIndex + 2);

            Vector2 leftTop(f->x / static_cast<float>(width),
                            f->y / static_cast<float>(height));

            Vector2 rightBottom((f->x + f->width) / static_cast<float>(width),
                                (f->y + f->height) / static_cast<float>(height));

            textCoords[0] = Vector2(leftTop.x, leftTop.y);
            textCoords[1] = Vector2(rightBottom.x, leftTop.y);
            textCoords[2] = Vector2(leftTop.x, rightBottom.y);
            textCoords[3] = Vector2(rightBottom.x, rightBottom.y);

            if (texture->isFlipped())
            {
                leftTop.y = 1.0f - leftTop.y;
                rightBottom.y = 1.0f - rightBottom.y;
            }

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset, y - f->yOffset, 0.0f),
                                         color, textCoords[0]));

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset + f->width, y - f->yOffset, 0.0f),
                                         color, textCoords[1]));

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset, y - f->yOffset - f->height, 0.0f),
                                         color, textCoords[2]));

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset + f->width, y - f->yOffset - f->height, 0.0f),
                                         color, textCoords[3]));

            // Only check kerning if there is greater then 1 character and
            // if the check character is 1 less then the end of the string.
            if (flen > 1 && i < flen)
            {
                x += getKerningPair(text[i], text[i+1]);
            }

            x +=  f->xAdvance;
        }

        float totalWidth = x;

        for (graphics::VertexPCT& vertex : vertices)
        {
            vertex.position.x -= totalWidth * anchor.x;
        }
    }
}
<commit_msg>Load BMFont from memory<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "BMFont.h"
#include "Engine.h"
#include "FileSystem.h"
#include "Vertex.h"
#include "Cache.h"
#include "Utils.h"

namespace ouzel
{
    template<typename CharT, typename TraitsT = std::char_traits<CharT>>
    class VectorBuffer: public std::basic_streambuf<CharT, TraitsT>
    {
    public:
        VectorBuffer(std::vector<uint8_t>& vec)
        {
            std::basic_streambuf<CharT, TraitsT>::setg(reinterpret_cast<CharT*>(vec.data()),
                                                       reinterpret_cast<CharT*>(vec.data()),
                                                       reinterpret_cast<CharT*>(vec.data() + vec.size()));
        }
    };

    BMFont::BMFont()
    {

    }

    BMFont::~BMFont()
    {

    }

    bool BMFont::parseFont(const std::string& filename)
    {
        std::vector<uint8_t> data;
        if (!sharedEngine->getFileSystem()->loadFile(filename, data))
        {
            return false;
        }

        VectorBuffer<char> databuf(data);
        std::istream stream(&databuf);

        std::string line;
        std::string read, key, value;
        std::size_t i;

        if (!stream)
        {
            log("Failed to open font file %s", filename.c_str());
            return false;
        }

        KerningInfo k;
        CharDescriptor c;

        while (!stream.eof())
        {
            std::getline(stream, line);

            std::stringstream lineStream;
            lineStream << line;

            lineStream >> read;

            if (read == "page")
            {
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "file")
                    {
                        // trim quotes
                        if (value.length() && value[0] == '"' && value[value.length() - 1] == '"')
                        {
                            value = value.substr(1, value.length() - 2);
                        }

                        texture = sharedEngine->getCache()->getTexture(value, false, true);
                    }
                }
            }
            else if (read == "common")
            {
                //this holds common data
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "lineHeight") converter >> lineHeight;
                    else if (key == "base") converter >> base;
                    else if (key == "scaleW") converter >> width;
                    else if (key == "scaleH") converter >> height;
                    else if (key == "pages") converter >> pages;
                    else if (key == "outline") converter >> outline;
                }
            }
            else if (read == "char")
            {
                //This is data for each specific character.
                int32_t charId = 0;

                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //Assign the correct value
                    converter << value;
                    if (key == "id") converter >> charId;
                    else if (key == "x") converter >> c.x;
                    else if (key == "y") converter >> c.y;
                    else if (key == "width") converter >> c.width;
                    else if (key == "height") converter >> c.height;
                    else if (key == "xoffset") converter >> c.xOffset;
                    else if (key == "yoffset") converter >> c.yOffset;
                    else if (key == "xadvance") converter >> c.xAdvance;
                    else if (key == "page") converter >> c.page;
                }

                chars.insert(std::map<int32_t, CharDescriptor>::value_type(charId, c));
            }
            else if (read == "kernings")
            {
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "count") converter >> kernCount;
                }
            }
            else if (read == "kerning")
            {
                while (!lineStream.eof())
                {
                    std::stringstream converter;
                    lineStream >> read;
                    i = read.find('=');
                    key = read.substr(0, i);
                    value = read.substr(i + 1);

                    //assign the correct value
                    converter << value;
                    if (key == "first") converter >> k.first;
                    else if (key == "second") converter >> k.second;
                    else if (key == "amount") converter >> k.amount;
                }
                kern[std::make_pair(k.first, k.second)] = k;
            }
        }

        return true;
    }

    int32_t BMFont::getKerningPair(int32_t first, int32_t second)
    {
        std::map<std::pair<int32_t, int32_t>, KerningInfo>::iterator i = kern.find(std::make_pair(first, second));

        if (i != kern.end())
        {
            return i->second.amount;
        }

        return 0;
    }

    float BMFont::getStringWidth(const std::string& text)
    {
        float total = 0;
        CharDescriptor* f;

        for (uint32_t i = 0; i < static_cast<uint32_t>(text.length()); ++i)
        {
            std::map<int32_t, CharDescriptor>::iterator iter = chars.find(text[i]);

            if (iter == chars.end())
            {
                continue;
            }

            f = &iter->second;
            total += f->xAdvance;
        }

        return total;
    }

    bool BMFont::loadFont(const std::string& filename)
    {
        if (!parseFont(filename))
        {
            log("Failed to parse font %s",filename.c_str());
            return false;
        }

        if (!texture)
        {
            return false;
        }

        kernCount = static_cast<uint16_t>(kern.size());

        return true;
    }

    void BMFont::getVertices(const std::string& text, const graphics::Color& color, const Vector2& anchor, std::vector<uint16_t>& indices, std::vector<graphics::VertexPCT>& vertices)
    {
        uint32_t flen;

        CharDescriptor  *f;

        float x = 0.0f;
        float y = lineHeight * (1.0f - anchor.y);

        flen = static_cast<uint32_t>(text.length());

        indices.clear();
        vertices.clear();

        indices.reserve(flen * 6);
        vertices.reserve(flen * 4);

        Vector2 textCoords[4];

        for (uint32_t i = 0; i != flen; ++i)
        {
            std::map<int32_t, CharDescriptor>::iterator iter = chars.find(text[i]);

            if (iter == chars.end())
            {
                continue;
            }
            else
            {
                f = &iter->second;
            }

            uint16_t startIndex = static_cast<uint16_t>(vertices.size());
            indices.push_back(startIndex + 0);
            indices.push_back(startIndex + 1);
            indices.push_back(startIndex + 2);

            indices.push_back(startIndex + 1);
            indices.push_back(startIndex + 3);
            indices.push_back(startIndex + 2);

            Vector2 leftTop(f->x / static_cast<float>(width),
                            f->y / static_cast<float>(height));

            Vector2 rightBottom((f->x + f->width) / static_cast<float>(width),
                                (f->y + f->height) / static_cast<float>(height));

            textCoords[0] = Vector2(leftTop.x, leftTop.y);
            textCoords[1] = Vector2(rightBottom.x, leftTop.y);
            textCoords[2] = Vector2(leftTop.x, rightBottom.y);
            textCoords[3] = Vector2(rightBottom.x, rightBottom.y);

            if (texture->isFlipped())
            {
                leftTop.y = 1.0f - leftTop.y;
                rightBottom.y = 1.0f - rightBottom.y;
            }

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset, y - f->yOffset, 0.0f),
                                         color, textCoords[0]));

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset + f->width, y - f->yOffset, 0.0f),
                                         color, textCoords[1]));

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset, y - f->yOffset - f->height, 0.0f),
                                         color, textCoords[2]));

            vertices.push_back(graphics::VertexPCT(Vector3(x + f->xOffset + f->width, y - f->yOffset - f->height, 0.0f),
                                         color, textCoords[3]));

            // Only check kerning if there is greater then 1 character and
            // if the check character is 1 less then the end of the string.
            if (flen > 1 && i < flen)
            {
                x += getKerningPair(text[i], text[i+1]);
            }

            x +=  f->xAdvance;
        }

        float totalWidth = x;

        for (graphics::VertexPCT& vertex : vertices)
        {
            vertex.position.x -= totalWidth * anchor.x;
        }
    }
}
<|endoftext|>


<commit_before>#include "object.hpp"

namespace p0
{
	namespace run
	{
		object::object()
			: m_is_marked(false)
			, m_is_marked_permanently(false)
		{
		}

		object::~object()
		{
		}

		void object::mark()
		{
			if (is_marked())
			{
				return;
			}

			//mark this object before the children
			//to prevent endless recursion on circular references
			m_is_marked = true;
			mark_recursively();
		}

		void object::unmark()
		{
			m_is_marked = false;
		}

		bool object::is_marked() const
		{
			return m_is_marked || m_is_marked_permanently;
		}

		void object::mark_permanently()
		{
			m_is_marked_permanently = true;
		}

		void object::unmark_permanently()
		{
			m_is_marked_permanently = false;
		}

		bool object::is_marked_permanently() const
		{
			return m_is_marked_permanently;
		}

		boost::optional<value> object::get_element(value const & /*key*/) const
		{
			return boost::optional<value>();
		}

		bool object::set_element(value const & /*key*/, value const & /*value*/)
		{
			return false;
		}

		integer object::get_hash_code() const
		{
			return static_cast<integer>(std::hash<object const *>()(this));
		}

		bool object::equals(object const &other) const
		{
			return (this == &other);
		}

		comparison_result::Enum object::compare(object const &right) const
		{
			if (this < &right)
			{
				return comparison_result::less;
			}
			if (this > &right)
			{
				return comparison_result::greater;
			}
			return comparison_result::equal;
		}

		boost::optional<value> object::call(
			std::vector<value> const & /*arguments*/,
			interpreter & /*interpreter*/)
		{
			return boost::optional<value>();
		}

		boost::optional<value> object::call_method(
				value const & /*method_name*/,
				std::vector<value> const & /*arguments*/,
				interpreter & /*interpreter*/)
		{
			return boost::optional<value>();
		}

		void object::print(std::ostream &out) const
		{
			out << "object";
		}

		bool object::bind(size_t /*index*/, value const & /*value*/)
		{
			return false;
		}

		boost::optional<value> object::get_bound(size_t /*index*/) const
		{
			return boost::optional<value>();
		}
	}
}
<commit_msg>permanent object marking fix<commit_after>#include "object.hpp"

namespace p0
{
	namespace run
	{
		object::object()
			: m_is_marked(false)
			, m_is_marked_permanently(false)
		{
		}

		object::~object()
		{
		}

		void object::mark()
		{
			//m_is_marked_permanently is not a condition here because we have
			//to mark the children anyway
			if (m_is_marked)
			{
				return;
			}

			//mark this object before the children
			//to prevent endless recursion on circular references
			m_is_marked = true;
			mark_recursively();
		}

		void object::unmark()
		{
			m_is_marked = false;
		}

		bool object::is_marked() const
		{
			return m_is_marked || m_is_marked_permanently;
		}

		void object::mark_permanently()
		{
			m_is_marked_permanently = true;
		}

		void object::unmark_permanently()
		{
			m_is_marked_permanently = false;
		}

		bool object::is_marked_permanently() const
		{
			return m_is_marked_permanently;
		}

		boost::optional<value> object::get_element(value const & /*key*/) const
		{
			return boost::optional<value>();
		}

		bool object::set_element(value const & /*key*/, value const & /*value*/)
		{
			return false;
		}

		integer object::get_hash_code() const
		{
			return static_cast<integer>(std::hash<object const *>()(this));
		}

		bool object::equals(object const &other) const
		{
			return (this == &other);
		}

		comparison_result::Enum object::compare(object const &right) const
		{
			if (this < &right)
			{
				return comparison_result::less;
			}
			if (this > &right)
			{
				return comparison_result::greater;
			}
			return comparison_result::equal;
		}

		boost::optional<value> object::call(
			std::vector<value> const & /*arguments*/,
			interpreter & /*interpreter*/)
		{
			return boost::optional<value>();
		}

		boost::optional<value> object::call_method(
				value const & /*method_name*/,
				std::vector<value> const & /*arguments*/,
				interpreter & /*interpreter*/)
		{
			return boost::optional<value>();
		}

		void object::print(std::ostream &out) const
		{
			out << "object";
		}

		bool object::bind(size_t /*index*/, value const & /*value*/)
		{
			return false;
		}

		boost::optional<value> object::get_bound(size_t /*index*/) const
		{
			return boost::optional<value>();
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>do not include non-mask bits in masks<commit_after><|endoftext|>


<commit_before>//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.

#include <math.h>
#include <algorithm>
#include "rocksdb/options.h"

namespace rocksdb {

namespace {

// For now, always use 1-0 as level bytes multiplier.
const int kBytesForLevelMultiplier = 10;
const size_t kBytesForOneMb = 1024 * 1024;

// Pick compaction style
CompactionStyle PickCompactionStyle(size_t write_buffer_size,
                                    int read_amp_threshold,
                                    int write_amp_threshold,
                                    uint64_t target_db_size) {
#ifndef ROCKSDB_LITE
  // Estimate read amplification and write amplification of two compaction
  // styles. If there is hard limit to force a choice, make the choice.
  // Otherwise, calculate a score based on threshold and expected value of
  // two styles, weighing reads 4X important than writes.
  int expected_levels = static_cast<int>(ceil(
      std::log(target_db_size / write_buffer_size) / std::log(kBytesForLevelMultiplier)));

  int expected_max_files_universal =
      static_cast<int>(ceil(log2(target_db_size / write_buffer_size)));

  const int kEstimatedLevel0FilesInLevelStyle = 2;
  // Estimate write amplification:
  // (1) 1 for every L0 file
  // (2) 2 for L1
  // (3) kBytesForLevelMultiplier for the last level. It's really hard to
  //     predict.
  // (3) kBytesForLevelMultiplier for other levels.
  int expected_write_amp_level = kEstimatedLevel0FilesInLevelStyle + 2
      + (expected_levels - 2) * kBytesForLevelMultiplier
      + kBytesForLevelMultiplier;
  int expected_read_amp_level =
      kEstimatedLevel0FilesInLevelStyle + expected_levels;

  int max_read_amp_uni = expected_max_files_universal;
  if (read_amp_threshold <= max_read_amp_uni) {
    return kCompactionStyleLevel;
  } else if (write_amp_threshold <= expected_write_amp_level) {
    return kCompactionStyleUniversal;
  }

  const double kReadWriteWeight = 4;

  double level_ratio =
      static_cast<double>(read_amp_threshold) / expected_read_amp_level *
          kReadWriteWeight +
      static_cast<double>(write_amp_threshold) / expected_write_amp_level;

  int expected_write_amp_uni = expected_max_files_universal / 2 + 2;
  int expected_read_amp_uni = expected_max_files_universal / 2 + 1;

  double uni_ratio =
      static_cast<double>(read_amp_threshold) / expected_read_amp_uni *
          kReadWriteWeight +
      static_cast<double>(write_amp_threshold) / expected_write_amp_uni;

  if (level_ratio > uni_ratio) {
    return kCompactionStyleLevel;
  } else {
    return kCompactionStyleUniversal;
  }
#else
  return kCompactionStyleLevel;
#endif  // !ROCKSDB_LITE
}

// Pick mem table size
void PickWriteBufferSize(size_t total_write_buffer_limit, Options* options) {
  const size_t kMaxWriteBufferSize = 128 * kBytesForOneMb;
  const size_t kMinWriteBufferSize = 4 * kBytesForOneMb;

  // Try to pick up a buffer size between 4MB and 128MB.
  // And try to pick 4 as the total number of write buffers.
  size_t write_buffer_size = total_write_buffer_limit / 4;
  if (write_buffer_size > kMaxWriteBufferSize) {
    write_buffer_size = kMaxWriteBufferSize;
  } else if (write_buffer_size < kMinWriteBufferSize) {
    write_buffer_size = std::min(static_cast<size_t>(kMinWriteBufferSize),
                                 total_write_buffer_limit / 2);
  }

  // Truncate to multiple of 1MB.
  if (write_buffer_size % kBytesForOneMb != 0) {
    write_buffer_size =
        (write_buffer_size / kBytesForOneMb + 1) * kBytesForOneMb;
  }

  options->write_buffer_size = write_buffer_size;
  options->max_write_buffer_number =
      static_cast<int>(total_write_buffer_limit / write_buffer_size);
  options->min_write_buffer_number_to_merge = 1;
}

#ifndef ROCKSDB_LITE
void OptimizeForUniversal(Options* options) {
  options->level0_file_num_compaction_trigger = 2;
  options->level0_slowdown_writes_trigger = 30;
  options->level0_stop_writes_trigger = 40;
  options->max_open_files = -1;
}
#endif

// Optimize parameters for level-based compaction
void OptimizeForLevel(int read_amplification_threshold,
                      int write_amplification_threshold,
                      uint64_t target_db_size, Options* options) {
  int expected_levels_one_level0_file =
      static_cast<int>(ceil(std::log(target_db_size / options->write_buffer_size) /
                            std::log(kBytesForLevelMultiplier)));

  int level0_stop_writes_trigger =
      read_amplification_threshold - expected_levels_one_level0_file;

  const size_t kInitialLevel0TotalSize = 128 * kBytesForOneMb;
  const int kMaxFileNumCompactionTrigger = 4;
  const int kMinLevel0StopTrigger = 3;

  int file_num_buffer = static_cast<int>(
      kInitialLevel0TotalSize / options->write_buffer_size + 1);

  if (level0_stop_writes_trigger > file_num_buffer) {
    // Have sufficient room for multiple level 0 files
    // Try enlarge the buffer up to 1GB

    // Try to enlarge the buffer up to 1GB, if still have sufficient headroom.
    file_num_buffer *=
        1 << std::max(0, std::min(3, level0_stop_writes_trigger -
                                       file_num_buffer - 2));

    options->level0_stop_writes_trigger = level0_stop_writes_trigger;
    options->level0_slowdown_writes_trigger = level0_stop_writes_trigger - 2;
    options->level0_file_num_compaction_trigger =
        std::min(kMaxFileNumCompactionTrigger, file_num_buffer / 2);
  } else {
    options->level0_stop_writes_trigger =
        std::max(kMinLevel0StopTrigger, file_num_buffer);
    options->level0_slowdown_writes_trigger =
        options->level0_stop_writes_trigger - 1;
    options->level0_file_num_compaction_trigger = 1;
  }

  // This doesn't consider compaction and overheads of mem tables. But usually
  // it is in the same order of magnitude.
  size_t expected_level0_compaction_size =
      options->level0_file_num_compaction_trigger * options->write_buffer_size;
  // Enlarge level1 target file size if level0 compaction size is larger.
  uint64_t max_bytes_for_level_base = 10 * kBytesForOneMb;
  if (expected_level0_compaction_size > max_bytes_for_level_base) {
    max_bytes_for_level_base = expected_level0_compaction_size;
  }
  options->max_bytes_for_level_base = max_bytes_for_level_base;
  // Now always set level multiplier to be 10
  options->max_bytes_for_level_multiplier = kBytesForLevelMultiplier;

  const uint64_t kMinFileSize = 2 * kBytesForOneMb;
  // Allow at least 3-way parallelism for compaction between level 1 and 2.
  uint64_t max_file_size = max_bytes_for_level_base / 3;
  if (max_file_size < kMinFileSize) {
    options->target_file_size_base = kMinFileSize;
  } else {
    if (max_file_size % kBytesForOneMb != 0) {
      max_file_size = (max_file_size / kBytesForOneMb + 1) * kBytesForOneMb;
    }
    options->target_file_size_base = max_file_size;
  }

  // TODO: consider to tune num_levels too.
}

}  // namespace

Options GetOptions(size_t total_write_buffer_limit,
                   int read_amplification_threshold,
                   int write_amplification_threshold, uint64_t target_db_size) {
  Options options;
  PickWriteBufferSize(total_write_buffer_limit, &options);
  size_t write_buffer_size = options.write_buffer_size;
  options.compaction_style =
      PickCompactionStyle(write_buffer_size, read_amplification_threshold,
                          write_amplification_threshold, target_db_size);
#ifndef ROCKSDB_LITE
  if (options.compaction_style == kCompactionStyleUniversal) {
    OptimizeForUniversal(&options);
  } else {
#else
  {
#endif  // !ROCKSDB_LITE
    OptimizeForLevel(read_amplification_threshold,
                     write_amplification_threshold, target_db_size, &options);
  }
  return options;
}

}  // namespace rocksdb
<commit_msg>Fix for GCC 5.4 (#1157)<commit_after>//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.

#include <math.h>
#include <cmath>
#include <algorithm>
#include "rocksdb/options.h"

namespace rocksdb {

namespace {

// For now, always use 1-0 as level bytes multiplier.
const int kBytesForLevelMultiplier = 10;
const size_t kBytesForOneMb = 1024 * 1024;

// Pick compaction style
CompactionStyle PickCompactionStyle(size_t write_buffer_size,
                                    int read_amp_threshold,
                                    int write_amp_threshold,
                                    uint64_t target_db_size) {
#ifndef ROCKSDB_LITE
  // Estimate read amplification and write amplification of two compaction
  // styles. If there is hard limit to force a choice, make the choice.
  // Otherwise, calculate a score based on threshold and expected value of
  // two styles, weighing reads 4X important than writes.
  int expected_levels = static_cast<int>(ceil(
      std::log(target_db_size / write_buffer_size) / std::log(kBytesForLevelMultiplier)));

  int expected_max_files_universal =
      static_cast<int>(ceil(log2(target_db_size / write_buffer_size)));

  const int kEstimatedLevel0FilesInLevelStyle = 2;
  // Estimate write amplification:
  // (1) 1 for every L0 file
  // (2) 2 for L1
  // (3) kBytesForLevelMultiplier for the last level. It's really hard to
  //     predict.
  // (3) kBytesForLevelMultiplier for other levels.
  int expected_write_amp_level = kEstimatedLevel0FilesInLevelStyle + 2
      + (expected_levels - 2) * kBytesForLevelMultiplier
      + kBytesForLevelMultiplier;
  int expected_read_amp_level =
      kEstimatedLevel0FilesInLevelStyle + expected_levels;

  int max_read_amp_uni = expected_max_files_universal;
  if (read_amp_threshold <= max_read_amp_uni) {
    return kCompactionStyleLevel;
  } else if (write_amp_threshold <= expected_write_amp_level) {
    return kCompactionStyleUniversal;
  }

  const double kReadWriteWeight = 4;

  double level_ratio =
      static_cast<double>(read_amp_threshold) / expected_read_amp_level *
          kReadWriteWeight +
      static_cast<double>(write_amp_threshold) / expected_write_amp_level;

  int expected_write_amp_uni = expected_max_files_universal / 2 + 2;
  int expected_read_amp_uni = expected_max_files_universal / 2 + 1;

  double uni_ratio =
      static_cast<double>(read_amp_threshold) / expected_read_amp_uni *
          kReadWriteWeight +
      static_cast<double>(write_amp_threshold) / expected_write_amp_uni;

  if (level_ratio > uni_ratio) {
    return kCompactionStyleLevel;
  } else {
    return kCompactionStyleUniversal;
  }
#else
  return kCompactionStyleLevel;
#endif  // !ROCKSDB_LITE
}

// Pick mem table size
void PickWriteBufferSize(size_t total_write_buffer_limit, Options* options) {
  const size_t kMaxWriteBufferSize = 128 * kBytesForOneMb;
  const size_t kMinWriteBufferSize = 4 * kBytesForOneMb;

  // Try to pick up a buffer size between 4MB and 128MB.
  // And try to pick 4 as the total number of write buffers.
  size_t write_buffer_size = total_write_buffer_limit / 4;
  if (write_buffer_size > kMaxWriteBufferSize) {
    write_buffer_size = kMaxWriteBufferSize;
  } else if (write_buffer_size < kMinWriteBufferSize) {
    write_buffer_size = std::min(static_cast<size_t>(kMinWriteBufferSize),
                                 total_write_buffer_limit / 2);
  }

  // Truncate to multiple of 1MB.
  if (write_buffer_size % kBytesForOneMb != 0) {
    write_buffer_size =
        (write_buffer_size / kBytesForOneMb + 1) * kBytesForOneMb;
  }

  options->write_buffer_size = write_buffer_size;
  options->max_write_buffer_number =
      static_cast<int>(total_write_buffer_limit / write_buffer_size);
  options->min_write_buffer_number_to_merge = 1;
}

#ifndef ROCKSDB_LITE
void OptimizeForUniversal(Options* options) {
  options->level0_file_num_compaction_trigger = 2;
  options->level0_slowdown_writes_trigger = 30;
  options->level0_stop_writes_trigger = 40;
  options->max_open_files = -1;
}
#endif

// Optimize parameters for level-based compaction
void OptimizeForLevel(int read_amplification_threshold,
                      int write_amplification_threshold,
                      uint64_t target_db_size, Options* options) {
  int expected_levels_one_level0_file =
      static_cast<int>(ceil(std::log(target_db_size / options->write_buffer_size) /
                            std::log(kBytesForLevelMultiplier)));

  int level0_stop_writes_trigger =
      read_amplification_threshold - expected_levels_one_level0_file;

  const size_t kInitialLevel0TotalSize = 128 * kBytesForOneMb;
  const int kMaxFileNumCompactionTrigger = 4;
  const int kMinLevel0StopTrigger = 3;

  int file_num_buffer = static_cast<int>(
      kInitialLevel0TotalSize / options->write_buffer_size + 1);

  if (level0_stop_writes_trigger > file_num_buffer) {
    // Have sufficient room for multiple level 0 files
    // Try enlarge the buffer up to 1GB

    // Try to enlarge the buffer up to 1GB, if still have sufficient headroom.
    file_num_buffer *=
        1 << std::max(0, std::min(3, level0_stop_writes_trigger -
                                       file_num_buffer - 2));

    options->level0_stop_writes_trigger = level0_stop_writes_trigger;
    options->level0_slowdown_writes_trigger = level0_stop_writes_trigger - 2;
    options->level0_file_num_compaction_trigger =
        std::min(kMaxFileNumCompactionTrigger, file_num_buffer / 2);
  } else {
    options->level0_stop_writes_trigger =
        std::max(kMinLevel0StopTrigger, file_num_buffer);
    options->level0_slowdown_writes_trigger =
        options->level0_stop_writes_trigger - 1;
    options->level0_file_num_compaction_trigger = 1;
  }

  // This doesn't consider compaction and overheads of mem tables. But usually
  // it is in the same order of magnitude.
  size_t expected_level0_compaction_size =
      options->level0_file_num_compaction_trigger * options->write_buffer_size;
  // Enlarge level1 target file size if level0 compaction size is larger.
  uint64_t max_bytes_for_level_base = 10 * kBytesForOneMb;
  if (expected_level0_compaction_size > max_bytes_for_level_base) {
    max_bytes_for_level_base = expected_level0_compaction_size;
  }
  options->max_bytes_for_level_base = max_bytes_for_level_base;
  // Now always set level multiplier to be 10
  options->max_bytes_for_level_multiplier = kBytesForLevelMultiplier;

  const uint64_t kMinFileSize = 2 * kBytesForOneMb;
  // Allow at least 3-way parallelism for compaction between level 1 and 2.
  uint64_t max_file_size = max_bytes_for_level_base / 3;
  if (max_file_size < kMinFileSize) {
    options->target_file_size_base = kMinFileSize;
  } else {
    if (max_file_size % kBytesForOneMb != 0) {
      max_file_size = (max_file_size / kBytesForOneMb + 1) * kBytesForOneMb;
    }
    options->target_file_size_base = max_file_size;
  }

  // TODO: consider to tune num_levels too.
}

}  // namespace

Options GetOptions(size_t total_write_buffer_limit,
                   int read_amplification_threshold,
                   int write_amplification_threshold, uint64_t target_db_size) {
  Options options;
  PickWriteBufferSize(total_write_buffer_limit, &options);
  size_t write_buffer_size = options.write_buffer_size;
  options.compaction_style =
      PickCompactionStyle(write_buffer_size, read_amplification_threshold,
                          write_amplification_threshold, target_db_size);
#ifndef ROCKSDB_LITE
  if (options.compaction_style == kCompactionStyleUniversal) {
    OptimizeForUniversal(&options);
  } else {
#else
  {
#endif  // !ROCKSDB_LITE
    OptimizeForLevel(read_amplification_threshold,
                     write_amplification_threshold, target_db_size, &options);
  }
  return options;
}

}  // namespace rocksdb
<|endoftext|>