...

Source file src/github.com/alecthomas/chroma/v2/lexers/lexer_benchmark_test.go

Documentation: github.com/alecthomas/chroma/v2/lexers

     1  package lexers_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	assert "github.com/alecthomas/assert/v2"
     7  
     8  	"github.com/alecthomas/chroma/v2"
     9  	"github.com/alecthomas/chroma/v2/lexers"
    10  )
    11  
    12  const lexerBenchSource = `/*
    13   * Licensed to the Apache Software Foundation (ASF) under one or more
    14   * contributor license agreements. See the NOTICE file distributed with
    15   * this work for additional information regarding copyright ownership.
    16   * The ASF licenses this file to You under the Apache License, Version 2.0
    17   * (the "License"); you may not use this file except in compliance with
    18   * the License. You may obtain a copy of the License at
    19   *
    20   *    http://www.apache.org/licenses/LICENSE-2.0
    21   *
    22   * Unless required by applicable law or agreed to in writing, software
    23   * distributed under the License is distributed on an "AS IS" BASIS,
    24   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    25   * See the License for the specific language governing permissions and
    26   * limitations under the License.
    27   */
    28  package org.apache.kafka.server.common;
    29  
    30  import org.apache.kafka.common.utils.Utils;
    31  
    32  import java.io.BufferedReader;
    33  import java.io.BufferedWriter;
    34  import java.io.File;
    35  import java.io.FileOutputStream;
    36  import java.io.IOException;
    37  import java.io.OutputStreamWriter;
    38  import java.nio.charset.StandardCharsets;
    39  import java.nio.file.FileAlreadyExistsException;
    40  import java.nio.file.Files;
    41  import java.nio.file.Path;
    42  import java.nio.file.Paths;
    43  import java.util.ArrayList;
    44  import java.util.Collection;
    45  import java.util.Collections;
    46  import java.util.List;
    47  import java.util.Optional;
    48  
    49  /**
    50   * This class represents a utility to capture a checkpoint in a file. It writes down to the file in the below format.
    51   *
    52   * ========= File beginning =========
    53   * version: int
    54   * entries-count: int
    55   * entry-as-string-on-each-line
    56   * ========= File end ===============
    57   *
    58   * Each entry is represented as a string on each line in the checkpoint file. {@link EntryFormatter} is used
    59   * to convert the entry into a string and vice versa.
    60   *
    61   * @param <T> entry type.
    62   */
    63  public class CheckpointFile<T> {
    64  
    65      private final int version;
    66      private final EntryFormatter<T> formatter;
    67      private final Object lock = new Object();
    68      private final Path absolutePath;
    69      private final Path tempPath;
    70  
    71      public CheckpointFile(File file,
    72                            int version,
    73                            EntryFormatter<T> formatter) throws IOException {
    74          this.version = version;
    75          this.formatter = formatter;
    76          try {
    77              // Create the file if it does not exist.
    78              Files.createFile(file.toPath());
    79          } catch (FileAlreadyExistsException ex) {
    80              // Ignore if file already exists.
    81          }
    82          absolutePath = file.toPath().toAbsolutePath();
    83          tempPath = Paths.get(absolutePath.toString() + ".tmp");
    84      }
    85  
    86      public void write(Collection<T> entries) throws IOException {
    87          synchronized (lock) {
    88              // write to temp file and then swap with the existing file
    89              try (FileOutputStream fileOutputStream = new FileOutputStream(tempPath.toFile());
    90                   BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8))) {
    91                  // Write the version
    92                  writer.write(Integer.toString(version));
    93                  writer.newLine();
    94  
    95                  // Write the entries count
    96                  writer.write(Integer.toString(entries.size()));
    97                  writer.newLine();
    98  
    99                  // Write each entry on a new line.
   100                  for (T entry : entries) {
   101                      writer.write(formatter.toString(entry));
   102                      writer.newLine();
   103                  }
   104  
   105                  writer.flush();
   106                  fileOutputStream.getFD().sync();
   107              }
   108  
   109              Utils.atomicMoveWithFallback(tempPath, absolutePath);
   110          }
   111      }
   112  
   113      public List<T> read() throws IOException {
   114          synchronized (lock) {
   115              try (BufferedReader reader = Files.newBufferedReader(absolutePath)) {
   116                  CheckpointReadBuffer<T> checkpointBuffer = new CheckpointReadBuffer<>(absolutePath.toString(), reader, version, formatter);
   117                  return checkpointBuffer.read();
   118              }
   119          }
   120      }
   121  
   122      private static class CheckpointReadBuffer<T> {
   123  
   124          private final String location;
   125          private final BufferedReader reader;
   126          private final int version;
   127          private final EntryFormatter<T> formatter;
   128  
   129          CheckpointReadBuffer(String location,
   130                               BufferedReader reader,
   131                               int version,
   132                               EntryFormatter<T> formatter) {
   133              this.location = location;
   134              this.reader = reader;
   135              this.version = version;
   136              this.formatter = formatter;
   137          }
   138  
   139          List<T> read() throws IOException {
   140              String line = reader.readLine();
   141              if (line == null)
   142                  return Collections.emptyList();
   143  
   144              int readVersion = toInt(line);
   145              if (readVersion != version) {
   146                  throw new IOException("Unrecognised version:" + readVersion + ", expected version: " + version
   147                                                + " in checkpoint file at: " + location);
   148              }
   149  
   150              line = reader.readLine();
   151              if (line == null) {
   152                  return Collections.emptyList();
   153              }
   154              int expectedSize = toInt(line);
   155              List<T> entries = new ArrayList<>(expectedSize);
   156              line = reader.readLine();
   157              while (line != null) {
   158                  Optional<T> maybeEntry = formatter.fromString(line);
   159                  if (!maybeEntry.isPresent()) {
   160                      throw buildMalformedLineException(line);
   161                  }
   162                  entries.add(maybeEntry.get());
   163                  line = reader.readLine();
   164              }
   165  
   166              if (entries.size() != expectedSize) {
   167                  throw new IOException("Expected [" + expectedSize + "] entries in checkpoint file ["
   168                                                + location + "], but found only [" + entries.size() + "]");
   169              }
   170  
   171              return entries;
   172          }
   173  
   174          private int toInt(String line) throws IOException {
   175              try {
   176                  return Integer.parseInt(line);
   177              } catch (NumberFormatException e) {
   178                  throw buildMalformedLineException(line);
   179              }
   180          }
   181  
   182          private IOException buildMalformedLineException(String line) {
   183              return new IOException(String.format("Malformed line in checkpoint file [%s]: %s", location, line));
   184          }
   185      }
   186  
   187      /**
   188       * This is used to convert the given entry of type {@code T} into a string and vice versa.
   189       *
   190       * @param <T> entry type
   191       */
   192      public interface EntryFormatter<T> {
   193  
   194          /**
   195           * @param entry entry to be converted into string.
   196           * @return String representation of the given entry.
   197           */
   198          String toString(T entry);
   199  
   200          /**
   201           * @param value string representation of an entry.
   202           * @return entry converted from the given string representation if possible. {@link Optional#empty()} represents
   203           * that the given string representation could not be converted into an entry.
   204           */
   205          Optional<T> fromString(String value);
   206      }
   207  }
   208  `
   209  
   210  func Benchmark(b *testing.B) {
   211  	b.ReportAllocs()
   212  	for i := 0; i < b.N; i++ {
   213  		it, err := lexers.GlobalLexerRegistry.Get("Java").Tokenise(nil, lexerBenchSource)
   214  		assert.NoError(b, err)
   215  		for t := it(); t != chroma.EOF; t = it() {
   216  		}
   217  	}
   218  }
   219  

View as plain text