// Copyright 2006 Google Inc. All Rights Reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//      http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// pattern.h : global pattern references and initialization

// This file implements easy access to statically declared
// data patterns.

#ifndef STRESSAPPTEST_PATTERN_H_
#define STRESSAPPTEST_PATTERN_H_

#include <vector>
#include <string>

// This file must work with autoconf on its public version,
// so these includes are correct.
#include "adler32memcpy.h"
#include "sattypes.h"

// 2 = 128 bit bus, 1 = 64 bit bus, 0 = 32 bit bus
const int kBusShift = 2;

// Pattern and CRC data structure
struct PatternData {
  const char *name;          // Name of this pattern.
  unsigned int *pat;         // Data array.
  unsigned int mask;         // Size - 1. data[index & mask] is always valid.
  unsigned char weight[4];   // Weighted frequency of this pattern.
                             // Each pattern has 32,64,128,256 width versions.
                             // All weights are added up, a random number is
                             // chosen between 0-sum(weights), and the
                             // appropriate pattern is chosen. Thus a weight of
                             // 1 is rare, a weight of 10 is 2x as likely to be
                             // chosen as a weight of 5.
};

// Data structure to access data patterns.
class Pattern {
 public:
  Pattern();
  ~Pattern();
  // Fill pattern data and calculate CRC.
  int Initialize(const struct PatternData &pattern_init,
                 int buswidth,
                 bool invert,
                 int weight);

  // Access data members.
  // "busshift_" allows for repeating each pattern word 1, 2, 4, etc. times.
  // in order to create patterns of different width.
  unsigned int pattern(unsigned int offset) {
    unsigned int data = pattern_->pat[(offset >> busshift_) & pattern_->mask];
    if (inverse_)
      data = ~data;
    return data;
  }
  const AdlerChecksum *crc() {return crc_;}
  unsigned int mask() {return pattern_->mask;}
  unsigned int weight() {return weight_;}
  const char *name() {return name_.c_str();}

 private:
  int CalculateCrc();
  const struct PatternData *pattern_;
  int busshift_;        // Target data bus width.
  bool inverse_;        // Invert the data from the original pattern.
  AdlerChecksum *crc_;  // CRC of this pattern.
  string name_;         // The human readable pattern name.
  int weight_;          // This is the likelihood that this
                        // pattern will be chosen.
  // We want to copy this!
  // DISALLOW_COPY_AND_ASSIGN(Pattern);
};

// Object used to access global pattern list.
class PatternList {
 public:
  PatternList();
  ~PatternList();
  // Initialize pointers to global data patterns, and calculate CRC.
  int Initialize();
  int Destroy();

  // Return the pattern designated by index i.
  Pattern *GetPattern(int i);
  // Return a random pattern according to the specified weighted probability.
  Pattern *GetRandomPattern();
  // Return the number of patterns available.
  int Size() {return size_;}

 private:
  vector<class Pattern> patterns_;
  int weightcount_;  // Total count of pattern weights.
  unsigned int size_;
  int initialized_;
  DISALLOW_COPY_AND_ASSIGN(PatternList);
};

// CrcIncrement allows an abstracted way to add a 32bit
// value into a running CRC. This function should be fast, and
// generate meaningful CRCs for the types of data patterns that
// we are using here.
// This CRC formula may not be optimal, but it does work.
// It may be improved in the future.
static inline uint32 CrcIncrement(uint32 crc, uint32 expected, int index) {
  uint32 addition = (expected ^ index);
  uint32 carry = (addition & crc) >> 31;

  return crc + addition + carry;
}


#endif  // STRESSAPPTEST_PATTERN_H_