Question

I ai mémoire mappée un grand fichier formaté (texte) contenant un nombre entier par ligne comme ceci:

123
345
34324
3232
...

Alors, j'ai un pointeur vers la mémoire au premier octet et aussi un pointeur vers la mémoire au dernier octet. Je suis en train de lire tous les entiers dans un tableau aussi vite que possible. Dans un premier temps j'ai créé un std :: classe spécialisée streambuf à travailler avec std :: istream à lire de cette mémoire, mais il semble être relativement lente.

Avez-vous des suggestions sur la façon d'analyser efficacement une chaîne comme "1231232 \ r \ n123123 \ r \ n123 \ r \ n1231 \ r \ n2387897 ..." dans un tableau {1231232,123123,1231,231, 2387897, ...}?

Le nombre d'entiers dans le fichier n'est pas connu à l'avance.

Était-ce utile?

La solution

std::vector<int> array;
char * p = ...; // start of memory mapped block
while ( not end of memory block )
{
    array.push_back(static_cast<int>(strtol(p, &p, 10)));
    while (not end of memory block && !isdigit(*p))
        ++p;
}

Ce code est un peu dangereux car il n'y a aucune garantie que strtol cessera à la fin du bloc de mémoire mappée, mais il est un début. Devrait aller très vite, même avec une vérification supplémentaire ajouté.

Autres conseils

Ce fut une tâche très intéressante pour moi d'apprendre un peu plus sur C ++.

Admise, le code est assez grand et a beaucoup de contrôle d'erreur, mais que montre seulement combien de différentes choses peuvent mal tourner lors de l'analyse.

#include <ctype.h>
#include <limits.h>
#include <stdio.h>

#include <iterator>
#include <vector>
#include <string>

static void
die(const char *reason)
{
  fprintf(stderr, "aborted (%s)\n", reason);
  exit(EXIT_FAILURE);
}

template <class BytePtr>
static bool
read_uint(BytePtr *begin_ref, BytePtr end, unsigned int *out)
{
  const unsigned int MAX_DIV = UINT_MAX / 10;
  const unsigned int MAX_MOD = UINT_MAX % 10;

  BytePtr begin = *begin_ref;
  unsigned int n = 0;

  while (begin != end && '0' <= *begin && *begin <= '9') {
    unsigned digit = *begin - '0';
    if (n > MAX_DIV || (n == MAX_DIV && digit > MAX_MOD))
      die("unsigned overflow");
    n = 10 * n + digit;
    begin++;
  }

  if (begin == *begin_ref)
    return false;

  *begin_ref = begin;
  *out = n;
  return true;
}

template <class BytePtr, class IntConsumer>
void
parse_ints(BytePtr begin, BytePtr end, IntConsumer out)
{
  while (true) {
    while (begin != end && *begin == (unsigned char) *begin && isspace(*begin))
      begin++;
    if (begin == end)
      return;

    bool negative = *begin == '-';
    if (negative) {
      begin++;
      if (begin == end)
        die("minus at end of input");
    }

    unsigned int un;
    if (!read_uint(&begin, end, &un))
      die("no number found");

    if (!negative && un > INT_MAX)
      die("too large positive");
    if (negative && un > -((unsigned int)INT_MIN))
      die("too small negative");

    int n = negative ? -un : un;
    *out++ = n;
  }
}

static void
print(int x)
{
  printf("%d\n", x);
}

int
main()
{
  std::vector<int> result;
  std::string input("2147483647 -2147483648 0 00000 1 2 32767 4 -17 6");

  parse_ints(input.begin(), input.end(), back_inserter(result));

  std::for_each(result.begin(), result.end(), print);
  return 0;
}

J'ai essayé difficile de ne pas invoquer une sorte de un comportement non défini , qui peut être assez difficile lors de la conversion des nombres non signés à des numéros signés ou invoquer isspace sur un type de données inconnu.

Étant donné que cette mémoire est mis en correspondance simple copier les caractères à un tableau de la pile et l'autre atoi à tableau entier au-dessus d'un autre fichier de mémoire mappée serait le très efficace. De cette façon, le fichier d'échange n'est pas utilisé pour ces grands tampons du tout.

open memory mapped file to output int buffer

declare small stack buffer of 20 chars
while not end of char array
  while current char not  line feed
    copy chars to stack buffer
    null terminate the buffer two chars back
    copy results of int buffer output buffer
    increment the output buffer pointer
  end while  
end while

Bien que cela ne pas utiliser la bibliothèque est a l'avantage de minimiser l'utilisation de la mémoire pour les fichiers de mémoire mappées, de sorte que les tampons temporaires sont limités à une de pile et celui utilisé par atoi en interne. Le tampon de sortie peut être jeté ou à gauche enregistrée dans le fichier au besoin.

NOTE:. Cette réponse a été modifié plusieurs fois

Lu ligne de mémoire en ligne (sur la base lien et ).

class line 
{
   std::string data;
public:
   friend std::istream &operator>>(std::istream &is, line &l) 
   {
      std::getline(is, l.data);
      return is;
   }
   operator std::string() { return data; }    
};

std::streambuf osrb;
setg(ptr, ptr, ptrs + size-1);
std::istream istr(&osrb);

std::vector<int> ints;

std::istream_iterator<line> begin(istr);
std::istream_iterator<line> end;
std::transform(begin, end, std::back_inserter(ints), &boost::lexical_cast<int, std::string>);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top