/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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.
 */

/**
 * Autogenerated by Thrift Compiler (0.14.1)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
#pragma once

#include <thrift/TApplicationException.h>
#include <thrift/TBase.h>
#include <thrift/Thrift.h>
#include <thrift/protocol/TProtocol.h>
#include <thrift/transport/TTransport.h>

#include <fmt/format.h>
#include <functional>
#include <iosfwd>
#include <memory>

namespace facebook::velox::parquet::thrift {

/**
 * Types supported by Parquet.  These types are intended to be used in
 * combination with the encodings to control the on disk storage format. For
 * example INT16 is not included as a type since a good encoding of INT32 would
 * handle this.
 */
struct Type {
  enum type {
    BOOLEAN = 0,
    INT32 = 1,
    INT64 = 2,
    INT96 = 3,
    FLOAT = 4,
    DOUBLE = 5,
    BYTE_ARRAY = 6,
    FIXED_LEN_BYTE_ARRAY = 7
  };
};

extern const std::map<int, const char*> _Type_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const Type::type& val);

std::string to_string(const Type::type& val);

/**
 * DEPRECATED: Common types used by frameworks(e.g. hive, pig) using parquet.
 * ConvertedType is superseded by LogicalType.  This enum should not be
 * extended.
 *
 * See LogicalTypes.md for conversion between ConvertedType and LogicalType.
 */
struct ConvertedType {
  enum type {
    /**
     * a BYTE_ARRAY actually contains UTF8 encoded chars
     */
    UTF8 = 0,
    /**
     * a map is converted as an optional field containing a repeated key/value
     * pair
     */
    MAP = 1,
    /**
     * a key/value pair is converted into a group of two fields
     */
    MAP_KEY_VALUE = 2,
    /**
     * a list is converted into an optional field containing a repeated field
     * for its values
     */
    LIST = 3,
    /**
     * an enum is converted into a binary field
     */
    ENUM = 4,
    /**
     * A decimal value.
     *
     * This may be used to annotate binary or fixed primitive types. The
     * underlying byte array stores the unscaled value encoded as two's
     * complement using big-endian byte order (the most significant byte is the
     * zeroth element). The value of the decimal is the value * 10^{-scale}.
     *
     * This must be accompanied by a (maximum) precision and a scale in the
     * SchemaElement. The precision specifies the number of digits in the
     * decimal and the scale stores the location of the decimal point. For
     * example 1.23 would have precision 3 (3 total digits) and scale 2 (the
     * decimal point is 2 digits over).
     */
    DECIMAL = 5,
    /**
     * A Date
     *
     * Stored as days since Unix epoch, encoded as the INT32 physical type.
     *
     */
    DATE = 6,
    /**
     * A time
     *
     * The total number of milliseconds since midnight.  The value is stored
     * as an INT32 physical type.
     */
    TIME_MILLIS = 7,
    /**
     * A time.
     *
     * The total number of microseconds since midnight.  The value is stored as
     * an INT64 physical type.
     */
    TIME_MICROS = 8,
    /**
     * A date/time combination
     *
     * Date and time recorded as milliseconds since the Unix epoch.  Recorded as
     * a physical type of INT64.
     */
    TIMESTAMP_MILLIS = 9,
    /**
     * A date/time combination
     *
     * Date and time recorded as microseconds since the Unix epoch.  The value
     * is stored as an INT64 physical type.
     */
    TIMESTAMP_MICROS = 10,
    /**
     * An unsigned integer value.
     *
     * The number describes the maximum number of meaningful data bits in
     * the stored value. 8, 16 and 32 bit values are stored using the
     * INT32 physical type.  64 bit values are stored using the INT64
     * physical type.
     *
     */
    UINT_8 = 11,
    UINT_16 = 12,
    UINT_32 = 13,
    UINT_64 = 14,
    /**
     * A signed integer value.
     *
     * The number describes the maximum number of meaningful data bits in
     * the stored value. 8, 16 and 32 bit values are stored using the
     * INT32 physical type.  64 bit values are stored using the INT64
     * physical type.
     *
     */
    INT_8 = 15,
    INT_16 = 16,
    INT_32 = 17,
    INT_64 = 18,
    /**
     * An embedded JSON document
     *
     * A JSON document embedded within a single UTF8 column.
     */
    JSON = 19,
    /**
     * An embedded BSON document
     *
     * A BSON document embedded within a single BINARY column.
     */
    BSON = 20,
    /**
     * An interval of time
     *
     * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12
     * This data is composed of three separate little endian unsigned
     * integers.  Each stores a component of a duration of time.  The first
     * integer identifies the number of months associated with the duration,
     * the second identifies the number of days associated with the duration
     * and the third identifies the number of milliseconds associated with
     * the provided duration.  This duration of time is independent of any
     * particular timezone or date.
     */
    INTERVAL = 21
  };
};

extern const std::map<int, const char*> _ConvertedType_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const ConvertedType::type& val);

std::string to_string(const ConvertedType::type& val);

/**
 * Representation of Schemas
 */
struct FieldRepetitionType {
  enum type {
    /**
     * This field is required (can not be null) and each record has exactly 1
     * value.
     */
    REQUIRED = 0,
    /**
     * The field is optional (can be null) and each record has 0 or 1 values.
     */
    OPTIONAL = 1,
    /**
     * The field is repeated and can contain 0 or more values
     */
    REPEATED = 2
  };
};

extern const std::map<int, const char*> _FieldRepetitionType_VALUES_TO_NAMES;

std::ostream& operator<<(
    std::ostream& out,
    const FieldRepetitionType::type& val);

std::string to_string(const FieldRepetitionType::type& val);

/**
 * Encodings supported by Parquet.  Not all encodings are valid for all types.
 * These enums are also used to specify the encoding of definition and
 * repetition levels. See the accompanying doc for the details of the more
 * complicated encodings.
 */
struct Encoding {
  enum type {
    /**
     * Default encoding.
     * BOOLEAN - 1 bit per value. 0 is false; 1 is true.
     * INT32 - 4 bytes per value.  Stored as little-endian.
     * INT64 - 8 bytes per value.  Stored as little-endian.
     * FLOAT - 4 bytes per value.  IEEE. Stored as little-endian.
     * DOUBLE - 8 bytes per value.  IEEE. Stored as little-endian.
     * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes.
     * FIXED_LEN_BYTE_ARRAY - Just the bytes.
     */
    PLAIN = 0,
    /**
     * Deprecated: Dictionary encoding. The values in the dictionary are encoded
     * in the plain type. in a data page use RLE_DICTIONARY instead. in a
     * Dictionary page use PLAIN instead
     */
    PLAIN_DICTIONARY = 2,
    /**
     * Group packed run length encoding. Usable for definition/repetition levels
     * encoding and Booleans (on one bit: 0 is false; 1 is true.)
     */
    RLE = 3,
    /**
     * Bit packed encoding.  This can only be used if the data has a known max
     * width.  Usable for definition/repetition levels encoding.
     */
    BIT_PACKED = 4,
    /**
     * Delta encoding for integers. This can be used for int columns and works
     * best on sorted data
     */
    DELTA_BINARY_PACKED = 5,
    /**
     * Encoding for byte arrays to separate the length values and the data. The
     * lengths are encoded using DELTA_BINARY_PACKED
     */
    DELTA_LENGTH_BYTE_ARRAY = 6,
    /**
     * Incremental-encoded byte array. Prefix lengths are encoded using
     * DELTA_BINARY_PACKED. Suffixes are stored as delta length byte arrays.
     */
    DELTA_BYTE_ARRAY = 7,
    /**
     * Dictionary encoding: the ids are encoded using the RLE encoding
     */
    RLE_DICTIONARY = 8,
    /**
     * Encoding for floating-point data.
     * K byte-streams are created where K is the size in bytes of the data type.
     * The individual bytes of an FP value are scattered to the corresponding
     * stream and the streams are concatenated. This itself does not reduce the
     * size of the data but can lead to better compression afterwards.
     */
    BYTE_STREAM_SPLIT = 9
  };
};

extern const std::map<int, const char*> _Encoding_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const Encoding::type& val);

std::string to_string(const Encoding::type& val);

/**
 * Supported compression algorithms.
 *
 * Codecs added in format version X.Y can be read by readers based on X.Y and
 * later. Codec support may vary between readers based on the format version and
 * libraries available at runtime.
 *
 * See Compression.md for a detailed specification of these algorithms.
 */
struct CompressionCodec {
  enum type {
    UNCOMPRESSED = 0,
    SNAPPY = 1,
    GZIP = 2,
    LZO = 3,
    BROTLI = 4,
    LZ4 = 5,
    ZSTD = 6,
    LZ4_RAW = 7
  };
};

extern const std::map<int, const char*> _CompressionCodec_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const CompressionCodec::type& val);

std::string to_string(const CompressionCodec::type& val);

struct PageType {
  enum type {
    DATA_PAGE = 0,
    INDEX_PAGE = 1,
    DICTIONARY_PAGE = 2,
    DATA_PAGE_V2 = 3
  };
};

extern const std::map<int, const char*> _PageType_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const PageType::type& val);

std::string to_string(const PageType::type& val);

/**
 * Enum to annotate whether lists of min/max elements inside ColumnIndex
 * are ordered and if so, in which direction.
 */
struct BoundaryOrder {
  enum type { UNORDERED = 0, ASCENDING = 1, DESCENDING = 2 };
};

extern const std::map<int, const char*> _BoundaryOrder_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const BoundaryOrder::type& val);

std::string to_string(const BoundaryOrder::type& val);

class Statistics;

class StringType;

class UUIDType;

class MapType;

class ListType;

class EnumType;

class DateType;

class NullType;

class DecimalType;

class MilliSeconds;

class MicroSeconds;

class NanoSeconds;

class TimeUnit;

class TimestampType;

class TimeType;

class IntType;

class JsonType;

class BsonType;

class LogicalType;

class SchemaElement;

class DataPageHeader;

class IndexPageHeader;

class DictionaryPageHeader;

class DataPageHeaderV2;

class SplitBlockAlgorithm;

class BloomFilterAlgorithm;

class XxHash;

class BloomFilterHash;

class Uncompressed;

class BloomFilterCompression;

class BloomFilterHeader;

class PageHeader;

class KeyValue;

class SortingColumn;

class PageEncodingStats;

class ColumnMetaData;

class EncryptionWithFooterKey;

class EncryptionWithColumnKey;

class ColumnCryptoMetaData;

class ColumnChunk;

class RowGroup;

class TypeDefinedOrder;

class ColumnOrder;

class PageLocation;

class OffsetIndex;

class ColumnIndex;

class AesGcmV1;

class AesGcmCtrV1;

class EncryptionAlgorithm;

class FileMetaData;

class FileCryptoMetaData;

typedef struct _Statistics__isset {
  _Statistics__isset()
      : max(false),
        min(false),
        null_count(false),
        distinct_count(false),
        max_value(false),
        min_value(false) {}
  bool max : 1;
  bool min : 1;
  bool null_count : 1;
  bool distinct_count : 1;
  bool max_value : 1;
  bool min_value : 1;
} _Statistics__isset;

/**
 * Statistics per row group and per page
 * All fields are optional.
 */
class Statistics : public virtual apache::thrift::TBase {
 public:
  Statistics(const Statistics&);
  Statistics& operator=(const Statistics&);
  Statistics()
      : max(),
        min(),
        null_count(0),
        distinct_count(0),
        max_value(),
        min_value() {}

  virtual ~Statistics() noexcept;
  /**
   * DEPRECATED: min and max value of the column. Use min_value and max_value.
   *
   * Values are encoded using PLAIN encoding, except that variable-length byte
   * arrays do not include a length prefix.
   *
   * These fields encode min and max values determined by signed comparison
   * only. New files should use the correct order for a column's logical type
   * and store the values in the min_value and max_value fields.
   *
   * To support older readers, these may be set when the column order is
   * signed.
   */
  std::string max;
  std::string min;
  /**
   * count of null value in the column
   */
  int64_t null_count;
  /**
   * count of distinct values occurring
   */
  int64_t distinct_count;
  /**
   * Min and max values for the column, determined by its ColumnOrder.
   *
   * Values are encoded using PLAIN encoding, except that variable-length byte
   * arrays do not include a length prefix.
   */
  std::string max_value;
  std::string min_value;

