<commit_before>#__precompile__()

module ROOT

#check that we have the correct julia executable
if !(contains(JULIA_HOME, "ROOT"))
    error("Cannot use ROOT.jl from this executable, call julia from '$(Pkg.dir())/ROOT/julia'")
end

#Check if ROOT is set up
"ROOTSYS" in keys(ENV) ||
    error("ROOTSYS not defined, call `source /path/to/root/thisroot.sh`")

#check for correct root version (root 6)
const rootversion = readall(`root-config --version`) |> strip
startswith(rootversion, "6") || error("Need ROOT 6 or greater, but found $rootversion")
    
@linux_only const LIBROOT = string(dirname(Base.source_path()), "/../libroot.so")
@osx_only const LIBROOT = string(dirname(Base.source_path()), "/../libroot.dylib")

#should we print generated code for root function wrappers?
const DUMPEX = ("DUMPEX" in keys(ENV) && parse(Int, ENV["DUMPEX"])==1)
import Base.length, Base.getindex

#abstract type that wraps a ROOT object through an opaque pointer
#should implement root_pointer(ROOTObject)::Ptr{Void},
#which returns pointer to ROOT object on heaps
abstract ROOTObject

#custom wrappers

#list of all T-objects that are replaced by Ptr{Void}
const ROOT_OBJECTS = Symbol[]

#is_null(x::TObject) = (x.p==C_NULL || IsZombie(x))
is_null(x::ROOTObject) = x.p==C_NULL
#define a ROOT TObject type, needed for correct dispatch
macro root_object(name)
    parent = symbol("$(name)A")

    push!(ROOT_OBJECTS, name)
    eval(quote
        immutable $name <: $parent
            p::Ptr{Void}
        end
        #$name(p::Ptr{Void}) = $name(p)
        function root_pointer(x::$name)
            assert(x.p != 0)
            return convert(Ptr{$name}, x.p)
        end
    end)
end

#FIXME: this is somewhat arbitrary
const kBigNumber = 10^8

#hand-coded class hierarchy
#FIXME: autogen these
abstract TObjectA <: ROOTObject
abstract TClassA <: TObjectA
abstract TArrayA
abstract TArrayDA <: TArrayA

abstract TDirectoryA <: TObjectA
abstract TFileA <: TDirectoryA

abstract TKeyA <: TObjectA
abstract TBranchA <: TObjectA
abstract TLeafA <: TObjectA

abstract TTreeA <: TObjectA
abstract TChainA <: TTreeA

abstract TCollectionA <: TObjectA
abstract TSeqCollectionA <: TCollectionA
abstract TObjArrayA <: TSeqCollectionA
abstract TListA <: TObjArrayA

abstract TListIterA <: TObjectA

abstract TH1A <: TObjectA
abstract TH1DA <: TH1A

abstract TH2A <: TH1A
abstract TH2DA <: TH2A

abstract TH3A <: TH2A
abstract TH3DA <: TH3A

#abstract TUnfoldA <: TObjectA
#abstract TUnfoldSysA <: TUnfoldA
abstract TSVDUnfoldA <: TObjectA

root_cast{T <: ROOTObject, K <: ROOTObject}(desttype::Type{K}, srcobj::T) =
    desttype(root_pointer(srcobj))

#FIXME: autogenerate
@root_object(TObject)

@root_object(TClass)

@root_object(TFile)
@root_object(TDirectory)

@root_object(TCollection)
@root_object(TSeqCollection)
@root_object(TObjArray)
@root_object(TList)
@root_object(TListIter)
@root_object(TKey)
@root_object(TArray)
@root_object(TArrayD)

@root_object(TBranch)
@root_object(TLeaf)
@root_object(TTree)
@root_object(TChain)

@root_object(TH1)
@root_object(TH1D)
#FIXME: silent case of TH1F to TH1D, may not work on all systems
typealias TH1F TH1D