  _Statistics__isset __isset;

  void __set_max(const std::string& val);

  void __set_min(const std::string& val);

  void __set_null_count(const int64_t val);

  void __set_distinct_count(const int64_t val);

  void __set_max_value(const std::string& val);

  void __set_min_value(const std::string& val);

  bool operator==(const Statistics& rhs) const {
    if (__isset.max != rhs.__isset.max)
      return false;
    else if (__isset.max && !(max == rhs.max))
      return false;
    if (__isset.min != rhs.__isset.min)
      return false;
    else if (__isset.min && !(min == rhs.min))
      return false;
    if (__isset.null_count != rhs.__isset.null_count)
      return false;
    else if (__isset.null_count && !(null_count == rhs.null_count))
      return false;
    if (__isset.distinct_count != rhs.__isset.distinct_count)
      return false;
    else if (__isset.distinct_count && !(distinct_count == rhs.distinct_count))
      return false;
    if (__isset.max_value != rhs.__isset.max_value)
      return false;
    else if (__isset.max_value && !(max_value == rhs.max_value))
      return false;
    if (__isset.min_value != rhs.__isset.min_value)
      return false;
    else if (__isset.min_value && !(min_value == rhs.min_value))
      return false;
    return true;
  }
  bool operator!=(const Statistics& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const Statistics&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(Statistics& a, Statistics& b);

std::ostream& operator<<(std::ostream& out, const Statistics& obj);

/**
 * Empty structs to use as logical type annotations
 */
class StringType : public virtual ::apache::thrift::TBase {
 public:
  StringType(const StringType&);
  StringType& operator=(const StringType&);
  StringType() {}

  virtual ~StringType() noexcept;

  bool operator==(const StringType& /* rhs */) const {
    return true;
  }
  bool operator!=(const StringType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const StringType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(StringType& a, StringType& b);

std::ostream& operator<<(std::ostream& out, const StringType& obj);

class UUIDType : public virtual ::apache::thrift::TBase {
 public:
  UUIDType(const UUIDType&);
  UUIDType& operator=(const UUIDType&);
  UUIDType() {}

  virtual ~UUIDType() noexcept;

  bool operator==(const UUIDType& /* rhs */) const {
    return true;
  }
  bool operator!=(const UUIDType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const UUIDType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(UUIDType& a, UUIDType& b);

std::ostream& operator<<(std::ostream& out, const UUIDType& obj);

class MapType : public virtual ::apache::thrift::TBase {
 public:
  MapType(const MapType&);
  MapType& operator=(const MapType&);
  MapType() {}

  virtual ~MapType() noexcept;

  bool operator==(const MapType& /* rhs */) const {
    return true;
  }
  bool operator!=(const MapType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const MapType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(MapType& a, MapType& b);

std::ostream& operator<<(std::ostream& out, const MapType& obj);

class ListType : public virtual ::apache::thrift::TBase {
 public:
  ListType(const ListType&);
  ListType& operator=(const ListType&);
  ListType() {}

  virtual ~ListType() noexcept;

  bool operator==(const ListType& /* rhs */) const {
    return true;
  }
  bool operator!=(const ListType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const ListType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ListType& a, ListType& b);

std::ostream& operator<<(std::ostream& out, const ListType& obj);

class EnumType : public virtual ::apache::thrift::TBase {
 public:
  EnumType(const EnumType&);
  EnumType& operator=(const EnumType&);
  EnumType() {}

  virtual ~EnumType() noexcept;

  bool operator==(const EnumType& /* rhs */) const {
    return true;
  }
  bool operator!=(const EnumType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const EnumType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EnumType& a, EnumType& b);

std::ostream& operator<<(std::ostream& out, const EnumType& obj);

class DateType : public virtual ::apache::thrift::TBase {
 public:
  DateType(const DateType&);
  DateType& operator=(const DateType&);
  DateType() {}

  virtual ~DateType() noexcept;

  bool operator==(const DateType& /* rhs */) const {
    return true;
  }
  bool operator!=(const DateType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const DateType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DateType& a, DateType& b);

std::ostream& operator<<(std::ostream& out, const DateType& obj);

/**
 * Logical type to annotate a column that is always null.
 *
 * Sometimes when discovering the schema of existing data, values are always
 * null and the physical type can't be determined. This annotation signals
 * the case where the physical type was guessed from all null values.
 */
class NullType : public virtual ::apache::thrift::TBase {
 public:
  NullType(const NullType&);
  NullType& operator=(const NullType&);
  NullType() {}

  virtual ~NullType() noexcept;

  bool operator==(const NullType& /* rhs */) const {
    return true;
  }
  bool operator!=(const NullType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const NullType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(NullType& a, NullType& b);

std::ostream& operator<<(std::ostream& out, const NullType& obj);

/**
 * Decimal logical type annotation
 *
 * To maintain forward-compatibility in v1, implementations using this logical
 * type must also set scale and precision on the annotated SchemaElement.
 *
 * Allowed for physical types: INT32, INT64, FIXED, and BINARY
 */
class DecimalType : public virtual ::apache::thrift::TBase {
 public:
  DecimalType(const DecimalType&);
  DecimalType& operator=(const DecimalType&);
  DecimalType() : scale(0), precision(0) {}

  virtual ~DecimalType() noexcept;
  int32_t scale;
  int32_t precision;

  void __set_scale(const int32_t val);

  void __set_precision(const int32_t val);

  bool operator==(const DecimalType& rhs) const {
    if (!(scale == rhs.scale))
      return false;
    if (!(precision == rhs.precision))
      return false;
    return true;
  }
  bool operator!=(const DecimalType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const DecimalType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DecimalType& a, DecimalType& b);

std::ostream& operator<<(std::ostream& out, const DecimalType& obj);

/**
 * Time units for logical types
 */
class MilliSeconds : public virtual ::apache::thrift::TBase {
 public:
  MilliSeconds(const MilliSeconds&);
  MilliSeconds& operator=(const MilliSeconds&);
  MilliSeconds() {}

  virtual ~MilliSeconds() noexcept;

  bool operator==(const MilliSeconds& /* rhs */) const {
    return true;
  }
  bool operator!=(const MilliSeconds& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const MilliSeconds&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(MilliSeconds& a, MilliSeconds& b);

std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj);

class MicroSeconds : public virtual ::apache::thrift::TBase {
 public:
  MicroSeconds(const MicroSeconds&);
  MicroSeconds& operator=(const MicroSeconds&);
  MicroSeconds() {}

  virtual ~MicroSeconds() noexcept;

  bool operator==(const MicroSeconds& /* rhs */) const {
    return true;
  }
  bool operator!=(const MicroSeconds& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const MicroSeconds&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(MicroSeconds& a, MicroSeconds& b);

std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj);

class NanoSeconds : public virtual ::apache::thrift::TBase {
 public:
  NanoSeconds(const NanoSeconds&);
  NanoSeconds& operator=(const NanoSeconds&);
  NanoSeconds() {}

  virtual ~NanoSeconds() noexcept;

  bool operator==(const NanoSeconds& /* rhs */) const {
    return true;
  }
  bool operator!=(const NanoSeconds& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const NanoSeconds&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(NanoSeconds& a, NanoSeconds& b);

std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj);

typedef struct _TimeUnit__isset {
  _TimeUnit__isset() : MILLIS(false), MICROS(false), NANOS(false) {}
  bool MILLIS : 1;
  bool MICROS : 1;
  bool NANOS : 1;
} _TimeUnit__isset;

class TimeUnit : public virtual ::apache::thrift::TBase {
 public:
  TimeUnit(const TimeUnit&);
  TimeUnit& operator=(const TimeUnit&);
  TimeUnit() {}

  virtual ~TimeUnit() noexcept;
  MilliSeconds MILLIS;
  MicroSeconds MICROS;
  NanoSeconds NANOS;

  _TimeUnit__isset __isset;

  void __set_MILLIS(const MilliSeconds& val);

  void __set_MICROS(const MicroSeconds& val);

  void __set_NANOS(const NanoSeconds& val);

  bool operator==(const TimeUnit& rhs) const {
    if (__isset.MILLIS != rhs.__isset.MILLIS)
      return false;
    else if (__isset.MILLIS && !(MILLIS == rhs.MILLIS))
      return false;
    if (__isset.MICROS != rhs.__isset.MICROS)
      return false;
    else if (__isset.MICROS && !(MICROS == rhs.MICROS))
      return false;
    if (__isset.NANOS != rhs.__isset.NANOS)
      return false;
    else if (__isset.NANOS && !(NANOS == rhs.NANOS))
      return false;
    return true;
  }
  bool operator!=(const TimeUnit& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const TimeUnit&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TimeUnit& a, TimeUnit& b);

std::ostream& operator<<(std::ostream& out, const TimeUnit& obj);

/**
 * Timestamp logical type annotation
 *
 * Allowed for physical types: INT64
 */
class TimestampType : public virtual ::apache::thrift::TBase {
 public:
  TimestampType(const TimestampType&);
  TimestampType& operator=(const TimestampType&);
  TimestampType() : isAdjustedToUTC(0) {}

  virtual ~TimestampType() noexcept;
  bool isAdjustedToUTC;
  TimeUnit unit;

  void __set_isAdjustedToUTC(const bool val);

  void __set_unit(const TimeUnit& val);

  bool operator==(const TimestampType& rhs) const {
    if (!(isAdjustedToUTC == rhs.isAdjustedToUTC))
      return false;
    if (!(unit == rhs.unit))
      return false;
    return true;
  }
  bool operator!=(const TimestampType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const TimestampType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TimestampType& a, TimestampType& b);

std::ostream& operator<<(std::ostream& out, const TimestampType& obj);

/**
 * Time logical type annotation
 *
 * Allowed for physical types: INT32 (millis), INT64 (micros, nanos)
 */
class TimeType : public virtual ::apache::thrift::TBase {
 public:
  TimeType(const TimeType&);
  TimeType& operator=(const TimeType&);
  TimeType() : isAdjustedToUTC(0) {}

  virtual ~TimeType() noexcept;
  bool isAdjustedToUTC;
  TimeUnit unit;

  void __set_isAdjustedToUTC(const bool val);

  void __set_unit(const TimeUnit& val);

  bool operator==(const TimeType& rhs) const {
    if (!(isAdjustedToUTC == rhs.isAdjustedToUTC))
      return false;
    if (!(unit == rhs.unit))
      return false;
    return true;
  }
  bool operator!=(const TimeType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const TimeType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TimeType& a, TimeType& b);

std::ostream& operator<<(std::ostream& out, const TimeType& obj);

/**
 * Integer logical type annotation
 *
 * bitWidth must be 8, 16, 32, or 64.
 *
 * Allowed for physical types: INT32, INT64
 */
class IntType : public virtual ::apache::thrift::TBase {
 public:
  IntType(const IntType&);
  IntType& operator=(const IntType&);
  IntType() : bitWidth(0), isSigned(0) {}

  virtual ~IntType() noexcept;
  int8_t bitWidth;
  bool isSigned;

  void __set_bitWidth(const int8_t val);

  void __set_isSigned(const bool val);

  bool operator==(const IntType& rhs) const {
    if (!(bitWidth == rhs.bitWidth))
      return false;
    if (!(isSigned == rhs.isSigned))
      return false;
    return true;
  }
  bool operator!=(const IntType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const IntType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(IntType& a, IntType& b);

std::ostream& operator<<(std::ostream& out, const IntType& obj);

/**
 * Embedded JSON logical type annotation
 *
 * Allowed for physical types: BINARY
 */
class JsonType : public virtual ::apache::thrift::TBase {
 public:
  JsonType(const JsonType&);
  JsonType& operator=(const JsonType&);
  JsonType() {}

  virtual ~JsonType() noexcept;

  bool operator==(const JsonType& /* rhs */) const {
    return true;
  }
  bool operator!=(const JsonType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const JsonType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(JsonType& a, JsonType& b);

std::ostream& operator<<(std::ostream& out, const JsonType& obj);

/**
 * Embedded BSON logical type annotation
 *
 * Allowed for physical types: BINARY
 */
class BsonType : public virtual ::apache::thrift::TBase {
 public:
  BsonType(const BsonType&);
  BsonType& operator=(const BsonType&);
  BsonType() {}

  virtual ~BsonType() noexcept;

  bool operator==(const BsonType& /* rhs */) const {
    return true;
  }
  bool operator!=(const BsonType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const BsonType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(BsonType& a, BsonType& b);

std::ostream& operator<<(std::ostream& out, const BsonType& obj);

typedef struct _LogicalType__isset {
  _LogicalType__isset()
      : STRING(false),
        MAP(false),
        LIST(false),
        ENUM(false),
        DECIMAL(false),
        DATE(false),
        TIME(false),
        TIMESTAMP(false),
        INTEGER(false),
        UNKNOWN(false),
        JSON(false),
        BSON(false),
        UUID(false) {}
  bool STRING : 1;
  bool MAP : 1;
  bool LIST : 1;
  bool ENUM : 1;
  bool DECIMAL : 1;
  bool DATE : 1;
  bool TIME : 1;
  bool TIMESTAMP : 1;
  bool INTEGER : 1;
  bool UNKNOWN : 1;
  bool JSON : 1;
  bool BSON : 1;
  bool UUID : 1;
} _LogicalType__isset;

/**
 * LogicalType annotations to replace ConvertedType.
 *
 * To maintain compatibility, implementations using LogicalType for a
 * SchemaElement must also set the corresponding ConvertedType (if any)
 * from the following table.
 */
class LogicalType : public virtual ::apache::thrift::TBase {
 public:
  LogicalType(const LogicalType&);
  LogicalType& operator=(const LogicalType&);
  LogicalType() {}

  virtual ~LogicalType() noexcept;
  StringType STRING;
  MapType MAP;
  ListType LIST;
  EnumType ENUM;
  DecimalType DECIMAL;
  DateType DATE;
  TimeType TIME;
  TimestampType TIMESTAMP;
  IntType INTEGER;
  NullType UNKNOWN;
  JsonType JSON;
  BsonType BSON;
  UUIDType UUID;

  _LogicalType__isset __isset;

  void __set_STRING(const StringType& val);

  void __set_MAP(const MapType& val);

  void __set_LIST(const ListType& val);

  void __set_ENUM(const EnumType& val);

  void __set_DECIMAL(const DecimalType& val);

  void __set_DATE(const DateType& val);

  void __set_TIME(const TimeType& val);

  void __set_TIMESTAMP(const TimestampType& val);

  void __set_INTEGER(const IntType& val);

  void __set_UNKNOWN(const NullType& val);

  void __set_JSON(const JsonType& val);

  void __set_BSON(const BsonType& val);

  void __set_UUID(const UUIDType& val);

  bool operator==(const LogicalType& rhs) const {
    if (__isset.STRING != rhs.__isset.STRING)
      return false;
    else if (__isset.STRING && !(STRING == rhs.STRING))
      return false;
    if (__isset.MAP != rhs.__isset.MAP)
      return false;
    else if (__isset.MAP && !(MAP == rhs.MAP))
      return false;
    if (__isset.LIST != rhs.__isset.LIST)
      return false;
    else if (__isset.LIST && !(LIST == rhs.LIST))
      return false;
    if (__isset.ENUM != rhs.__isset.ENUM)
      return false;
    else if (__isset.ENUM && !(ENUM == rhs.ENUM))
      return false;
    if (__isset.DECIMAL != rhs.__isset.DECIMAL)
      return false;
    else if (__isset.DECIMAL && !(DECIMAL == rhs.DECIMAL))
      return false;
    if (__isset.DATE != rhs.__isset.DATE)
      return false;
    else if (__isset.DATE && !(DATE == rhs.DATE))
      return false;
    if (__isset.TIME != rhs.__isset.TIME)
      return false;
    else if (__isset.TIME && !(TIME == rhs.TIME))
      return false;
    if (__isset.TIMESTAMP != rhs.__isset.TIMESTAMP)
      return false;
    else if (__isset.TIMESTAMP && !(TIMESTAMP == rhs.TIMESTAMP))
      return false;
    if (__isset.INTEGER != rhs.__isset.INTEGER)
      return false;
    else if (__isset.INTEGER && !(INTEGER == rhs.INTEGER))
      return false;
    if (__isset.UNKNOWN != rhs.__isset.UNKNOWN)
      return false;
    else if (__isset.UNKNOWN && !(UNKNOWN == rhs.UNKNOWN))
      return false;
    if (__isset.JSON != rhs.__isset.JSON)
      return false;
    else if (__isset.JSON && !(JSON == rhs.JSON))
      return false;
    if (__isset.BSON != rhs.__isset.BSON)
      return false;
    else if (__isset.BSON && !(BSON == rhs.BSON))
      return false;
    if (__isset.UUID != rhs.__isset.UUID)
      return false;
    else if (__isset.UUID && !(UUID == rhs.UUID))
      return false;
    return true;
  }
  bool operator!=(const LogicalType& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const LogicalType&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(LogicalType& a, LogicalType& b);

std::ostream& operator<<(std::ostream& out, const LogicalType& obj);

typedef struct _SchemaElement__isset {
  _SchemaElement__isset()
      : type(false),
        type_length(false),
        repetition_type(false),
        num_children(false),
        converted_type(false),
        scale(false),
        precision(false),
        field_id(false),
        logicalType(false) {}
  bool type : 1;
  bool type_length : 1;
  bool repetition_type : 1;
  bool num_children : 1;
  bool converted_type : 1;
  bool scale : 1;
  bool precision : 1;
  bool field_id : 1;
  bool logicalType : 1;
} _SchemaElement__isset;

/**
 * Represents a element inside a schema definition.
 *  - if it is a group (inner node) then type is undefined and num_children is
 * defined
 *  - if it is a primitive type (leaf) then type is defined and num_children is
 * undefined the nodes are listed in depth first traversal order.
 */
class SchemaElement : public virtual ::apache::thrift::TBase {
 public:
  SchemaElement(const SchemaElement&);
  SchemaElement& operator=(const SchemaElement&);
  SchemaElement()
      : type((Type::type)0),
        type_length(0),
        repetition_type((FieldRepetitionType::type)0),
        name(),
        num_children(0),
        converted_type((ConvertedType::type)0),
        scale(0),
        precision(0),
        field_id(0) {}

  virtual ~SchemaElement() noexcept;
  /**
   * Data type for this field. Not set if the current element is a non-leaf node
   *
   * @see Type
   */
  Type::type type;
  /**
   * If type is FIXED_LEN_BYTE_ARRAY, this is the byte length of the vales.
   * Otherwise, if specified, this is the maximum bit length to store any of the
   * values. (e.g. a low cardinality INT col could have this set to 3).  Note
   * that this is in the schema, and therefore fixed for the entire file.
   */
  int32_t type_length;
  /**
   * repetition of the field. The root of the schema does not have a
   * repetition_type. All other nodes must have one
   *
   * @see FieldRepetitionType
   */
  FieldRepetitionType::type repetition_type;
  /**
   * Name of the field in the schema
   */
  std::string name;
  /**
   * Nested fields.  Since thrift does not support nested fields,
   * the nesting is flattened to a single list by a depth-first traversal.
   * The children count is used to construct the nested relationship.
   * This field is not set when the element is a primitive type
   */
  int32_t num_children;
  /**
   * DEPRECATED: When the schema is the result of a conversion from another
   * model. Used to record the original type to help with cross conversion.
   *
   * This is superseded by logicalType.
   *
   * @see ConvertedType
   */
  ConvertedType::type converted_type;
  /**
   * DEPRECATED: Used when this column contains decimal data.
   * See the DECIMAL converted type for more details.
   *
   * This is superseded by using the DecimalType annotation in logicalType.
   */
  int32_t scale;
  int32_t precision;
  /**
   * When the original schema supports field ids, this will save the
   * original field id in the parquet schema
   */
  int32_t field_id;
  /**
   * The logical type of this SchemaElement
   *
   * LogicalType replaces ConvertedType, but ConvertedType is still required
   * for some logical types to ensure forward-compatibility in format v1.
   */
  LogicalType logicalType;

  _SchemaElement__isset __isset;

  void __set_type(const Type::type val);

  void __set_type_length(const int32_t val);

  void __set_repetition_type(const FieldRepetitionType::type val);

  void __set_name(const std::string& val);

  void __set_num_children(const int32_t val);

  void __set_converted_type(const ConvertedType::type val);

  void __set_scale(const int32_t val);

  void __set_precision(const int32_t val);

  void __set_field_id(const int32_t val);

  void __set_logicalType(const LogicalType& val);

  bool operator==(const SchemaElement& rhs) const {
    if (__isset.type != rhs.__isset.type)
      return false;
    else if (__isset.type && !(type == rhs.type))
      return false;
    if (__isset.type_length != rhs.__isset.type_length)
      return false;
    else if (__isset.type_length && !(type_length == rhs.type_length))
      return false;
    if (__isset.repetition_type != rhs.__isset.repetition_type)
      return false;
    else if (
        __isset.repetition_type && !(repetition_type == rhs.repetition_type))
      return false;
    if (!(name == rhs.name))
      return false;
    if (__isset.num_children != rhs.__isset.num_children)
      return false;
    else if (__isset.num_children && !(num_children == rhs.num_children))
      return false;
    if (__isset.converted_type != rhs.__isset.converted_type)
      return false;
    else if (__isset.converted_type && !(converted_type == rhs.converted_type))
      return false;
    if (__isset.scale != rhs.__isset.scale)
      return false;
    else if (__isset.scale && !(scale == rhs.scale))
      return false;
    if (__isset.precision != rhs.__isset.precision)
      return false;
    else if (__isset.precision && !(precision == rhs.precision))
      return false;
    if (__isset.field_id != rhs.__isset.field_id)
      return false;
    else if (__isset.field_id && !(field_id == rhs.field_id))
      return false;
    if (__isset.logicalType != rhs.__isset.logicalType)
      return false;
    else if (__isset.logicalType && !(logicalType == rhs.logicalType))
      return false;
    return true;
  }
  bool operator!=(const SchemaElement& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const SchemaElement&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(SchemaElement& a, SchemaElement& b);

std::ostream& operator<<(std::ostream& out, const SchemaElement& obj);

typedef struct _DataPageHeader__isset {
  _DataPageHeader__isset() : statistics(false) {}
  bool statistics : 1;
} _DataPageHeader__isset;

/**
 * Data page header
 */
class DataPageHeader : public virtual ::apache::thrift::TBase {
 public:
  DataPageHeader(const DataPageHeader&);
  DataPageHeader& operator=(const DataPageHeader&);
  DataPageHeader()
      : num_values(0),
        encoding((Encoding::type)0),
        definition_level_encoding((Encoding::type)0),
        repetition_level_encoding((Encoding::type)0) {}

  virtual ~DataPageHeader() noexcept;
  /**
   * Number of values, including NULLs, in this data page. *
   */
  int32_t num_values;
  /**
   * Encoding used for this data page *
   *
   * @see Encoding
   */
  Encoding::type encoding;
  /**
   * Encoding used for definition levels *
   *
   * @see Encoding
   */
  Encoding::type definition_level_encoding;
  /**
   * Encoding used for repetition levels *
   *
   * @see Encoding
   */
  Encoding::type repetition_level_encoding;
  /**
   * Optional statistics for the data in this page*
   */
  Statistics statistics;

  _DataPageHeader__isset __isset;

  void __set_num_values(const int32_t val);

  void __set_encoding(const Encoding::type val);

  void __set_definition_level_encoding(const Encoding::type val);

  void __set_repetition_level_encoding(const Encoding::type val);

  void __set_statistics(const Statistics& val);

  bool operator==(const DataPageHeader& rhs) const {
    if (!(num_values == rhs.num_values))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (!(definition_level_encoding == rhs.definition_level_encoding))
      return false;
    if (!(repetition_level_encoding == rhs.repetition_level_encoding))
      return false;
    if (__isset.statistics != rhs.__isset.statistics)
      return false;
    else if (__isset.statistics && !(statistics == rhs.statistics))
      return false;
    return true;
  }
  bool operator!=(const DataPageHeader& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const DataPageHeader&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DataPageHeader& a, DataPageHeader& b);

std::ostream& operator<<(std::ostream& out, const DataPageHeader& obj);

class IndexPageHeader : public virtual ::apache::thrift::TBase {
 public:
  IndexPageHeader(const IndexPageHeader&);
  IndexPageHeader& operator=(const IndexPageHeader&);
  IndexPageHeader() {}

  virtual ~IndexPageHeader() noexcept;

  bool operator==(const IndexPageHeader& /* rhs */) const {
    return true;
  }
  bool operator!=(const IndexPageHeader& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const IndexPageHeader&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(IndexPageHeader& a, IndexPageHeader& b);

std::ostream& operator<<(std::ostream& out, const IndexPageHeader& obj);

typedef struct _DictionaryPageHeader__isset {
  _DictionaryPageHeader__isset() : is_sorted(false) {}
  bool is_sorted : 1;
} _DictionaryPageHeader__isset;

/**
 * The dictionary page must be placed at the first position of the column chunk
 * if it is partly or completely dictionary encoded. At most one dictionary page
 * can be placed in a column chunk.
 *
 */
class DictionaryPageHeader : public virtual ::apache::thrift::TBase {
 public:
  DictionaryPageHeader(const DictionaryPageHeader&);
  DictionaryPageHeader& operator=(const DictionaryPageHeader&);
  DictionaryPageHeader()
      : num_values(0), encoding((Encoding::type)0), is_sorted(0) {}

  virtual ~DictionaryPageHeader() noexcept;
  /**
   * Number of values in the dictionary *
   */
  int32_t num_values;
  /**
   * Encoding using this dictionary page *
   *
   * @see Encoding
   */
  Encoding::type encoding;
  /**
   * If true, the entries in the dictionary are sorted in ascending order *
   */
  bool is_sorted;

  _DictionaryPageHeader__isset __isset;

  void __set_num_values(const int32_t val);

  void __set_encoding(const Encoding::type val);

  void __set_is_sorted(const bool val);

  bool operator==(const DictionaryPageHeader& rhs) const {
    if (!(num_values == rhs.num_values))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (__isset.is_sorted != rhs.__isset.is_sorted)
      return false;
    else if (__isset.is_sorted && !(is_sorted == rhs.is_sorted))
      return false;
    return true;
  }
  bool operator!=(const DictionaryPageHeader& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const DictionaryPageHeader&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DictionaryPageHeader& a, DictionaryPageHeader& b);

std::ostream& operator<<(std::ostream& out, const DictionaryPageHeader& obj);

typedef struct _DataPageHeaderV2__isset {
  _DataPageHeaderV2__isset() : is_compressed(true), statistics(false) {}
  bool is_compressed : 1;
  bool statistics : 1;
} _DataPageHeaderV2__isset;

/**
 * New page format allowing reading levels without decompressing the data
 * Repetition and definition levels are uncompressed
 * The remaining section containing the data is compressed if is_compressed is
 * true
 *
 */
class DataPageHeaderV2 : public virtual ::apache::thrift::TBase {
 public:
  DataPageHeaderV2(const DataPageHeaderV2&);
  DataPageHeaderV2& operator=(const DataPageHeaderV2&);
  DataPageHeaderV2()
      : num_values(0),
        num_nulls(0),
        num_rows(0),
        encoding((Encoding::type)0),
        definition_levels_byte_length(0),
        repetition_levels_byte_length(0),
        is_compressed(true) {}

  virtual ~DataPageHeaderV2() noexcept;
  /**
   * Number of values, including NULLs, in this data page. *
   */
  int32_t num_values;
  /**
   * Number of NULL values, in this data page.
   * Number of non-null = num_values - num_nulls which is also the number of
   * values in the data section *
   */
  int32_t num_nulls;
  /**
   * Number of rows in this data page. which means pages change on record
   * boundaries (r = 0) *
   */
  int32_t num_rows;
  /**
   * Encoding used for data in this page *
   *
   * @see Encoding
   */
  Encoding::type encoding;
  /**
   * length of the definition levels
   */
  int32_t definition_levels_byte_length;
  /**
   * length of the repetition levels
   */
  int32_t repetition_levels_byte_length;
  /**
   * whether the values are compressed.
   * Which means the section of the page between
   * definition_levels_byte_length + repetition_levels_byte_length + 1 and
   * compressed_page_size (included) is compressed with the compression_codec.
   * If missing it is considered compressed
   */
  bool is_compressed;
  /**
   * optional statistics for the data in this page *
   */
  Statistics statistics;

  _DataPageHeaderV2__isset __isset;

  void __set_num_values(const int32_t val);

  void __set_num_nulls(const int32_t val);

  void __set_num_rows(const int32_t val);

  void __set_encoding(const Encoding::type val);

  void __set_definition_levels_byte_length(const int32_t val);

  void __set_repetition_levels_byte_length(const int32_t val);

  void __set_is_compressed(const bool val);

  void __set_statistics(const Statistics& val);

  bool operator==(const DataPageHeaderV2& rhs) const {
    if (!(num_values == rhs.num_values))
      return false;
    if (!(num_nulls == rhs.num_nulls))
      return false;
    if (!(num_rows == rhs.num_rows))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (!(definition_levels_byte_length == rhs.definition_levels_byte_length))
      return false;
    if (!(repetition_levels_byte_length == rhs.repetition_levels_byte_length))
      return false;
    if (__isset.is_compressed != rhs.__isset.is_compressed)
      return false;
    else if (__isset.is_compressed && !(is_compressed == rhs.is_compressed))
      return false;
    if (__isset.statistics != rhs.__isset.statistics)
      return false;
    else if (__isset.statistics && !(statistics == rhs.statistics))
      return false;
    return true;
  }
  bool operator!=(const DataPageHeaderV2& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const DataPageHeaderV2&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DataPageHeaderV2& a, DataPageHeaderV2& b);

std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj);

/**
 * Block-based algorithm type annotation. *
 */
class SplitBlockAlgorithm : public virtual ::apache::thrift::TBase {
 public:
  SplitBlockAlgorithm(const SplitBlockAlgorithm&);
  SplitBlockAlgorithm& operator=(const SplitBlockAlgorithm&);
  SplitBlockAlgorithm() {}

  virtual ~SplitBlockAlgorithm() noexcept;

  bool operator==(const SplitBlockAlgorithm& /* rhs */) const {
    return true;
  }
  bool operator!=(const SplitBlockAlgorithm& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const SplitBlockAlgorithm&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(SplitBlockAlgorithm& a, SplitBlockAlgorithm& b);

std::ostream& operator<<(std::ostream& out, const SplitBlockAlgorithm& obj);

typedef struct _BloomFilterAlgorithm__isset {
  _BloomFilterAlgorithm__isset() : BLOCK(false) {}
  bool BLOCK : 1;
} _BloomFilterAlgorithm__isset;

/**
 * The algorithm used in Bloom filter. *
 */
class BloomFilterAlgorithm : public virtual ::apache::thrift::TBase {
 public:
  BloomFilterAlgorithm(const BloomFilterAlgorithm&);
  BloomFilterAlgorithm& operator=(const BloomFilterAlgorithm&);
  BloomFilterAlgorithm() {}

  virtual ~BloomFilterAlgorithm() noexcept;
  /**
   * Block-based Bloom filter. *
   */
  SplitBlockAlgorithm BLOCK;

  _BloomFilterAlgorithm__isset __isset;

  void __set_BLOCK(const SplitBlockAlgorithm& val);

  bool operator==(const BloomFilterAlgorithm& rhs) const {
    if (__isset.BLOCK != rhs.__isset.BLOCK)
      return false;
    else if (__isset.BLOCK && !(BLOCK == rhs.BLOCK))
      return false;
    return true;
  }
  bool operator!=(const BloomFilterAlgorithm& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const BloomFilterAlgorithm&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(BloomFilterAlgorithm& a, BloomFilterAlgorithm& b);

std::ostream& operator<<(std::ostream& out, const BloomFilterAlgorithm& obj);

/**
 * Hash strategy type annotation. xxHash is an extremely fast non-cryptographic
 * hash algorithm. It uses 64 bits version of xxHash.
 *
 */
class XxHash : public virtual ::apache::thrift::TBase {
 public:
  XxHash(const XxHash&);
  XxHash& operator=(const XxHash&);
  XxHash() {}

  virtual ~XxHash() noexcept;

  bool operator==(const XxHash& /* rhs */) const {
    return true;
  }
  bool operator!=(const XxHash& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const XxHash&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(XxHash& a, XxHash& b);

std::ostream& operator<<(std::ostream& out, const XxHash& obj);

typedef struct _BloomFilterHash__isset {
  _BloomFilterHash__isset() : XXHASH(false) {}
  bool XXHASH : 1;
} _BloomFilterHash__isset;

/**
 * The hash function used in Bloom filter. This function takes the hash of a
 * column value using plain encoding.
 *
 */
class BloomFilterHash : public virtual ::apache::thrift::TBase {
 public:
  BloomFilterHash(const BloomFilterHash&);
  BloomFilterHash& operator=(const BloomFilterHash&);
  BloomFilterHash() {}

  virtual ~BloomFilterHash() noexcept;
  /**
   * xxHash Strategy. *
   */
  XxHash XXHASH;

  _BloomFilterHash__isset __isset;

  void __set_XXHASH(const XxHash& val);

  bool operator==(const BloomFilterHash& rhs) const {
    if (__isset.XXHASH != rhs.__isset.XXHASH)
      return false;
    else if (__isset.XXHASH && !(XXHASH == rhs.XXHASH))
      return false;
    return true;
  }
  bool operator!=(const BloomFilterHash& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const BloomFilterHash&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(BloomFilterHash& a, BloomFilterHash& b);

std::ostream& operator<<(std::ostream& out, const BloomFilterHash& obj);

/**
 * The compression used in the Bloom filter.
 *
 */
class Uncompressed : public virtual ::apache::thrift::TBase {
 public:
  Uncompressed(const Uncompressed&);
  Uncompressed& operator=(const Uncompressed&);
  Uncompressed() {}

  virtual ~Uncompressed() noexcept;

  bool operator==(const Uncompressed& /* rhs */) const {
    return true;
  }
  bool operator!=(const Uncompressed& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const Uncompressed&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(Uncompressed& a, Uncompressed& b);

std::ostream& operator<<(std::ostream& out, const Uncompressed& obj);

typedef struct _BloomFilterCompression__isset {
  _BloomFilterCompression__isset() : UNCOMPRESSED(false) {}
  bool UNCOMPRESSED : 1;
} _BloomFilterCompression__isset;

class BloomFilterCompression : public virtual ::apache::thrift::TBase {
 public:
  BloomFilterCompression(const BloomFilterCompression&);
  BloomFilterCompression& operator=(const BloomFilterCompression&);
  BloomFilterCompression() {}

  virtual ~BloomFilterCompression() noexcept;
  Uncompressed UNCOMPRESSED;

  _BloomFilterCompression__isset __isset;

  void __set_UNCOMPRESSED(const Uncompressed& val);

  bool operator==(const BloomFilterCompression& rhs) const {
    if (__isset.UNCOMPRESSED != rhs.__isset.UNCOMPRESSED)
      return false;
    else if (__isset.UNCOMPRESSED && !(UNCOMPRESSED == rhs.UNCOMPRESSED))
      return false;
    return true;
  }
  bool operator!=(const BloomFilterCompression& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const BloomFilterCompression&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(BloomFilterCompression& a, BloomFilterCompression& b);

std::ostream& operator<<(std::ostream& out, const BloomFilterCompression& obj);

/**
 * Bloom filter header is stored at beginning of Bloom filter data of each
 * column and followed by its bitset.
 *
 */
class BloomFilterHeader : public virtual ::apache::thrift::TBase {
 public:
  BloomFilterHeader(const BloomFilterHeader&);
  BloomFilterHeader& operator=(const BloomFilterHeader&);
  BloomFilterHeader() : numBytes(0) {}

  virtual ~BloomFilterHeader() noexcept;
  /**
   * The size of bitset in bytes *
   */
  int32_t numBytes;
  /**
   * The algorithm for setting bits. *
   */
  BloomFilterAlgorithm algorithm;
  /**
   * The hash function used for Bloom filter. *
   */
  BloomFilterHash hash;
  /**
   * The compression used in the Bloom filter *
   */
  BloomFilterCompression compression;

  void __set_numBytes(const int32_t val);

  void __set_algorithm(const BloomFilterAlgorithm& val);

  void __set_hash(const BloomFilterHash& val);

  void __set_compression(const BloomFilterCompression& val);

  bool operator==(const BloomFilterHeader& rhs) const {
    if (!(numBytes == rhs.numBytes))
      return false;
    if (!(algorithm == rhs.algorithm))
      return false;
    if (!(hash == rhs.hash))
      return false;
    if (!(compression == rhs.compression))
      return false;
    return true;
  }
  bool operator!=(const BloomFilterHeader& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const BloomFilterHeader&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(BloomFilterHeader& a, BloomFilterHeader& b);

std::ostream& operator<<(std::ostream& out, const BloomFilterHeader& obj);

typedef struct _PageHeader__isset {
  _PageHeader__isset()
      : crc(false),
        data_page_header(false),
        index_page_header(false),
        dictionary_page_header(false),
        data_page_header_v2(false) {}
  bool crc : 1;
  bool data_page_header : 1;
  bool index_page_header : 1;
  bool dictionary_page_header : 1;
  bool data_page_header_v2 : 1;
} _PageHeader__isset;

class PageHeader : public virtual ::apache::thrift::TBase {
 public:
  PageHeader(const PageHeader&);
  PageHeader& operator=(const PageHeader&);
  PageHeader()
      : type((PageType::type)0),
        uncompressed_page_size(0),
        compressed_page_size(0),
        crc(0) {}

  virtual ~PageHeader() noexcept;
  /**
   * the type of the page: indicates which of the *_header fields is set *
   *
   * @see PageType
   */
  PageType::type type;
  /**
   * Uncompressed page size in bytes (not including this header) *
   */
  int32_t uncompressed_page_size;
  /**
   * Compressed (and potentially encrypted) page size in bytes, not including
   * this header *
   */
  int32_t compressed_page_size;
  /**
   * The 32bit CRC for the page, to be be calculated as follows:
   * - Using the standard CRC32 algorithm
   * - On the data only, i.e. this header should not be included. 'Data'
   *   hereby refers to the concatenation of the repetition levels, the
   *   definition levels and the column value, in this exact order.
   * - On the encoded versions of the repetition levels, definition levels and
   *   column values
   * - On the compressed versions of the repetition levels, definition levels
   *   and column values where possible;
   *   - For v1 data pages, the repetition levels, definition levels and column
   *     values are always compressed together. If a compression scheme is
   *     specified, the CRC shall be calculated on the compressed version of
   *     this concatenation. If no compression scheme is specified, the CRC
   *     shall be calculated on the uncompressed version of this concatenation.
   *   - For v2 data pages, the repetition levels and definition levels are
   *     handled separately from the data and are never compressed (only
   *     encoded). If a compression scheme is specified, the CRC shall be
   *     calculated on the concatenation of the uncompressed repetition levels,
   *     uncompressed definition levels and the compressed column values.
   *     If no compression scheme is specified, the CRC shall be calculated on
   *     the uncompressed concatenation.
   * - In encrypted columns, CRC is calculated after page encryption; the
   *   encryption itself is performed after page compression (if compressed)
   * If enabled, this allows for disabling checksumming in HDFS if only a few
   * pages need to be read.
   *
   */
  int32_t crc;
  DataPageHeader data_page_header;
  IndexPageHeader index_page_header;
  DictionaryPageHeader dictionary_page_header;
  DataPageHeaderV2 data_page_header_v2;

  _PageHeader__isset __isset;

  void __set_type(const PageType::type val);

  void __set_uncompressed_page_size(const int32_t val);

  void __set_compressed_page_size(const int32_t val);

  void __set_crc(const int32_t val);

  void __set_data_page_header(const DataPageHeader& val);

  void __set_index_page_header(const IndexPageHeader& val);

  void __set_dictionary_page_header(const DictionaryPageHeader& val);

  void __set_data_page_header_v2(const DataPageHeaderV2& val);

  bool operator==(const PageHeader& rhs) const {
    if (!(type == rhs.type))
      return false;
    if (!(uncompressed_page_size == rhs.uncompressed_page_size))
      return false;
    if (!(compressed_page_size == rhs.compressed_page_size))
      return false;
    if (__isset.crc != rhs.__isset.crc)
      return false;
    else if (__isset.crc && !(crc == rhs.crc))
      return false;
    if (__isset.data_page_header != rhs.__isset.data_page_header)
      return false;
    else if (
        __isset.data_page_header && !(data_page_header == rhs.data_page_header))
      return false;
    if (__isset.index_page_header != rhs.__isset.index_page_header)
      return false;
    else if (
        __isset.index_page_header &&
        !(index_page_header == rhs.index_page_header))
      return false;
    if (__isset.dictionary_page_header != rhs.__isset.dictionary_page_header)
      return false;
    else if (
        __isset.dictionary_page_header &&
        !(dictionary_page_header == rhs.dictionary_page_header))
      return false;
    if (__isset.data_page_header_v2 != rhs.__isset.data_page_header_v2)
      return false;
    else if (
        __isset.data_page_header_v2 &&
        !(data_page_header_v2 == rhs.data_page_header_v2))
      return false;
    return true;
  }
  bool operator!=(const PageHeader& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const PageHeader&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(PageHeader& a, PageHeader& b);

std::ostream& operator<<(std::ostream& out, const PageHeader& obj);

typedef struct _KeyValue__isset {
  _KeyValue__isset() : value(false) {}
  bool value : 1;
} _KeyValue__isset;

/**
 * Wrapper struct to store key values
 */
class KeyValue : public virtual ::apache::thrift::TBase {
 public:
  KeyValue(const KeyValue&);
  KeyValue& operator=(const KeyValue&);
  KeyValue() : key(), value() {}

  virtual ~KeyValue() noexcept;
  std::string key;
  std::string value;

  _KeyValue__isset __isset;

  void __set_key(const std::string& val);

  void __set_value(const std::string& val);

  bool operator==(const KeyValue& rhs) const {
    if (!(key == rhs.key))
      return false;
    if (__isset.value != rhs.__isset.value)
      return false;
    else if (__isset.value && !(value == rhs.value))
      return false;
    return true;
  }
  bool operator!=(const KeyValue& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const KeyValue&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(KeyValue& a, KeyValue& b);

std::ostream& operator<<(std::ostream& out, const KeyValue& obj);

/**
 * Wrapper struct to specify sort order
 */
class SortingColumn : public virtual ::apache::thrift::TBase {
 public:
  SortingColumn(const SortingColumn&);
  SortingColumn& operator=(const SortingColumn&);
  SortingColumn() : column_idx(0), descending(0), nulls_first(0) {}

  virtual ~SortingColumn() noexcept;
  /**
   * The column index (in this row group) *
   */
  int32_t column_idx;
  /**
   * If true, indicates this column is sorted in descending order. *
   */
  bool descending;
  /**
   * If true, nulls will come before non-null values, otherwise,
   * nulls go at the end.
   */
  bool nulls_first;

  void __set_column_idx(const int32_t val);

  void __set_descending(const bool val);

  void __set_nulls_first(const bool val);

  bool operator==(const SortingColumn& rhs) const {
    if (!(column_idx == rhs.column_idx))
      return false;
    if (!(descending == rhs.descending))
      return false;
    if (!(nulls_first == rhs.nulls_first))
      return false;
    return true;
  }
  bool operator!=(const SortingColumn& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const SortingColumn&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(SortingColumn& a, SortingColumn& b);

std::ostream& operator<<(std::ostream& out, const SortingColumn& obj);

/**
 * statistics of a given page type and encoding
 */
class PageEncodingStats : public virtual ::apache::thrift::TBase {
 public:
  PageEncodingStats(const PageEncodingStats&);
  PageEncodingStats& operator=(const PageEncodingStats&);
  PageEncodingStats()
      : page_type((PageType::type)0), encoding((Encoding::type)0), count(0) {}

  virtual ~PageEncodingStats() noexcept;
  /**
   * the page type (data/dic/...) *
   *
   * @see PageType
   */
  PageType::type page_type;
  /**
   * encoding of the page *
   *
   * @see Encoding
   */
  Encoding::type encoding;
  /**
   * number of pages of this type with this encoding *
   */
  int32_t count;

  void __set_page_type(const PageType::type val);

  void __set_encoding(const Encoding::type val);

  void __set_count(const int32_t val);

  bool operator==(const PageEncodingStats& rhs) const {
    if (!(page_type == rhs.page_type))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (!(count == rhs.count))
      return false;
    return true;
  }
  bool operator!=(const PageEncodingStats& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const PageEncodingStats&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(PageEncodingStats& a, PageEncodingStats& b);

std::ostream& operator<<(std::ostream& out, const PageEncodingStats& obj);

typedef struct _ColumnMetaData__isset {
  _ColumnMetaData__isset()
      : key_value_metadata(false),
        index_page_offset(false),
        dictionary_page_offset(false),
        statistics(false),
        encoding_stats(false),
        bloom_filter_offset(false) {}
  bool key_value_metadata : 1;
  bool index_page_offset : 1;
  bool dictionary_page_offset : 1;
  bool statistics : 1;
  bool encoding_stats : 1;
  bool bloom_filter_offset : 1;
} _ColumnMetaData__isset;

/**
 * Description for column metadata
 */
class ColumnMetaData : public virtual ::apache::thrift::TBase {
 public:
  ColumnMetaData(const ColumnMetaData&);
  ColumnMetaData& operator=(const ColumnMetaData&);
  ColumnMetaData()
      : type((Type::type)0),
        codec((CompressionCodec::type)0),
        num_values(0),
        total_uncompressed_size(0),
        total_compressed_size(0),
        data_page_offset(0),
        index_page_offset(0),
        dictionary_page_offset(0),
        bloom_filter_offset(0) {}

  virtual ~ColumnMetaData() noexcept;
  /**
   * Type of this column *
   *
   * @see Type
   */
  Type::type type;
  /**
   * Set of all encodings used for this column. The purpose is to validate
   * whether we can decode those pages. *
   */
  std::vector<Encoding::type> encodings;
  /**
   * Path in schema *
   */
  std::vector<std::string> path_in_schema;
  /**
   * Compression codec *
   *
   * @see CompressionCodec
   */
  CompressionCodec::type codec;
  /**
   * Number of values in this column *
   */
  int64_t num_values;
  /**
   * total byte size of all uncompressed pages in this column chunk (including
   * the headers) *
   */
  int64_t total_uncompressed_size;
  /**
   * total byte size of all compressed, and potentially encrypted, pages
   * in this column chunk (including the headers) *
   */
  int64_t total_compressed_size;
  /**
   * Optional key/value metadata *
   */
  std::vector<KeyValue> key_value_metadata;
  /**
   * Byte offset from beginning of file to first data page *
   */
  int64_t data_page_offset;
  /**
   * Byte offset from beginning of file to root index page *
   */
  int64_t index_page_offset;
  /**
   * Byte offset from the beginning of file to first (only) dictionary page *
   */
  int64_t dictionary_page_offset;
  /**
   * optional statistics for this column chunk
   */
  Statistics statistics;
  /**
   * Set of all encodings used for pages in this column chunk.
   * This information can be used to determine if all data pages are
   * dictionary encoded for example *
   */
  std::vector<PageEncodingStats> encoding_stats;
  /**
   * Byte offset from beginning of file to Bloom filter data. *
   */
  int64_t bloom_filter_offset;

  _ColumnMetaData__isset __isset;

  void __set_type(const Type::type val);

  void __set_encodings(const std::vector<Encoding::type>& val);

  void __set_path_in_schema(const std::vector<std::string>& val);

  void __set_codec(const CompressionCodec::type val);

  void __set_num_values(const int64_t val);

  void __set_total_uncompressed_size(const int64_t val);

  void __set_total_compressed_size(const int64_t val);

  void __set_key_value_metadata(const std::vector<KeyValue>& val);

  void __set_data_page_offset(const int64_t val);

  void __set_index_page_offset(const int64_t val);

  void __set_dictionary_page_offset(const int64_t val);

  void __set_statistics(const Statistics& val);

  void __set_encoding_stats(const std::vector<PageEncodingStats>& val);

  void __set_bloom_filter_offset(const int64_t val);

  bool operator==(const ColumnMetaData& rhs) const {
    if (!(type == rhs.type))
      return false;
    if (!(encodings == rhs.encodings))
      return false;
    if (!(path_in_schema == rhs.path_in_schema))
      return false;
    if (!(codec == rhs.codec))
      return false;
    if (!(num_values == rhs.num_values))
      return false;
    if (!(total_uncompressed_size == rhs.total_uncompressed_size))
      return false;
    if (!(total_compressed_size == rhs.total_compressed_size))
      return false;
    if (__isset.key_value_metadata != rhs.__isset.key_value_metadata)
      return false;
    else if (
        __isset.key_value_metadata &&
        !(key_value_metadata == rhs.key_value_metadata))
      return false;
    if (!(data_page_offset == rhs.data_page_offset))
      return false;
    if (__isset.index_page_offset != rhs.__isset.index_page_offset)
      return false;
    else if (
        __isset.index_page_offset &&
        !(index_page_offset == rhs.index_page_offset))
      return false;
    if (__isset.dictionary_page_offset != rhs.__isset.dictionary_page_offset)
      return false;
    else if (
        __isset.dictionary_page_offset &&
        !(dictionary_page_offset == rhs.dictionary_page_offset))
      return false;
    if (__isset.statistics != rhs.__isset.statistics)
      return false;
    else if (__isset.statistics && !(statistics == rhs.statistics))
      return false;
    if (__isset.encoding_stats != rhs.__isset.encoding_stats)
      return false;
    else if (__isset.encoding_stats && !(encoding_stats == rhs.encoding_stats))
      return false;
    if (__isset.bloom_filter_offset != rhs.__isset.bloom_filter_offset)
      return false;
    else if (
        __isset.bloom_filter_offset &&
        !(bloom_filter_offset == rhs.bloom_filter_offset))
      return false;
    return true;
  }
  bool operator!=(const ColumnMetaData& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const ColumnMetaData&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnMetaData& a, ColumnMetaData& b);

std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj);

class EncryptionWithFooterKey : public virtual ::apache::thrift::TBase {
 public:
  EncryptionWithFooterKey(const EncryptionWithFooterKey&);
  EncryptionWithFooterKey& operator=(const EncryptionWithFooterKey&);
  EncryptionWithFooterKey() {}

  virtual ~EncryptionWithFooterKey() noexcept;

  bool operator==(const EncryptionWithFooterKey& /* rhs */) const {
    return true;
  }
  bool operator!=(const EncryptionWithFooterKey& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const EncryptionWithFooterKey&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EncryptionWithFooterKey& a, EncryptionWithFooterKey& b);

std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj);

typedef struct _EncryptionWithColumnKey__isset {
  _EncryptionWithColumnKey__isset() : key_metadata(false) {}
  bool key_metadata : 1;
} _EncryptionWithColumnKey__isset;

class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase {
 public:
  EncryptionWithColumnKey(const EncryptionWithColumnKey&);
  EncryptionWithColumnKey& operator=(const EncryptionWithColumnKey&);
  EncryptionWithColumnKey() : key_metadata() {}

  virtual ~EncryptionWithColumnKey() noexcept;
  /**
   * Column path in schema *
   */
  std::vector<std::string> path_in_schema;
  /**
   * Retrieval metadata of column encryption key *
   */
  std::string key_metadata;

  _EncryptionWithColumnKey__isset __isset;

  void __set_path_in_schema(const std::vector<std::string>& val);

  void __set_key_metadata(const std::string& val);

  bool operator==(const EncryptionWithColumnKey& rhs) const {
    if (!(path_in_schema == rhs.path_in_schema))
      return false;
    if (__isset.key_metadata != rhs.__isset.key_metadata)
      return false;
    else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata))
      return false;
    return true;
  }
  bool operator!=(const EncryptionWithColumnKey& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const EncryptionWithColumnKey&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EncryptionWithColumnKey& a, EncryptionWithColumnKey& b);

std::ostream& operator<<(std::ostream& out, const EncryptionWithColumnKey& obj);

typedef struct _ColumnCryptoMetaData__isset {
  _ColumnCryptoMetaData__isset()
      : ENCRYPTION_WITH_FOOTER_KEY(false), ENCRYPTION_WITH_COLUMN_KEY(false) {}
  bool ENCRYPTION_WITH_FOOTER_KEY : 1;
  bool ENCRYPTION_WITH_COLUMN_KEY : 1;
} _ColumnCryptoMetaData__isset;

class ColumnCryptoMetaData : public virtual ::apache::thrift::TBase {
 public:
  ColumnCryptoMetaData(const ColumnCryptoMetaData&);
  ColumnCryptoMetaData& operator=(const ColumnCryptoMetaData&);
  ColumnCryptoMetaData() {}

  virtual ~ColumnCryptoMetaData() noexcept;
  EncryptionWithFooterKey ENCRYPTION_WITH_FOOTER_KEY;
  EncryptionWithColumnKey ENCRYPTION_WITH_COLUMN_KEY;

  _ColumnCryptoMetaData__isset __isset;

  void __set_ENCRYPTION_WITH_FOOTER_KEY(const EncryptionWithFooterKey& val);

  void __set_ENCRYPTION_WITH_COLUMN_KEY(const EncryptionWithColumnKey& val);

  bool operator==(const ColumnCryptoMetaData& rhs) const {
    if (__isset.ENCRYPTION_WITH_FOOTER_KEY !=
        rhs.__isset.ENCRYPTION_WITH_FOOTER_KEY)
      return false;
    else if (
        __isset.ENCRYPTION_WITH_FOOTER_KEY &&
        !(ENCRYPTION_WITH_FOOTER_KEY == rhs.ENCRYPTION_WITH_FOOTER_KEY))
      return false;
    if (__isset.ENCRYPTION_WITH_COLUMN_KEY !=
        rhs.__isset.ENCRYPTION_WITH_COLUMN_KEY)
      return false;
    else if (
        __isset.ENCRYPTION_WITH_COLUMN_KEY &&
        !(ENCRYPTION_WITH_COLUMN_KEY == rhs.ENCRYPTION_WITH_COLUMN_KEY))
      return false;
    return true;
  }
  bool operator!=(const ColumnCryptoMetaData& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const ColumnCryptoMetaData&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnCryptoMetaData& a, ColumnCryptoMetaData& b);

std::ostream& operator<<(std::ostream& out, const ColumnCryptoMetaData& obj);

typedef struct _ColumnChunk__isset {
  _ColumnChunk__isset()
      : file_path(false),
        meta_data(false),
        offset_index_offset(false),
        offset_index_length(false),
        column_index_offset(false),
        column_index_length(false),
        crypto_metadata(false),
        encrypted_column_metadata(false) {}
  bool file_path : 1;
  bool meta_data : 1;
  bool offset_index_offset : 1;
  bool offset_index_length : 1;
  bool column_index_offset : 1;
  bool column_index_length : 1;
  bool crypto_metadata : 1;
  bool encrypted_column_metadata : 1;
} _ColumnChunk__isset;

class ColumnChunk : public virtual ::apache::thrift::TBase {
 public:
  ColumnChunk(const ColumnChunk&);
  ColumnChunk& operator=(const ColumnChunk&);
  ColumnChunk()
      : file_path(),
        file_offset(0),
        offset_index_offset(0),
        offset_index_length(0),
        column_index_offset(0),
        column_index_length(0),
        encrypted_column_metadata() {}

  virtual ~ColumnChunk() noexcept;
  /**
   * File where column data is stored.  If not set, assumed to be same file as
   * metadata.  This path is relative to the current file.
   *
   */
  std::string file_path;
  /**
   * Byte offset in file_path to the ColumnMetaData *
   */
  int64_t file_offset;
  /**
   * Column metadata for this chunk. This is the same content as what is at
   * file_path/file_offset.  Having it here has it replicated in the file
   * metadata.
   *
   */
  ColumnMetaData meta_data;
  /**
   * File offset of ColumnChunk's OffsetIndex *
   */
  int64_t offset_index_offset;
  /**
   * Size of ColumnChunk's OffsetIndex, in bytes *
   */
  int32_t offset_index_length;
  /**
   * File offset of ColumnChunk's ColumnIndex *
   */
  int64_t column_index_offset;
  /**
   * Size of ColumnChunk's ColumnIndex, in bytes *
   */
  int32_t column_index_length;
  /**
   * Crypto metadata of encrypted columns *
   */
  ColumnCryptoMetaData crypto_metadata;
  /**
   * Encrypted column metadata for this chunk *
   */
  std::string encrypted_column_metadata;

  _ColumnChunk__isset __isset;

  void __set_file_path(const std::string& val);

  void __set_file_offset(const int64_t val);

  void __set_meta_data(const ColumnMetaData& val);

  void __set_offset_index_offset(const int64_t val);

  void __set_offset_index_length(const int32_t val);

  void __set_column_index_offset(const int64_t val);

  void __set_column_index_length(const int32_t val);

  void __set_crypto_metadata(const ColumnCryptoMetaData& val);

  void __set_encrypted_column_metadata(const std::string& val);

  bool operator==(const ColumnChunk& rhs) const {
    if (__isset.file_path != rhs.__isset.file_path)
      return false;
    else if (__isset.file_path && !(file_path == rhs.file_path))
      return false;
    if (!(file_offset == rhs.file_offset))
      return false;
    if (__isset.meta_data != rhs.__isset.meta_data)
      return false;
    else if (__isset.meta_data && !(meta_data == rhs.meta_data))
      return false;
    if (__isset.offset_index_offset != rhs.__isset.offset_index_offset)
      return false;
    else if (
        __isset.offset_index_offset &&
        !(offset_index_offset == rhs.offset_index_offset))
      return false;
    if (__isset.offset_index_length != rhs.__isset.offset_index_length)
      return false;
    else if (
        __isset.offset_index_length &&
        !(offset_index_length == rhs.offset_index_length))
      return false;
    if (__isset.column_index_offset != rhs.__isset.column_index_offset)
      return false;
    else if (
        __isset.column_index_offset &&
        !(column_index_offset == rhs.column_index_offset))
      return false;
    if (__isset.column_index_length != rhs.__isset.column_index_length)
      return false;
    else if (
        __isset.column_index_length &&
        !(column_index_length == rhs.column_index_length))
      return false;
    if (__isset.crypto_metadata != rhs.__isset.crypto_metadata)
      return false;
    else if (
        __isset.crypto_metadata && !(crypto_metadata == rhs.crypto_metadata))
      return false;
    if (__isset.encrypted_column_metadata !=
        rhs.__isset.encrypted_column_metadata)
      return false;
    else if (
        __isset.encrypted_column_metadata &&
        !(encrypted_column_metadata == rhs.encrypted_column_metadata))
      return false;
    return true;
  }
  bool operator!=(const ColumnChunk& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const ColumnChunk&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnChunk& a, ColumnChunk& b);

std::ostream& operator<<(std::ostream& out, const ColumnChunk& obj);

typedef struct _RowGroup__isset {
  _RowGroup__isset()
      : sorting_columns(false),
        file_offset(false),
        total_compressed_size(false),
        ordinal(false) {}
  bool sorting_columns : 1;
  bool file_offset : 1;
  bool total_compressed_size : 1;
  bool ordinal : 1;
} _RowGroup__isset;

class RowGroup : public virtual ::apache::thrift::TBase {
 public:
  RowGroup(const RowGroup&);
  RowGroup& operator=(const RowGroup&);
  RowGroup()
      : total_byte_size(0),
        num_rows(0),
        file_offset(0),
        total_compressed_size(0),
        ordinal(0) {}

  virtual ~RowGroup() noexcept;
  /**
   * Metadata for each column chunk in this row group.
   * This list must have the same order as the SchemaElement list in
   * FileMetaData.
   *
   */
  std::vector<ColumnChunk> columns;
  /**
   * Total byte size of all the uncompressed column data in this row group *
   */
  int64_t total_byte_size;
  /**
   * Number of rows in this row group *
   */
  int64_t num_rows;
  /**
   * If set, specifies a sort ordering of the rows in this RowGroup.
   * The sorting columns can be a subset of all the columns.
   */
  std::vector<SortingColumn> sorting_columns;
  /**
   * Byte offset from beginning of file to first page (data or dictionary)
   * in this row group *
   */
  int64_t file_offset;
  /**
   * Total byte size of all compressed (and potentially encrypted) column data
   * in this row group *
   */
  int64_t total_compressed_size;
  /**
   * Row group ordinal in the file *
   */
  int16_t ordinal;

  _RowGroup__isset __isset;

  void __set_columns(const std::vector<ColumnChunk>& val);

  void __set_total_byte_size(const int64_t val);

  void __set_num_rows(const int64_t val);

  void __set_sorting_columns(const std::vector<SortingColumn>& val);

  void __set_file_offset(const int64_t val);

  void __set_total_compressed_size(const int64_t val);

  void __set_ordinal(const int16_t val);

  bool operator==(const RowGroup& rhs) const {
    if (!(columns == rhs.columns))
      return false;
    if (!(total_byte_size == rhs.total_byte_size))
      return false;
    if (!(num_rows == rhs.num_rows))
      return false;
    if (__isset.sorting_columns != rhs.__isset.sorting_columns)
      return false;
    else if (
        __isset.sorting_columns && !(sorting_columns == rhs.sorting_columns))
      return false;
    if (__isset.file_offset != rhs.__isset.file_offset)
      return false;
    else if (__isset.file_offset && !(file_offset == rhs.file_offset))
      return false;
    if (__isset.total_compressed_size != rhs.__isset.total_compressed_size)
      return false;
    else if (
        __isset.total_compressed_size &&
        !(total_compressed_size == rhs.total_compressed_size))
      return false;
    if (__isset.ordinal != rhs.__isset.ordinal)
      return false;
    else if (__isset.ordinal && !(ordinal == rhs.ordinal))
      return false;
    return true;
  }
  bool operator!=(const RowGroup& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const RowGroup&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(RowGroup& a, RowGroup& b);

std::ostream& operator<<(std::ostream& out, const RowGroup& obj);

/**
 * Empty struct to signal the order defined by the physical or logical type
 */
class TypeDefinedOrder : public virtual ::apache::thrift::TBase {
 public:
  TypeDefinedOrder(const TypeDefinedOrder&);
  TypeDefinedOrder& operator=(const TypeDefinedOrder&);
  TypeDefinedOrder() {}

  virtual ~TypeDefinedOrder() noexcept;

  bool operator==(const TypeDefinedOrder& /* rhs */) const {
    return true;
  }
  bool operator!=(const TypeDefinedOrder& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const TypeDefinedOrder&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TypeDefinedOrder& a, TypeDefinedOrder& b);

std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj);

typedef struct _ColumnOrder__isset {
  _ColumnOrder__isset() : TYPE_ORDER(false) {}
  bool TYPE_ORDER : 1;
} _ColumnOrder__isset;

/**
 * Union to specify the order used for the min_value and max_value fields for a
 * column. This union takes the role of an enhanced enum that allows rich
 * elements (which will be needed for a collation-based ordering in the future).
 *
 * Possible values are:
 * * TypeDefinedOrder - the column uses the order defined by its logical or
 *                      physical type (if there is no logical type).
 *
 * If the reader does not support the value of this union, min and max stats
 * for this column should be ignored.
 */
class ColumnOrder : public virtual ::apache::thrift::TBase {
 public:
  ColumnOrder(const ColumnOrder&);
  ColumnOrder& operator=(const ColumnOrder&);
  ColumnOrder() {}

  virtual ~ColumnOrder() noexcept;
  /**
   * The sort orders for logical types are:
   *   UTF8 - unsigned byte-wise comparison
   *   INT8 - signed comparison
   *   INT16 - signed comparison
   *   INT32 - signed comparison
   *   INT64 - signed comparison
   *   UINT8 - unsigned comparison
   *   UINT16 - unsigned comparison
   *   UINT32 - unsigned comparison
   *   UINT64 - unsigned comparison
   *   DECIMAL - signed comparison of the represented value
   *   DATE - signed comparison
   *   TIME_MILLIS - signed comparison
   *   TIME_MICROS - signed comparison
   *   TIMESTAMP_MILLIS - signed comparison
   *   TIMESTAMP_MICROS - signed comparison
   *   INTERVAL - unsigned comparison
   *   JSON - unsigned byte-wise comparison
   *   BSON - unsigned byte-wise comparison
   *   ENUM - unsigned byte-wise comparison
   *   LIST - undefined
   *   MAP - undefined
   *
   * In the absence of logical types, the sort order is determined by the
   * physical type: BOOLEAN - false, true INT32 - signed comparison INT64 -
   * signed comparison INT96 (only used for legacy timestamps) - undefined FLOAT
   * - signed comparison of the represented value (*) DOUBLE - signed comparison
   * of the represented value (*) BYTE_ARRAY - unsigned byte-wise comparison
   *   FIXED_LEN_BYTE_ARRAY - unsigned byte-wise comparison
   *
   * (*) Because the sorting order is not specified properly for floating
   *     point values (relations vs. total ordering) the following
   *     compatibility rules should be applied when reading statistics:
   *     - If the min is a NaN, it should be ignored.
   *     - If the max is a NaN, it should be ignored.
   *     - If the min is +0, the row group may contain -0 values as well.
   *     - If the max is -0, the row group may contain +0 values as well.
   *     - When looking for NaN values, min and max should be ignored.
   */
  TypeDefinedOrder TYPE_ORDER;

  _ColumnOrder__isset __isset;

  void __set_TYPE_ORDER(const TypeDefinedOrder& val);

  bool operator==(const ColumnOrder& rhs) const {
    if (__isset.TYPE_ORDER != rhs.__isset.TYPE_ORDER)
      return false;
    else if (__isset.TYPE_ORDER && !(TYPE_ORDER == rhs.TYPE_ORDER))
      return false;
    return true;
  }
  bool operator!=(const ColumnOrder& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const ColumnOrder&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnOrder& a, ColumnOrder& b);

std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj);

class PageLocation : public virtual ::apache::thrift::TBase {
 public:
  PageLocation(const PageLocation&);
  PageLocation& operator=(const PageLocation&);
  PageLocation() : offset(0), compressed_page_size(0), first_row_index(0) {}

  virtual ~PageLocation() noexcept;
  /**
   * Offset of the page in the file *
   */
  int64_t offset;
  /**
   * Size of the page, including header. Sum of compressed_page_size and header
   * length
   */
  int32_t compressed_page_size;
  /**
   * Index within the RowGroup of the first row of the page; this means pages
   * change on record boundaries (r = 0).
   */
  int64_t first_row_index;

  void __set_offset(const int64_t val);

  void __set_compressed_page_size(const int32_t val);

  void __set_first_row_index(const int64_t val);

  bool operator==(const PageLocation& rhs) const {
    if (!(offset == rhs.offset))
      return false;
    if (!(compressed_page_size == rhs.compressed_page_size))
      return false;
    if (!(first_row_index == rhs.first_row_index))
      return false;
    return true;
  }
  bool operator!=(const PageLocation& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const PageLocation&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(PageLocation& a, PageLocation& b);

std::ostream& operator<<(std::ostream& out, const PageLocation& obj);

class OffsetIndex : public virtual ::apache::thrift::TBase {
 public:
  OffsetIndex(const OffsetIndex&);
  OffsetIndex& operator=(const OffsetIndex&);
  OffsetIndex() {}

  virtual ~OffsetIndex() noexcept;
  /**
   * PageLocations, ordered by increasing PageLocation.offset. It is required
   * that page_locations[i].first_row_index <
   * page_locations[i+1].first_row_index.
   */
  std::vector<PageLocation> page_locations;

  void __set_page_locations(const std::vector<PageLocation>& val);

  bool operator==(const OffsetIndex& rhs) const {
    if (!(page_locations == rhs.page_locations))
      return false;
    return true;
  }
  bool operator!=(const OffsetIndex& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const OffsetIndex&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(OffsetIndex& a, OffsetIndex& b);

std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj);

typedef struct _ColumnIndex__isset {
  _ColumnIndex__isset() : null_counts(false) {}
  bool null_counts : 1;
} _ColumnIndex__isset;

/**
 * Description for ColumnIndex.
 * Each <array-field>[i] refers to the page at OffsetIndex.page_locations[i]
 */
class ColumnIndex : public virtual ::apache::thrift::TBase {
 public:
  ColumnIndex(const ColumnIndex&);
  ColumnIndex& operator=(const ColumnIndex&);
  ColumnIndex() : boundary_order((BoundaryOrder::type)0) {}

  virtual ~ColumnIndex() noexcept;
  /**
   * A list of Boolean values to determine the validity of the corresponding
   * min and max values. If true, a page contains only null values, and writers
   * have to set the corresponding entries in min_values and max_values to
   * byte[0], so that all lists have the same length. If false, the
   * corresponding entries in min_values and max_values must be valid.
   */
  std::vector<bool> null_pages;
  /**
   * Two lists containing lower and upper bounds for the values of each page
   * determined by the ColumnOrder of the column. These may be the actual
   * minimum and maximum values found on a page, but can also be (more compact)
   * values that do not exist on a page. For example, instead of storing ""Blart
   * Versenwald III", a writer may set min_values[i]="B", max_values[i]="C".
   * Such more compact values must still be valid values within the column's
   * logical type. Readers must make sure that list entries are populated before
   * using them by inspecting null_pages.
   */
  std::vector<std::string> min_values;
  std::vector<std::string> max_values;
  /**
   * Stores whether both min_values and max_values are orderd and if so, in
   * which direction. This allows readers to perform binary searches in both
   * lists. Readers cannot assume that max_values[i] <= min_values[i+1], even
   * if the lists are ordered.
   *
   * @see BoundaryOrder
   */
  BoundaryOrder::type boundary_order;
  /**
   * A list containing the number of null values for each page *
   */
  std::vector<int64_t> null_counts;

  _ColumnIndex__isset __isset;

  void __set_null_pages(const std::vector<bool>& val);

  void __set_min_values(const std::vector<std::string>& val);

  void __set_max_values(const std::vector<std::string>& val);

  void __set_boundary_order(const BoundaryOrder::type val);

  void __set_null_counts(const std::vector<int64_t>& val);

  bool operator==(const ColumnIndex& rhs) const {
    if (!(null_pages == rhs.null_pages))
      return false;
    if (!(min_values == rhs.min_values))
      return false;
    if (!(max_values == rhs.max_values))
      return false;
    if (!(boundary_order == rhs.boundary_order))
      return false;
    if (__isset.null_counts != rhs.__isset.null_counts)
      return false;
    else if (__isset.null_counts && !(null_counts == rhs.null_counts))
      return false;
    return true;
  }
  bool operator!=(const ColumnIndex& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const ColumnIndex&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnIndex& a, ColumnIndex& b);

std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj);

typedef struct _AesGcmV1__isset {
  _AesGcmV1__isset()
      : aad_prefix(false), aad_file_unique(false), supply_aad_prefix(false) {}
  bool aad_prefix : 1;
  bool aad_file_unique : 1;
  bool supply_aad_prefix : 1;
} _AesGcmV1__isset;

class AesGcmV1 : public virtual ::apache::thrift::TBase {
 public:
  AesGcmV1(const AesGcmV1&);
  AesGcmV1& operator=(const AesGcmV1&);
  AesGcmV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) {}

  virtual ~AesGcmV1() noexcept;
  /**
   * AAD prefix *
   */
  std::string aad_prefix;
  /**
   * Unique file identifier part of AAD suffix *
   */
  std::string aad_file_unique;
  /**
   * In files encrypted with AAD prefix without storing it,
   * readers must supply the prefix *
   */
  bool supply_aad_prefix;

  _AesGcmV1__isset __isset;

  void __set_aad_prefix(const std::string& val);

  void __set_aad_file_unique(const std::string& val);

  void __set_supply_aad_prefix(const bool val);

  bool operator==(const AesGcmV1& rhs) const {
    if (__isset.aad_prefix != rhs.__isset.aad_prefix)
      return false;
    else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix))
      return false;
    if (__isset.aad_file_unique != rhs.__isset.aad_file_unique)
      return false;
    else if (
        __isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique))
      return false;
    if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix)
      return false;
    else if (
        __isset.supply_aad_prefix &&
        !(supply_aad_prefix == rhs.supply_aad_prefix))
      return false;
    return true;
  }
  bool operator!=(const AesGcmV1& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const AesGcmV1&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(AesGcmV1& a, AesGcmV1& b);

std::ostream& operator<<(std::ostream& out, const AesGcmV1& obj);

typedef struct _AesGcmCtrV1__isset {
  _AesGcmCtrV1__isset()
      : aad_prefix(false), aad_file_unique(false), supply_aad_prefix(false) {}
  bool aad_prefix : 1;
  bool aad_file_unique : 1;
  bool supply_aad_prefix : 1;
} _AesGcmCtrV1__isset;

class AesGcmCtrV1 : public virtual ::apache::thrift::TBase {
 public:
  AesGcmCtrV1(const AesGcmCtrV1&);
  AesGcmCtrV1& operator=(const AesGcmCtrV1&);
  AesGcmCtrV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) {}

  virtual ~AesGcmCtrV1() noexcept;
  /**
   * AAD prefix *
   */
  std::string aad_prefix;
  /**
   * Unique file identifier part of AAD suffix *
   */
  std::string aad_file_unique;
  /**
   * In files encrypted with AAD prefix without storing it,
   * readers must supply the prefix *
   */
  bool supply_aad_prefix;

  _AesGcmCtrV1__isset __isset;

  void __set_aad_prefix(const std::string& val);

  void __set_aad_file_unique(const std::string& val);

  void __set_supply_aad_prefix(const bool val);

  bool operator==(const AesGcmCtrV1& rhs) const {
    if (__isset.aad_prefix != rhs.__isset.aad_prefix)
      return false;
    else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix))
      return false;
    if (__isset.aad_file_unique != rhs.__isset.aad_file_unique)
      return false;
    else if (
        __isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique))
      return false;
    if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix)
      return false;
    else if (
        __isset.supply_aad_prefix &&
        !(supply_aad_prefix == rhs.supply_aad_prefix))
      return false;
    return true;
  }
  bool operator!=(const AesGcmCtrV1& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const AesGcmCtrV1&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(AesGcmCtrV1& a, AesGcmCtrV1& b);

std::ostream& operator<<(std::ostream& out, const AesGcmCtrV1& obj);

typedef struct _EncryptionAlgorithm__isset {
  _EncryptionAlgorithm__isset() : AES_GCM_V1(false), AES_GCM_CTR_V1(false) {}
  bool AES_GCM_V1 : 1;
  bool AES_GCM_CTR_V1 : 1;
} _EncryptionAlgorithm__isset;

class EncryptionAlgorithm : public virtual ::apache::thrift::TBase {
 public:
  EncryptionAlgorithm(const EncryptionAlgorithm&);
  EncryptionAlgorithm& operator=(const EncryptionAlgorithm&);
  EncryptionAlgorithm() {}

  virtual ~EncryptionAlgorithm() noexcept;
  AesGcmV1 AES_GCM_V1;
  AesGcmCtrV1 AES_GCM_CTR_V1;

  _EncryptionAlgorithm__isset __isset;

  void __set_AES_GCM_V1(const AesGcmV1& val);

  void __set_AES_GCM_CTR_V1(const AesGcmCtrV1& val);

  bool operator==(const EncryptionAlgorithm& rhs) const {
    if (__isset.AES_GCM_V1 != rhs.__isset.AES_GCM_V1)
      return false;
    else if (__isset.AES_GCM_V1 && !(AES_GCM_V1 == rhs.AES_GCM_V1))
      return false;
    if (__isset.AES_GCM_CTR_V1 != rhs.__isset.AES_GCM_CTR_V1)
      return false;
    else if (__isset.AES_GCM_CTR_V1 && !(AES_GCM_CTR_V1 == rhs.AES_GCM_CTR_V1))
      return false;
    return true;
  }
  bool operator!=(const EncryptionAlgorithm& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const EncryptionAlgorithm&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EncryptionAlgorithm& a, EncryptionAlgorithm& b);

std::ostream& operator<<(std::ostream& out, const EncryptionAlgorithm& obj);

typedef struct _FileMetaData__isset {
  _FileMetaData__isset()
      : key_value_metadata(false),
        created_by(false),
        column_orders(false),
        encryption_algorithm(false),
        footer_signing_key_metadata(false) {}
  bool key_value_metadata : 1;
  bool created_by : 1;
  bool column_orders : 1;
  bool encryption_algorithm : 1;
  bool footer_signing_key_metadata : 1;
} _FileMetaData__isset;

/**
 * Description for file metadata
 */
class FileMetaData : public virtual ::apache::thrift::TBase {
 public:
  FileMetaData(const FileMetaData&);
  FileMetaData& operator=(const FileMetaData&);
  FileMetaData()
      : version(0), num_rows(0), created_by(), footer_signing_key_metadata() {}

  virtual ~FileMetaData() noexcept;
  /**
   * Version of this file *
   */
  int32_t version;
  /**
   * Parquet schema for this file.  This schema contains metadata for all the
   * columns. The schema is represented as a tree with a single root.  The nodes
   * of the tree are flattened to a list by doing a depth-first traversal. The
   * column metadata contains the path in the schema for that column which can
   * be used to map columns to nodes in the schema. The first element is the
   * root *
   */
  std::vector<SchemaElement> schema;
  /**
   * Number of rows in this file *
   */
  int64_t num_rows;
  /**
   * Row groups in this file *
   */
  std::vector<RowGroup> row_groups;
  /**
   * Optional key/value metadata *
   */
  std::vector<KeyValue> key_value_metadata;
  /**
   * String for application that wrote this file.  This should be in the format
   * <Application> version <App Version> (build <App Build Hash>).
   * e.g. impala version 1.0 (build 6cf94d29b2b7115df4de2c06e2ab4326d721eb55)
   *
   */
  std::string created_by;
  /**
   * Sort order used for the min_value and max_value fields in the Statistics
   * objects and the min_values and max_values fields in the ColumnIndex
   * objects of each column in this file. Sort orders are listed in the order
   * matching the columns in the schema. The indexes are not necessary the same
   * though, because only leaf nodes of the schema are represented in the list
   * of sort orders.
   *
   * Without column_orders, the meaning of the min_value and max_value fields
   * in the Statistics object and the ColumnIndex object is undefined. To ensure
   * well-defined behaviour, if these fields are written to a Parquet file,
   * column_orders must be written as well.
   *
   * The obsolete min and max fields in the Statistics object are always sorted
   * by signed comparison regardless of column_orders.
   */
  std::vector<ColumnOrder> column_orders;
  /**
   * Encryption algorithm. This field is set only in encrypted files
   * with plaintext footer. Files with encrypted footer store algorithm id
   * in FileCryptoMetaData structure.
   */
  EncryptionAlgorithm encryption_algorithm;
  /**
   * Retrieval metadata of key used for signing the footer.
   * Used only in encrypted files with plaintext footer.
   */
  std::string footer_signing_key_metadata;

  _FileMetaData__isset __isset;

  void __set_version(const int32_t val);

  void __set_schema(const std::vector<SchemaElement>& val);

  void __set_num_rows(const int64_t val);

  void __set_row_groups(const std::vector<RowGroup>& val);

  void __set_key_value_metadata(const std::vector<KeyValue>& val);

  void __set_created_by(const std::string& val);

  void __set_column_orders(const std::vector<ColumnOrder>& val);

  void __set_encryption_algorithm(const EncryptionAlgorithm& val);

  void __set_footer_signing_key_metadata(const std::string& val);

  bool operator==(const FileMetaData& rhs) const {
    if (!(version == rhs.version))
      return false;
    if (!(schema == rhs.schema))
      return false;
    if (!(num_rows == rhs.num_rows))
      return false;
    if (!(row_groups == rhs.row_groups))
      return false;
    if (__isset.key_value_metadata != rhs.__isset.key_value_metadata)
      return false;
    else if (
        __isset.key_value_metadata &&
        !(key_value_metadata == rhs.key_value_metadata))
      return false;
    if (__isset.created_by != rhs.__isset.created_by)
      return false;
    else if (__isset.created_by && !(created_by == rhs.created_by))
      return false;
    if (__isset.column_orders != rhs.__isset.column_orders)
      return false;
    else if (__isset.column_orders && !(column_orders == rhs.column_orders))
      return false;
    if (__isset.encryption_algorithm != rhs.__isset.encryption_algorithm)
      return false;
    else if (
        __isset.encryption_algorithm &&
        !(encryption_algorithm == rhs.encryption_algorithm))
      return false;
    if (__isset.footer_signing_key_metadata !=
        rhs.__isset.footer_signing_key_metadata)
      return false;
    else if (
        __isset.footer_signing_key_metadata &&
        !(footer_signing_key_metadata == rhs.footer_signing_key_metadata))
      return false;
    return true;
  }
  bool operator!=(const FileMetaData& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const FileMetaData&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(FileMetaData& a, FileMetaData& b);

std::ostream& operator<<(std::ostream& out, const FileMetaData& obj);

typedef struct _FileCryptoMetaData__isset {
  _FileCryptoMetaData__isset() : key_metadata(false) {}
  bool key_metadata : 1;
} _FileCryptoMetaData__isset;

/**
 * Crypto metadata for files with encrypted footer *
 */
class FileCryptoMetaData : public virtual ::apache::thrift::TBase {
 public:
  FileCryptoMetaData(const FileCryptoMetaData&);
  FileCryptoMetaData& operator=(const FileCryptoMetaData&);
  FileCryptoMetaData() : key_metadata() {}

  virtual ~FileCryptoMetaData() noexcept;
  /**
   * Encryption algorithm. This field is only used for files
   * with encrypted footer. Files with plaintext footer store algorithm id
   * inside footer (FileMetaData structure).
   */
  EncryptionAlgorithm encryption_algorithm;
  /**
   * Retrieval metadata of key used for encryption of footer,
   * and (possibly) columns *
   */
  std::string key_metadata;

  _FileCryptoMetaData__isset __isset;

  void __set_encryption_algorithm(const EncryptionAlgorithm& val);

  void __set_key_metadata(const std::string& val);

  bool operator==(const FileCryptoMetaData& rhs) const {
    if (!(encryption_algorithm == rhs.encryption_algorithm))
      return false;
    if (__isset.key_metadata != rhs.__isset.key_metadata)
      return false;
    else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata))
      return false;
    return true;
  }
  bool operator!=(const FileCryptoMetaData& rhs) const {
    return !(*this == rhs);
  }

  bool operator<(const FileCryptoMetaData&) const;

  uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(FileCryptoMetaData& a, FileCryptoMetaData& b);

std::ostream& operator<<(std::ostream& out, const FileCryptoMetaData& obj);

} // namespace facebook::velox::parquet::thrift

template <>
struct fmt::formatter<facebook::velox::parquet::thrift::Type::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::Type::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};

template <>
struct fmt::formatter<facebook::velox::parquet::thrift::CompressionCodec::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::CompressionCodec::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};

template <>
struct fmt::formatter<facebook::velox::parquet::thrift::ConvertedType::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::ConvertedType::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};

template <>
struct fmt::formatter<
    facebook::velox::parquet::thrift::FieldRepetitionType::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::FieldRepetitionType::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};

template <>
struct fmt::formatter<facebook::velox::parquet::thrift::Encoding::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::Encoding::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};

template <>
struct fmt::formatter<facebook::velox::parquet::thrift::PageType::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::PageType::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};

template <>
struct fmt::formatter<facebook::velox::parquet::thrift::BoundaryOrder::type>
    : fmt::formatter<std::string_view> {
  auto format(
      const facebook::velox::parquet::thrift::BoundaryOrder::type& s,
      format_context& ctx) const {
    return formatter<std::string_view>::format(
        facebook::velox::parquet::thrift::to_string(s), ctx);
  }
};