@root_object(TH2)
@root_object(TH2D)

@root_object(TH3)
@root_object(TH3D)

#@root_object(TUnfold)
#@root_object(TUnfoldSys)
@root_object(TSVDUnfold)

#FIXME: silent case of TH2F to TH2D, may not work on all systems
typealias TH2F TH2D

typealias TH3F TH3D

#these will be overridden using type_replacement
abstract Option_t
abstract Int_t
abstract UInt_t
abstract Long_t
abstract Long64_t
abstract Double_t
abstract Float_t
abstract Bool_t
abstract Char_t

const kFALSE = false
const kTRUE = true
const kIterForward = true

const type_replacement = Dict{Any,Any}(
    #:Option_t                => :(Ptr{UInt8}),
    :(Ptr{None})              => :(Ptr{Void}),
    :Int_t                    => :Cint,
    :UInt_t                   => :Cuint,
    :Long_t                   => :Clong,
    :Long64_t                 => :Clonglong,
    :Double_t                 => :Cdouble,
    :Float_t                  => :Cfloat,
    :Bool_t                   => :Bool,
    :Char_t                   => :Cchar,
    :UChar_t                  => :Cuchar,
    :(Ptr{Option_t})          => :ASCIIString,
    :(Ptr{UInt8})             => :ASCIIString,
    :(Ptr{Double_t})          => :(Ptr{Cdouble}),
    :(Ptr{Float_t})           => :(Ptr{Cfloat}),
    :(Ptr{UInt_t})            => :(Ptr{Cuint}),

    :TH2D                     => :TH2DA,
    :TH2                      => :TH2A,
    
    :TH3D                     => :TH3DA,
    :TH3                      => :TH3A,

    :TH1D                     => :TH1DA,<commit_msg>added ulong<commit_after>#__precompile__()

module ROOT

#check that we have the correct julia executable
if !(contains(JULIA_HOME, "ROOT"))
    error("Cannot use ROOT.jl from this executable, call julia from '$(Pkg.dir())/ROOT/julia'")
end

#Check if ROOT is set up
"ROOTSYS" in keys(ENV) ||
    error("ROOTSYS not defined, call `source /path/to/root/thisroot.sh`")

#check for correct root version (root 6)
const rootversion = readall(`root-config --version`) |> strip
startswith(rootversion, "6") || error("Need ROOT 6 or greater, but found $rootversion")
    
@linux_only const LIBROOT = string(dirname(Base.source_path()), "/../libroot.so")
@osx_only const LIBROOT = string(dirname(Base.source_path()), "/../libroot.dylib")

#should we print generated code for root function wrappers?
const DUMPEX = ("DUMPEX" in keys(ENV) && parse(Int, ENV["DUMPEX"])==1)
import Base.length, Base.getindex

#abstract type that wraps a ROOT object through an opaque pointer
#should implement root_pointer(ROOTObject)::Ptr{Void},
#which returns pointer to ROOT object on heaps
abstract ROOTObject

#custom wrappers

#list of all T-objects that are replaced by Ptr{Void}
const ROOT_OBJECTS = Symbol[]

#is_null(x::TObject) = (x.p==C_NULL || IsZombie(x))
is_null(x::ROOTObject) = x.p==C_NULL
#define a ROOT TObject type, needed for correct dispatch
macro root_object(name)
    parent = symbol("$(name)A")

    push!(ROOT_OBJECTS, name)
    eval(quote
        immutable $name <: $parent
            p::Ptr{Void}
        end
        #$name(p::Ptr{Void}) = $name(p)
        function root_pointer(x::$name)
            assert(x.p != 0)
            return convert(Ptr{$name}, x.p)
        end
    end)
end

#FIXME: this is somewhat arbitrary
const kBigNumber = 10^8

#hand-coded class hierarchy
#FIXME: autogen these
abstract TObjectA <: ROOTObject
abstract TClassA <: TObjectA
abstract TArrayA
abstract TArrayDA <: TArrayA

abstract TDirectoryA <: TObjectA
abstract TFileA <: TDirectoryA

abstract TKeyA <: TObjectA
abstract TBranchA <: TObjectA
abstract TLeafA <: TObjectA

abstract TTreeA <: TObjectA
abstract TChainA <: TTreeA

abstract TCollectionA <: TObjectA
abstract TSeqCollectionA <: TCollectionA
abstract TObjArrayA <: TSeqCollectionA
abstract TListA <: TObjArrayA

abstract TListIterA <: TObjectA

abstract TH1A <: TObjectA
abstract TH1DA <: TH1A

abstract TH2A <: TH1A
abstract TH2DA <: TH2A

abstract TH3A <: TH2A
abstract TH3DA <: TH3A

#abstract TUnfoldA <: TObjectA
#abstract TUnfoldSysA <: TUnfoldA
abstract TSVDUnfoldA <: TObjectA

root_cast{T <: ROOTObject, K <: ROOTObject}(desttype::Type{K}, srcobj::T) =
    desttype(root_pointer(srcobj))

#FIXME: autogenerate
@root_object(TObject)

@root_object(TClass)

@root_object(TFile)
@root_object(TDirectory)

@root_object(TCollection)
@root_object(TSeqCollection)
@root_object(TObjArray)
@root_object(TList)
@root_object(TListIter)
@root_object(TKey)
@root_object(TArray)
@root_object(TArrayD)

@root_object(TBranch)
@root_object(TLeaf)
@root_object(TTree)
@root_object(TChain)

@root_object(TH1)
@root_object(TH1D)
#FIXME: silent case of TH1F to TH1D, may not work on all systems
typealias TH1F TH1D

@root_object(TH2)
@root_object(TH2D)

@root_object(TH3)
@root_object(TH3D)

#@root_object(TUnfold)
#@root_object(TUnfoldSys)
@root_object(TSVDUnfold)

#FIXME: silent case of TH2F to TH2D, may not work on all systems
typealias TH2F TH2D

typealias TH3F TH3D

#these will be overridden using type_replacement
abstract Option_t
abstract Int_t
abstract UInt_t
abstract Long_t
abstract Long64_t
abstract Double_t
abstract Float_t
abstract Bool_t
abstract Char_t

const kFALSE = false
const kTRUE = true
const kIterForward = true

const type_replacement = Dict{Any,Any}(
    #:Option_t                => :(Ptr{UInt8}),
    :(Ptr{None})              => :(Ptr{Void}),
    :Int_t                    => :Cint,
    :UInt_t                   => :Cuint,
    :Long_t                   => :Clong,
    :ULong_t                  => :Culong,
    :Long64_t                 => :Clonglong,
    :ULong64_t                => :Culonglong,
    :Double_t                 => :Cdouble,
    :Float_t                  => :Cfloat,
    :Bool_t                   => :Bool,
    :Char_t                   => :Cchar,
    :UChar_t                  => :Cuchar,
    :(Ptr{Option_t})          => :ASCIIString,
    :(Ptr{UInt8})             => :ASCIIString,
    :(Ptr{Double_t})          => :(Ptr{Cdouble}),
    :(Ptr{Float_t})           => :(Ptr{Cfloat}),
    :(Ptr{UInt_t})            => :(Ptr{Cuint}),

    :TH2D                     => :TH2DA,
    :TH2                      => :TH2A,
    
    :TH3D                     => :TH3DA,
    :TH3                      => :TH3A,

    :TH1D                     => :TH1DA,
{'fraction_non_alphanumeric': 0.11906797776827704, 'fraction_numerical': 0.011115861479264643, 'mean_word_length': 3.2570518653321203, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2036455', 'n_tokens_mistral': 3364, 'n_tokens_neox': 3282, 'n_words': 806}