<commit_before>#include "rhftda_elemental.hpp"

using namespace El;

using namespace aquarius::op;
using namespace aquarius::input;
using namespace aquarius::tensor;
using namespace aquarius::task;
using namespace aquarius::symmetry;

namespace aquarius
{
namespace cc
{

template <typename U>
ElementalRHFTDA<U>::ElementalRHFTDA(const string& name, Config& config)
: Task(name, config)
{
    vector<Requirement> reqs;
    reqs.push_back(Requirement("molecule", "molecule"));
    reqs.push_back(Requirement("mofock", "f"));
    reqs.push_back(Requirement("<Ai|Bj>", "VAIBJ"));
    reqs.push_back(Requirement("<Ai|Jb>", "VAIJB"));
    addProduct(Product("rhftda.evals_sing", "evals_sing", reqs));
    addProduct(Product("rhftda.evals_trip", "evals_trip", reqs));
    addProduct(Product("rhftda.evecs_sing", "evecs_sing", reqs));
    addProduct(Product("rhftda.evecs_trip", "evecs_trip", reqs));
}

template <typename U>
bool ElementalRHFTDA<U>::run(TaskDAG& dag, const Arena& arena)
{
    const Molecule& molecule = get<Molecule>("molecule");
    const PointGroup& group = molecule.getGroup();
    int nirrep = group.getNumIrreps();

    const auto& f = get<OneElectronOperator<U>>("f");
    const Space& occ = f.occ;
    const Space& vrt = f.vrt;
    const vector<int>& nI = occ.nalpha;
    const vector<int>& nA = vrt.nalpha;

    const auto& VAIBJ = this->template get<SymmetryBlockedTensor<U>>("VAIBJ");
    const auto& VAIJB = this->template get<SymmetryBlockedTensor<U>>("VAIJB");
    const auto& fAB = f.getAB()({0,0},{0,0});
    const auto& fIJ = f.getIJ()({0,0},{0,0});

    SymmetryBlockedTensor<U> H_sing("H_sing", arena, group, 4, {nA,nI,nA,nI}, {NS,NS,NS,NS}, true);
    SymmetryBlockedTensor<U> H_trip("H_trip", arena, group, 4, {nA,nI,nA,nI}, {NS,NS,NS,NS}, true);

    H_trip["aibi"]  =     fAB[  "ab"];
    H_trip["aibj"] -=   VAIBJ["ajbi"];
    H_trip["aiaj"] -=     fIJ[  "ji"];

    H_sing["aibj"]  =  H_trip["aibj"];
    H_sing["aibj"] += 2*VAIJB["ajib"];

    auto& evecs_sing = put("evecs_sing", new vector<unique_vector<SymmetryBlockedTensor<U>>>(nirrep));
    auto& evecs_trip = put("evecs_trip", new vector<unique_vector<SymmetryBlockedTensor<U>>>(nirrep));
    auto& evals_sing = put("evals_sing", new vector<vector<U>>(nirrep));
    auto& evals_trip = put("evals_trip", new vector<vector<U>>(nirrep));

    for (int R = 0;R < nirrep;R++)
    {
        const Representation& irr_R = group.getIrrep(R);

        int ntot = 0;
        for (int i = 0, count = 0;i < nirrep;i++)
        {
            const Representation& irr_i = group.getIrrep(i);
            for (int a = 0;a < nirrep;a++)
            {
                const Representation& irr_a = group.getIrrep(a);
                if (!(irr_a*irr_i*irr_R).isTotallySymmetric()) continue;
                ntot += nA[a]*nI[i];
                assert(count++ < nirrep);
            }
            assert(i < nirrep-1 || count == nirrep);
        }

        DistMatrix<U> H_sing_elem(ntot, ntot);
        DistMatrix<U> C_sing_elem(ntot, ntot);
        DistMatrix<U> H_trip_elem(ntot, ntot);
        DistMatrix<U> C_trip_elem(ntot, ntot);
        DistMatrix<U,VC,STAR> C_sing_local;
        DistMatrix<U,VC,STAR> C_trip_local;
        DistMatrix<U> E_sing_elem;
        DistMatrix<U> E_trip_elem;
        DistMatrix<U,STAR,STAR> E_sing_local;
        DistMatrix<U,STAR,STAR> E_trip_local;

        int offbj = 0;
        for (int j = 0;j < nirrep;j++)
        {
            const Representation& irr_j = group.getIrrep(j);
            for (int b = 0;b < nirrep;b++)
            {
                const Representation& irr_b = group.getIrrep(b);
                if (!(irr_b*irr_j*irr_R).isTotallySymmetric()) continue;

                int nb = nA[b];
                int nj = nI[j];
                int nbj = nb*nj;

                int offai = 0;
                for (int i = 0;i < nirrep;i++)
                {
                    const Representation& irr_i = group.getIrrep(i);
                    for (int a = 0;a < nirrep;a++)
                    {
                        const Representation& irr_a = group.getIrrep(a);
                        if (!(irr_a*irr_i*irr_R).isTotallySymmetric()) continue;

                        int na = nA[a];
                        int ni = nI[i];
                        int nai = na*ni;

                        int cshift = H_sing_elem.ColShift();
                        int rshift = H_sing_elem.RowShift();
                        int cstride = H_sing_elem.ColStride();
                        int rstride = H_sing_elem.RowStride();

                        int ishift0 = cshift-offai%cstride;
                        if (ishift0 < 0) ishift0 += cstride;
                        int iloc0   = offai+ishift0;

                        int ishift1 = cshift-(offai+nai)%cstride;
                        if (ishift1 < 0) ishift1 += cstride;
                        int iloc1   = (offai+nai)+ishift1;

                        int jshift0 = rshift-offbj%rstride;
                        if (jshift0 < 0) jshift0 += rstride;
                        int jloc0   = offbj+jshift0;

                        int jshift1 = rshift-(offbj+nai)%rstride;
                        if (jshift1 < 0) jshift1 += rstride;
                        int jloc1   = (offbj+nai)+jshift1;

                        vector<tkv_pair<U>> pairs;

                        for (int iloc = iloc0;iloc < iloc1;iloc += cstride)
                        {
                            key aidx = (iloc-offai)%na;
                            key iidx = (iloc-offai)/na;
                            assert(aidx >= 0 && aidx < na);
                            assert(iidx >= 0 && iidx < ni);

                            for (int jloc = jloc0;jloc < jloc1;jloc += rstride)
                            {
                                key bidx = (jloc-offbj)%nb;
                                key jidx = (jloc-offbj)/nb;
                                assert(bidx >= 0 && bidx < nb);
                                assert(jidx >= 0 && jidx < nj);

                                key k = ((jidx*nb+bidx)*ni+iidx)*na+aidx;
                                pairs.emplace_back(k, 0);
                            }
                        }

                        H_sing({a,i,b,j}).getRemoteData(pairs);

                        for (auto p : pairs)
                        {
                            key k = p.k;
                            int aidx = k%na;
                            k /= na;
                            int iidx = k%ni;
                            k /= nj;
                            int bidx = k%nb;
                            k /= nb;
                            int jidx = k;

                            int iloc = aidx+iidx*na+offai;
                            int jloc = bidx+jidx*nb+offbj;
                            assert(iloc%cstride == cshift);
                            assert(jloc%rstride == rshift);
                            iloc /= cstride;
                            jloc /= rstride;

                            assert(aidx >= 0 && aidx < na);
                            assert(bidx >= 0 && bidx < nb);
                            assert(iidx >= 0 && iidx < ni);
                            assert(jidx >= 0 && jidx < nj);
                            H_sing_elem.SetLocal(iloc, jloc, p.d);
                        }

                        H_trip({a,i,b,j}).getRemoteData(pairs);

                        for (auto p : pairs)
                        {
                            key k = p.k;
                            int aidx = k%na;
                            k /= na;
                            int jidx = k%nj;
                            k /= nj;
                            int bidx = k%nb;
                            k /= nb;
                            int iidx = k;

                            int iloc = aidx+iidx*na+offai;
                            int jloc = bidx+jidx*nb+offbj;
                            assert(iloc%cstride == cshift);
                            assert(jloc%rstride == rshift);
                            iloc /= cstride;
                            jloc /= rstride;

                            assert(aidx >= 0 && aidx < na);
                            assert(bidx >= 0 && bidx < nb);
                            assert(iidx >= 0 && iidx < ni);
                            assert(jidx >= 0 && jidx < nj);
                            H_trip_elem.SetLocal(iloc, jloc, p.d);
                        }

                        offai += nai;
                    }
                }
                offbj += nbj;
            }
        }

        HermitianEig(UPPER, H_sing_elem, E_sing_elem, C_sing_elem);
        HermitianEig(UPPER, H_trip_elem, E_trip_elem, C_trip_elem);

        E_sing_local = E_sing_elem;
        E_trip_local = E_trip_elem;
        C_sing_local = C_sing_elem;
        C_trip_local = C_trip_elem;

        for (int root = 0;root < ntot;root++)
        {
            evals_sing[R].push_back(E_sing_local.GetLocal(root, 0));
            evals_trip[R].push_back(E_trip_local.GetLocal(root, 0));
            evecs_sing[R].emplace_back("R", arena, occ.group, 2, vec(nA,nI), vec((int)NS,(int)NS), true);
            evecs_trip[R].emplace_back("R", arena, occ.group, 2, vec(nA,nI), vec((int)NS,(int)NS), true);
            auto& evec_sing = evecs_sing[R][root];
            auto& evec_trip = evecs_trip[R][root];

            int offai = 0;
            for (int i = 0;i < nirrep;i++)
            {
                const Representation& irr_i = group.getIrrep(i);
                for (int a = 0;a < nirrep;a++)
                {
                    const Representation& irr_a = group.getIrrep(a);
                    if (!(irr_a*irr_i*irr_R).isTotallySymmetric()) continue;

                    int nai = nA[a]*nI[i];

                    int cshift = C_sing_local.ColShift();
                    int cstride = C_sing_local.ColStride();

                    int shift0 = offai%cstride;
                    int loc0 = offai/cstride;
                    if (shift0 > cshift) loc0++;

                    int shift1 = (offai+nai)%cstride;
                    int loc1 = (offai+nai)/cstride;
                    if (shift1 > cshift) loc1++;

                    vector<tkv_pair<U>> pairs(loc1-loc0-1);

                    for (int loc = loc0;loc < loc1;loc++)
                    {
                        pairs[loc-loc0].k = loc*cstride+cshift-offai;
                        pairs[loc-loc0].d = C_sing_local.GetLocal(loc, root);
                    }

                    evec_sing({a,i}).writeRemoteData(pairs);

                    for (int loc = loc0;loc < loc1;loc++)
                    {
                        pairs[loc-loc0].k = loc*cstride+cshift-offai;
                        pairs[loc-loc0].d = C_trip_local.GetLocal(loc, root);
                    }

                    evec_trip({a,i}).writeRemoteData(pairs);

                    offai += nai;
                }
            }
        }

        cosort(evals_sing[R].begin() , evals_sing[R].end(),
               evecs_sing[R].pbegin(), evecs_sing[R].pend());
        cosort(evals_trip[R].begin() , evals_trip[R].end(),
               evecs_trip[R].pbegin(), evecs_trip[R].pend());
    }

    return true;
}

}
}

INSTANTIATE_SPECIALIZATIONS(aquarius::cc::ElementalRHFTDA);
REGISTER_TASK(aquarius::cc::ElementalRHFTDA<double>, "elementalrhftda");
<commit_msg> Fix vector length bug.<commit_after>#include "rhftda_elemental.hpp"

using namespace El;

using namespace aquarius::op;
using namespace aquarius::input;
using namespace aquarius::tensor;
using namespace aquarius::task;
using namespace aquarius::symmetry;

namespace aquarius
{
namespace cc
{

template <typename U>
ElementalRHFTDA<U>::ElementalRHFTDA(const string& name, Config& config)
: Task(name, config)
{
    vector<Requirement> reqs;
    reqs.push_back(Requirement("molecule", "molecule"));
    reqs.push_back(Requirement("mofock", "f"));
    reqs.push_back(Requirement("<Ai|Bj>", "VAIBJ"));
    reqs.push_back(Requirement("<Ai|Jb>", "VAIJB"));
    addProduct(Product("rhftda.evals_sing", "evals_sing", reqs));
    addProduct(Product("rhftda.evals_trip", "evals_trip", reqs));
    addProduct(Product("rhftda.evecs_sing", "evecs_sing", reqs));
    addProduct(Product("rhftda.evecs_trip", "evecs_trip", reqs));
}

template <typename U>
bool ElementalRHFTDA<U>::run(TaskDAG& dag, const Arena& arena)
{
    const Molecule& molecule = get<Molecule>("molecule");
    const PointGroup& group = molecule.getGroup();
    int nirrep = group.getNumIrreps();

    const auto& f = get<OneElectronOperator<U>>("f");
    const Space& occ = f.occ;
    const Space& vrt = f.vrt;
    const vector<int>& nI = occ.nalpha;
    const vector<int>& nA = vrt.nalpha;

    const auto& VAIBJ = this->template get<SymmetryBlockedTensor<U>>("VAIBJ");
    const auto& VAIJB = this->template get<SymmetryBlockedTensor<U>>("VAIJB");
    const auto& fAB = f.getAB()({0,0},{0,0});
    const auto& fIJ = f.getIJ()({0,0},{0,0});

    SymmetryBlockedTensor<U> H_sing("H_sing", arena, group, 4, {nA,nI,nA,nI}, {NS,NS,NS,NS}, true);
    SymmetryBlockedTensor<U> H_trip("H_trip", arena, group, 4, {nA,nI,nA,nI}, {NS,NS,NS,NS}, true);

    H_trip["aibi"]  =     fAB[  "ab"];
    H_trip["aibj"] -=   VAIBJ["ajbi"];
    H_trip["aiaj"] -=     fIJ[  "ji"];

    H_sing["aibj"]  =  H_trip["aibj"];
    H_sing["aibj"] += 2*VAIJB["ajib"];

    auto& evecs_sing = put("evecs_sing", new vector<unique_vector<SymmetryBlockedTensor<U>>>(nirrep));
    auto& evecs_trip = put("evecs_trip", new vector<unique_vector<SymmetryBlockedTensor<U>>>(nirrep));
    auto& evals_sing = put("evals_sing", new vector<vector<U>>(nirrep));
    auto& evals_trip = put("evals_trip", new vector<vector<U>>(nirrep));

    for (int R = 0;R < nirrep;R++)
    {
        const Representation& irr_R = group.getIrrep(R);

        int ntot = 0;
        for (int i = 0, count = 0;i < nirrep;i++)
        {
            const Representation& irr_i = group.getIrrep(i);
            for (int a = 0;a < nirrep;a++)
            {
                const Representation& irr_a = group.getIrrep(a);
                if (!(irr_a*irr_i*irr_R).isTotallySymmetric()) continue;
                ntot += nA[a]*nI[i];
                assert(count++ < nirrep);
            }
            assert(i < nirrep-1 || count == nirrep);
        }

        DistMatrix<U> H_sing_elem(ntot, ntot);
        DistMatrix<U> C_sing_elem(ntot, ntot);
        DistMatrix<U> H_trip_elem(ntot, ntot);
        DistMatrix<U> C_trip_elem(ntot, ntot);
        DistMatrix<U,VC,STAR> C_sing_local;
        DistMatrix<U,VC,STAR> C_trip_local;
        DistMatrix<U> E_sing_elem;
        DistMatrix<U> E_trip_elem;
        DistMatrix<U,STAR,STAR> E_sing_local;
        DistMatrix<U,STAR,STAR> E_trip_local;

        int offbj = 0;
        for (int j = 0;j < nirrep;j++)
        {
            const Representation& irr_j = group.getIrrep(j);
            for (int b = 0;b < nirrep;b++)
            {
                const Representation& irr_b = group.getIrrep(b);
                if (!(irr_b*irr_j*irr_R).isTotallySymmetric()) continue;

                int nb = nA[b];
                int nj = nI[j];
                int nbj = nb*nj;

                int offai = 0;
                for (int i = 0;i < nirrep;i++)
                {
                    const Representation& irr_i = group.getIrrep(i);
                    for (int a = 0;a < nirrep;a++)
                    {
                        const Representation& irr_a = group.getIrrep(a);
                        if (!(irr_a*irr_i*irr_R).isTotallySymmetric()) continue;

                        int na = nA[a];
                        int ni = nI[i];
                        int nai = na*ni;

                        int cshift = H_sing_elem.ColShift();
                        int rshift = H_sing_elem.RowShift();
                        int cstride = H_sing_elem.ColStride();
                        int rstride = H_sing_elem.RowStride();

                        int ishift0 = cshift-offai%cstride;
                        if (ishift0 < 0) ishift0 += cstride;
                        int iloc0   = offai+ishift0;

                        int ishift1 = cshift-(offai+nai)%cstride;
                        if (ishift1 < 0) ishift1 += cstride;
                        int iloc1   = (offai+nai)+ishift1;

                        int jshift0 = rshift-offbj%rstride;
                        if (jshift0 < 0) jshift0 += rstride;
                        int jloc0   = offbj+jshift0;

                        int jshift1 = rshift-(offbj+nai)%rstride;
                        if (jshift1 < 0) jshift1 += rstride;
                        int jloc1   = (offbj+nai)+jshift1;

                        vector<tkv_pair<U>> pairs;

                        for (int iloc = iloc0;iloc < iloc1;iloc += cstride)
                        {
                            key aidx = (iloc-offai)%na;
                            key iidx = (iloc-offai)/na;
                            assert(aidx >= 0 && aidx < na);
                            assert(iidx >= 0 && iidx < ni);

                            for (int jloc = jloc0;jloc < jloc1;jloc += rstride)
                            {
                                key bidx = (jloc-offbj)%nb;
                                key jidx = (jloc-offbj)/nb;
                                assert(bidx >= 0 && bidx < nb);
                                assert(jidx >= 0 && jidx < nj);

                                key k = ((jidx*nb+bidx)*ni+iidx)*na+aidx;
                                pairs.emplace_back(k, 0);
                            }
                        }

                        H_sing({a,i,b,j}).getRemoteData(pairs);

                        for (auto p : pairs)
                        {
                            key k = p.k;
                            int aidx = k%na;
                            k /= na;
                            int iidx = k%ni;
                            k /= nj;
                            int bidx = k%nb;
                            k /= nb;
                            int jidx = k;

                            int iloc = aidx+iidx*na+offai;
                            int jloc = bidx+jidx*nb+offbj;
                            assert(iloc%cstride == cshift);
                            assert(jloc%rstride == rshift);
                            iloc /= cstride;
                            jloc /= rstride;

                            assert(aidx >= 0 && aidx < na);
                            assert(bidx >= 0 && bidx < nb);
                            assert(iidx >= 0 && iidx < ni);
                            assert(jidx >= 0 && jidx < nj);
                            H_sing_elem.SetLocal(iloc, jloc, p.d);
                        }

                        H_trip({a,i,b,j}).getRemoteData(pairs);

                        for (auto p : pairs)
                        {
                            key k = p.k;
                            int aidx = k%na;
                            k /= na;
                            int jidx = k%nj;
                            k /= nj;
                            int bidx = k%nb;
                            k /= nb;
                            int iidx = k;

                            int iloc = aidx+iidx*na+offai;
                            int jloc = bidx+jidx*nb+offbj;
                            assert(iloc%cstride == cshift);
                            assert(jloc%rstride == rshift);
                            iloc /= cstride;
                            jloc /= rstride;

                            assert(aidx >= 0 && aidx < na);
                            assert(bidx >= 0 && bidx < nb);
                            assert(iidx >= 0 && iidx < ni);
                            assert(jidx >= 0 && jidx < nj);
                            H_trip_elem.SetLocal(iloc, jloc, p.d);
                        }

                        offai += nai;
                    }
                }
                offbj += nbj;
            }
        }

        HermitianEig(UPPER, H_sing_elem, E_sing_elem, C_sing_elem);
        HermitianEig(UPPER, H_trip_elem, E_trip_elem, C_trip_elem);

        E_sing_local = E_sing_elem;
        E_trip_local = E_trip_elem;
        C_sing_local = C_sing_elem;
        C_trip_local = C_trip_elem;

        for (int root = 0;root < ntot;root++)
        {
            evals_sing[R].push_back(E_sing_local.GetLocal(root, 0));
            evals_trip[R].push_back(E_trip_local.GetLocal(root, 0));
            evecs_sing[R].emplace_back("R", arena, occ.group, 2, vec(nA,nI), vec((int)NS,(int)NS), true);
            evecs_trip[R].emplace_back("R", arena, occ.group, 2, vec(nA,nI), vec((int)NS,(int)NS), true);
            auto& evec_sing = evecs_sing[R][root];
            auto& evec_trip = evecs_trip[R][root];

            int offai = 0;
            for (int i = 0;i < nirrep;i++)
            {
                const Representation& irr_i = group.getIrrep(i);
                for (int a = 0;a < nirrep;a++)
                {
                    const Representation& irr_a = group.getIrrep(a);
                    if (!(irr_a*irr_i*irr_R).isTotallySymmetric()) continue;

                    int nai = nA[a]*nI[i];

                    int cshift = C_sing_local.ColShift();
                    int cstride = C_sing_local.ColStride();

                    int shift0 = offai%cstride;
                    int loc0 = offai/cstride;
                    if (shift0 > cshift) loc0++;

                    int shift1 = (offai+nai)%cstride;
                    int loc1 = (offai+nai)/cstride;
                    if (shift1 > cshift) loc1++;

                    vector<tkv_pair<U>> pairs(loc1-loc0+1);

                    for (int loc = loc0;loc < loc1;loc++)
                    {
                        pairs[loc-loc0].k = loc*cstride+cshift-offai;
                        pairs[loc-loc0].d = C_sing_local.GetLocal(loc, root);
                    }

                    evec_sing({a,i}).writeRemoteData(pairs);

                    for (int loc = loc0;loc < loc1;loc++)
                    {
                        pairs[loc-loc0].k = loc*cstride+cshift-offai;
                        pairs[loc-loc0].d = C_trip_local.GetLocal(loc, root);
                    }

                    evec_trip({a,i}).writeRemoteData(pairs);

                    offai += nai;
                }
            }
        }

        cosort(evals_sing[R].begin() , evals_sing[R].end(),
               evecs_sing[R].pbegin(), evecs_sing[R].pend());
        cosort(evals_trip[R].begin() , evals_trip[R].end(),
               evecs_trip[R].pbegin(), evecs_trip[R].pend());
    }

    return true;
}

}
}

INSTANTIATE_SPECIALIZATIONS(aquarius::cc::ElementalRHFTDA);
REGISTER_TASK(aquarius::cc::ElementalRHFTDA<double>, "elementalrhftda");
<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef CERT_DATABASE_HXX
#define CERT_DATABASE_HXX

#include "pg/Connection.hxx"
#include "ssl/Unique.hxx"

#include <string>

typedef struct aes_key_st AES_KEY;
struct CertDatabaseConfig;

class CertDatabase {
    const CertDatabaseConfig &config;

    Pg::Connection conn;

public:
    explicit CertDatabase(const CertDatabaseConfig &_config);

    ConnStatusType GetStatus() const {
        return conn.GetStatus();
    }

    gcc_pure
    const char *GetErrorMessage() const {
        return conn.GetErrorMessage();
    }

    bool CheckConnected();
    void EnsureConnected();

    gcc_pure
    int GetSocket() const {
        return conn.GetSocket();
    }

    void ConsumeInput() {
        conn.ConsumeInput();
    }

    Pg::Notify GetNextNotify() {
        return conn.GetNextNotify();
    }

    Pg::Result ListenModified();
    Pg::Result NotifyModified();

    gcc_pure
    std::string GetCurrentTimestamp() {
        const auto result = conn.Execute("SELECT CURRENT_TIMESTAMP");
        return result.GetOnlyStringChecked();
    }

    gcc_pure
    std::string GetLastModified() {
        const auto result = conn.Execute("SELECT MAX(modified) FROM server_certificate");
        return result.GetOnlyStringChecked();
    }

    bool BeginSerializable() {
        return conn.BeginSerializable();
    }

    bool Commit() {
        return conn.Commit();
    }

    void Migrate();

    Pg::Serial GetIdByHandle(const char *handle);

    void InsertServerCertificate(const char *handle,
                                 const char *common_name,
                                 const char *issuer_common_name,
                                 const char *not_before,
                                 const char *not_after,
                                 X509 &cert, ConstBuffer<void> key,
                                 const char *key_wrap_name);

    /**
     * @return true when new certificate has been inserted, false when an
     * existing certificate has been updated
     */
    bool LoadServerCertificate(const char *handle,
                               X509 &cert, EVP_PKEY &key,
                               const char *key_wrap_name,
                               AES_KEY *wrap_key);

    /**
     * Delete *.acme.invalid for alt_names of the given certificate.
     */
    unsigned DeleteAcmeInvalidAlt(X509 &cert);

    UniqueX509 GetServerCertificateByHandle(const char *handle);

    /**
     * Throws std::runtime_error on error.
     *
     * @return a pair of certificate and key, or {nullptr, nullptr} if
     * no matching certificate was found
     */
    std::pair<UniqueX509, UniqueEVP_PKEY> GetServerCertificateKeyByHandle(const char *handle);
    std::pair<UniqueX509, UniqueEVP_PKEY> GetServerCertificateKey(const char *name);
    std::pair<UniqueX509, UniqueEVP_PKEY> GetServerCertificateKey(Pg::Serial id);

    /**
     * Result columns: id, handle, issuer_common_name, not_after
     */
    Pg::Result FindServerCertificatesByName(const char *name);

    std::list<std::string> GetNamesByHandle(const char *handle);

    void SetHandle(Pg::Serial id, const char *handle);

private:
    Pg::Result InsertServerCertificate(const char *handle,
                                       const char *common_name,
                                       const char *issuer_common_name,
                                       const char *not_before,
                                       const char *not_after,
                                       Pg::BinaryValue cert, Pg::BinaryValue key,
                                       const char *key_wrap_name) {
        return conn.ExecuteBinary("INSERT INTO server_certificate("
                                  "handle, common_name, issuer_common_name, "
                                  "not_before, not_after, "
                                  "certificate_der, key_der, key_wrap_name) "
                                  "VALUES($1, $2, $3, $4, $5, $6, $7, $8)"
                                  " RETURNING id",
                                  handle, common_name, issuer_common_name,
                                  not_before, not_after,
                                  cert, key, key_wrap_name);
    }

    Pg::Result UpdateServerCertificate(const char *handle,
                                       const char *common_name,
                                       const char *issuer_common_name,
                                       const char *not_before,
                                       const char *not_after,
                                       Pg::BinaryValue cert, Pg::BinaryValue key,
                                       const char *key_wrap_name) {
        return conn.ExecuteBinary("UPDATE server_certificate SET "
                                  "common_name=$1, "
                                  "not_before=$2, not_after=$3, "
                                  "certificate_der=$4, key_der=$5, "
                                  "key_wrap_name=$6, "
                                  "issuer_common_name=$7, "
                                  "modified=CURRENT_TIMESTAMP, deleted=FALSE "
                                  "WHERE handle=$8"
                                  " RETURNING id",
                                  common_name, not_before, not_after,
                                  cert, key, key_wrap_name,
                                  issuer_common_name, handle);
    }

    Pg::Result DeleteAltNames(const char *server_certificate_id) {
        return conn.ExecuteParams("DELETE FROM server_certificate_alt_name"
                                  " WHERE server_certificate_id=$1",
                                  server_certificate_id);
    }

    Pg::Result InsertAltName(const char *server_certificate_id,
                             const char *name) {
        return conn.ExecuteParams("INSERT INTO server_certificate_alt_name"
                                  "(server_certificate_id, name)"
                                  " VALUES($1, $2)",
                                  server_certificate_id, name);
    }

public:
    Pg::Result DeleteServerCertificateByHandle(const char *handle) {
        return conn.ExecuteParams(true,
                                  "UPDATE server_certificate SET "
                                  "modified=CURRENT_TIMESTAMP, deleted=TRUE "
                                  "WHERE handle=$1 AND NOT deleted",
                                  handle);
    }

private:
    template<typename T>
    Pg::Result DeleteAcmeInvalidByNames(const T &names) {
        return conn.ExecuteParams(true,
                                  "UPDATE server_certificate SET "
                                  "modified=CURRENT_TIMESTAMP, deleted=TRUE "
                                  "WHERE NOT deleted AND common_name = ANY($1)"
                                  " AND EXISTS("
                                  "SELECT id FROM server_certificate_alt_name"
                                  " WHERE server_certificate_id=server_certificate.id"
                                  " AND name LIKE '%.acme.invalid')",
                                  names);
    }

    Pg::Result FindServerCertificateByHandle(const char *handle) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der "
                                  "FROM server_certificate "
                                  "WHERE NOT deleted AND handle=$1"
                                  "LIMIT 1",
                                  handle);
    }

    Pg::Result FindServerCertificateKeyByHandle(const char *handle) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der, key_der, key_wrap_name "
                                  "FROM server_certificate "
                                  "WHERE handle=$1 AND NOT deleted "
                                  "LIMIT 1",
                                  handle);
    }

    Pg::Result FindServerCertificateKeyByName(const char *common_name) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der, key_der, key_wrap_name "
                                  "FROM server_certificate "
                                  "WHERE NOT deleted AND "
                                  "(common_name=$1 OR EXISTS("
                                  "SELECT id FROM server_certificate_alt_name"
                                  " WHERE server_certificate_id=server_certificate.id"
                                  " AND name=$1))"
                                  "ORDER BY"
                                  /* prefer certificates which expire later */
                                  " not_after DESC,"
                                  /* prefer exact match in common_name: */
                                  " common_name=$1 DESC "
                                  "LIMIT 1",
                                  common_name);
    }

    Pg::Result FindServerCertificateKeyById(Pg::Serial id) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der, key_der, key_wrap_name "
                                  "FROM server_certificate "
                                  "WHERE id=$1",
                                  id);
    }

public:
    Pg::Result GetModifiedServerCertificatesMeta(const char *since) {
        return conn.ExecuteParams("SELECT deleted, modified, handle "
                                  "FROM server_certificate "
                                  "WHERE modified>$1",
                                  since);
    }

    Pg::Result TailModifiedServerCertificatesMeta() {
        return conn.Execute("SELECT deleted, modified, handle "
                            "FROM server_certificate "
                            "ORDER BY modified LIMIT 20");
    }
};

#endif
<commit_msg>certdb/CertDatabase: support handle==nullptr in UpdateServerCertificate()<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef CERT_DATABASE_HXX
#define CERT_DATABASE_HXX

#include "pg/Connection.hxx"
#include "ssl/Unique.hxx"

#include <string>

typedef struct aes_key_st AES_KEY;
struct CertDatabaseConfig;

class CertDatabase {
    const CertDatabaseConfig &config;

    Pg::Connection conn;

public:
    explicit CertDatabase(const CertDatabaseConfig &_config);

    ConnStatusType GetStatus() const {
        return conn.GetStatus();
    }

    gcc_pure
    const char *GetErrorMessage() const {
        return conn.GetErrorMessage();
    }

    bool CheckConnected();
    void EnsureConnected();

    gcc_pure
    int GetSocket() const {
        return conn.GetSocket();
    }

    void ConsumeInput() {
        conn.ConsumeInput();
    }

    Pg::Notify GetNextNotify() {
        return conn.GetNextNotify();
    }

    Pg::Result ListenModified();
    Pg::Result NotifyModified();

    gcc_pure
    std::string GetCurrentTimestamp() {
        const auto result = conn.Execute("SELECT CURRENT_TIMESTAMP");
        return result.GetOnlyStringChecked();
    }

    gcc_pure
    std::string GetLastModified() {
        const auto result = conn.Execute("SELECT MAX(modified) FROM server_certificate");
        return result.GetOnlyStringChecked();
    }

    bool BeginSerializable() {
        return conn.BeginSerializable();
    }

    bool Commit() {
        return conn.Commit();
    }

    void Migrate();

    Pg::Serial GetIdByHandle(const char *handle);

    void InsertServerCertificate(const char *handle,
                                 const char *common_name,
                                 const char *issuer_common_name,
                                 const char *not_before,
                                 const char *not_after,
                                 X509 &cert, ConstBuffer<void> key,
                                 const char *key_wrap_name);

    /**
     * @return true when new certificate has been inserted, false when an
     * existing certificate has been updated
     */
    bool LoadServerCertificate(const char *handle,
                               X509 &cert, EVP_PKEY &key,
                               const char *key_wrap_name,
                               AES_KEY *wrap_key);

    /**
     * Delete *.acme.invalid for alt_names of the given certificate.
     */
    unsigned DeleteAcmeInvalidAlt(X509 &cert);

    UniqueX509 GetServerCertificateByHandle(const char *handle);

    /**
     * Throws std::runtime_error on error.
     *
     * @return a pair of certificate and key, or {nullptr, nullptr} if
     * no matching certificate was found
     */
    std::pair<UniqueX509, UniqueEVP_PKEY> GetServerCertificateKeyByHandle(const char *handle);
    std::pair<UniqueX509, UniqueEVP_PKEY> GetServerCertificateKey(const char *name);
    std::pair<UniqueX509, UniqueEVP_PKEY> GetServerCertificateKey(Pg::Serial id);

    /**
     * Result columns: id, handle, issuer_common_name, not_after
     */
    Pg::Result FindServerCertificatesByName(const char *name);

    std::list<std::string> GetNamesByHandle(const char *handle);

    void SetHandle(Pg::Serial id, const char *handle);

private:
    Pg::Result InsertServerCertificate(const char *handle,
                                       const char *common_name,
                                       const char *issuer_common_name,
                                       const char *not_before,
                                       const char *not_after,
                                       Pg::BinaryValue cert, Pg::BinaryValue key,
                                       const char *key_wrap_name) {
        return conn.ExecuteBinary("INSERT INTO server_certificate("
                                  "handle, common_name, issuer_common_name, "
                                  "not_before, not_after, "
                                  "certificate_der, key_der, key_wrap_name) "
                                  "VALUES($1, $2, $3, $4, $5, $6, $7, $8)"
                                  " RETURNING id",
                                  handle, common_name, issuer_common_name,
                                  not_before, not_after,
                                  cert, key, key_wrap_name);
    }

    Pg::Result UpdateServerCertificate(const char *handle,
                                       const char *common_name,
                                       const char *issuer_common_name,
                                       const char *not_before,
                                       const char *not_after,
                                       Pg::BinaryValue cert, Pg::BinaryValue key,
                                       const char *key_wrap_name) {
        // TODO: remove handle==nullptr support eventually
        return conn.ExecuteBinary(handle != nullptr
                                  ? "UPDATE server_certificate SET "
                                  "common_name=$1, "
                                  "not_before=$2, not_after=$3, "
                                  "certificate_der=$4, key_der=$5, "
                                  "key_wrap_name=$6, "
                                  "issuer_common_name=$7, "
                                  "modified=CURRENT_TIMESTAMP, deleted=FALSE "
                                  "WHERE handle=$8"
                                  " RETURNING id"
                                  : "UPDATE server_certificate SET "
                                  "not_before=$2, not_after=$3, "
                                  "certificate_der=$4, key_der=$5, "
                                  "key_wrap_name=$6, "
                                  "issuer_common_name=$7, "
                                  "handle=$8, "
                                  "modified=CURRENT_TIMESTAMP, deleted=FALSE "
                                  "WHERE common_name=$1"
                                  " RETURNING id",
                                 common_name, not_before, not_after,
                                 cert, key, key_wrap_name,
                                 issuer_common_name, handle);
    }

    Pg::Result DeleteAltNames(const char *server_certificate_id) {
        return conn.ExecuteParams("DELETE FROM server_certificate_alt_name"
                                  " WHERE server_certificate_id=$1",
                                  server_certificate_id);
    }

    Pg::Result InsertAltName(const char *server_certificate_id,
                             const char *name) {
        return conn.ExecuteParams("INSERT INTO server_certificate_alt_name"
                                  "(server_certificate_id, name)"
                                  " VALUES($1, $2)",
                                  server_certificate_id, name);
    }

public:
    Pg::Result DeleteServerCertificateByHandle(const char *handle) {
        return conn.ExecuteParams(true,
                                  "UPDATE server_certificate SET "
                                  "modified=CURRENT_TIMESTAMP, deleted=TRUE "
                                  "WHERE handle=$1 AND NOT deleted",
                                  handle);
    }

private:
    template<typename T>
    Pg::Result DeleteAcmeInvalidByNames(const T &names) {
        return conn.ExecuteParams(true,
                                  "UPDATE server_certificate SET "
                                  "modified=CURRENT_TIMESTAMP, deleted=TRUE "
                                  "WHERE NOT deleted AND common_name = ANY($1)"
                                  " AND EXISTS("
                                  "SELECT id FROM server_certificate_alt_name"
                                  " WHERE server_certificate_id=server_certificate.id"
                                  " AND name LIKE '%.acme.invalid')",
                                  names);
    }

    Pg::Result FindServerCertificateByHandle(const char *handle) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der "
                                  "FROM server_certificate "
                                  "WHERE NOT deleted AND handle=$1"
                                  "LIMIT 1",
                                  handle);
    }

    Pg::Result FindServerCertificateKeyByHandle(const char *handle) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der, key_der, key_wrap_name "
                                  "FROM server_certificate "
                                  "WHERE handle=$1 AND NOT deleted "
                                  "LIMIT 1",
                                  handle);
    }

    Pg::Result FindServerCertificateKeyByName(const char *common_name) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der, key_der, key_wrap_name "
                                  "FROM server_certificate "
                                  "WHERE NOT deleted AND "
                                  "(common_name=$1 OR EXISTS("
                                  "SELECT id FROM server_certificate_alt_name"
                                  " WHERE server_certificate_id=server_certificate.id"
                                  " AND name=$1))"
                                  "ORDER BY"
                                  /* prefer certificates which expire later */
                                  " not_after DESC,"
                                  /* prefer exact match in common_name: */
                                  " common_name=$1 DESC "
                                  "LIMIT 1",
                                  common_name);
    }

    Pg::Result FindServerCertificateKeyById(Pg::Serial id) {
        return conn.ExecuteParams(true,
                                  "SELECT certificate_der, key_der, key_wrap_name "
                                  "FROM server_certificate "
                                  "WHERE id=$1",
                                  id);
    }

public:
    Pg::Result GetModifiedServerCertificatesMeta(const char *since) {
        return conn.ExecuteParams("SELECT deleted, modified, handle "
                                  "FROM server_certificate "
                                  "WHERE modified>$1",
                                  since);
    }

    Pg::Result TailModifiedServerCertificatesMeta() {
        return conn.Execute("SELECT deleted, modified, handle "
                            "FROM server_certificate "
                            "ORDER BY modified LIMIT 20");
    }
};

#endif
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <chartsql/CSTableScan.h>
#include <chartsql/qtree/ColumnReferenceNode.h>
#include <chartsql/runtime/defaultruntime.h>
#include <chartsql/runtime/compile.h>
#include <fnord/inspect.h>

using namespace fnord;

namespace csql {

CSTableScan::CSTableScan(
    RefPtr<SequentialScanNode> stmt,
    cstable::CSTableReader&& cstable,
    QueryBuilder* runtime) :
    cstable_(std::move(cstable)),
    colindex_(0),
    aggr_strategy_(stmt->aggregationStrategy()) {
  Set<String> column_names;
  for (const auto& slnode : stmt->selectList()) {
    findColumns(slnode->expression(), &column_names);
    column_names_.emplace_back(slnode->columnName());
  }

  auto where_expr = stmt->whereExpression();
  if (!where_expr.isEmpty()) {
    findColumns(where_expr.get(), &column_names);
  }

  for (const auto& col : column_names) {
    columns_.emplace(col, ColumnRef(cstable_.getColumnReader(col), colindex_++));
  }

  for (auto& slnode : stmt->selectList()) {
    resolveColumns(slnode->expression());
  }

  for (const auto& slnode : stmt->selectList()) {
    select_list_.emplace_back(
        findMaxRepetitionLevel(slnode->expression()),
        runtime->buildValueExpression(slnode->expression()),
        &scratch_);
  }

  if (!where_expr.isEmpty()) {
    resolveColumns(where_expr.get());
    where_expr_ = runtime->buildValueExpression(where_expr.get());
  }
}

void CSTableScan::execute(
    ExecutionContext* context,
    Function<bool (int argc, const SValue* argv)> fn) {
  context->incrNumSubtasksTotal(1);

  if (columns_.empty()) {
    scanWithoutColumns(fn);
  } else {
    scan(fn);
  }
  context->incrNumSubtasksCompleted(1);
}

void CSTableScan::scan(
    Function<bool (int argc, const SValue* argv)> fn) {
  uint64_t select_level = 0;
  uint64_t fetch_level = 0;

  Vector<SValue> in_row(colindex_, SValue{});
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t num_records = 0;
  size_t total_records = cstable_.numRecords();
  while (num_records < total_records) {
    uint64_t next_level = 0;

    if (fetch_level == 0) {
      ++num_records;
    }

    for (auto& col : columns_) {
      auto nextr = col.second.reader->nextRepetitionLevel();

      if (nextr >= fetch_level) {
        auto& reader = col.second.reader;

        uint64_t r;
        uint64_t d;
        void* data;
        size_t size;
        reader->next(&r, &d, &data, &size);

        if (d < reader->maxDefinitionLevel()) {
          in_row[col.second.index] = SValue();
        } else {
          switch (col.second.reader->type()) {

            case msg::FieldType::STRING:
              in_row[col.second.index] =
                  SValue(SValue::StringType((char*) data, size));
              break;

            case msg::FieldType::UINT32:
            case msg::FieldType::UINT64:
              switch (size) {
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint32_t*) data)));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint64_t*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            case msg::FieldType::BOOLEAN:
              switch (size) {
                case sizeof(uint8_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint8_t*) data) > 0));
                  break;
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint32_t*) data) > 0));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint64_t*) data) > 0));
                  break;
                case 0:
                  in_row[col.second.index] = SValue(SValue::BoolType(false));
                  break;
              }
              break;

            case msg::FieldType::OBJECT:
              RAISE(kIllegalStateError);

          }
        }
      }

      next_level = std::max(
          next_level,
          col.second.reader->nextRepetitionLevel());
    }

    fetch_level = next_level;

    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(in_row.size(), in_row.data(), &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      for (int i = 0; i < select_list_.size(); ++i) {
        if (select_list_[i].rep_level >= select_level) {
          select_list_[i].compiled->accumulate(
              &select_list_[i].instance,
              in_row.size(),
              in_row.data());
        }
      }

      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
          if (next_level != 0) {
            break;
          }

          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->result(
                &select_list_[i].instance,
                &out_row[i]);

            select_list_[i].compiled->reset(&select_list_[i].instance);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                in_row.size(),
                in_row.data(),
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

      }

      select_level = fetch_level;
    } else {
      select_level = std::min(select_level, fetch_level);
    }

    for (const auto& col : columns_) {
      if (col.second.reader->maxRepetitionLevel() >= select_level) {
        in_row[col.second.index] = SValue();
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::scanWithoutColumns(
    Function<bool (int argc, const SValue* argv)> fn) {
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t total_records = cstable_.numRecords();
  for (size_t i = 0; i < total_records; ++i) {
    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(0, nullptr, &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->accumulate(
                &select_list_[i].instance,
                0,
                nullptr);
          }
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                0,
                nullptr,
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }
          break;
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::findColumns(
    RefPtr<ValueExpressionNode> expr,
    Set<String>* column_names) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    column_names->emplace(fieldref->fieldName());
  }

  for (const auto& e : expr->arguments()) {
    findColumns(e, column_names);
  }
}

void CSTableScan::resolveColumns(RefPtr<ValueExpressionNode> expr) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    fieldref->setColumnIndex(col->second.index);
  }

  for (const auto& e : expr->arguments()) {
    resolveColumns(e);
  }
}

uint64_t CSTableScan::findMaxRepetitionLevel(
    RefPtr<ValueExpressionNode> expr) const {
  uint64_t max_level = 0;

  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    auto col_level = col->second.reader->maxRepetitionLevel();
    if (col_level > max_level) {
      max_level = col_level;
    }
  }

  for (const auto& e : expr->arguments()) {
    auto e_level = findMaxRepetitionLevel(e);
    if (e_level > max_level) {
      max_level = e_level;
    }
  }

  return max_level;
}

Vector<String> CSTableScan::columnNames() const {
  return column_names_;
}

size_t CSTableScan::numColumns() const {
  return column_names_.size();
}

CSTableScan::ColumnRef::ColumnRef(
    RefPtr<cstable::ColumnReader> r,
    size_t i) :
    reader(r),
    index(i) {}

CSTableScan::ExpressionRef::ExpressionRef(
    size_t _rep_level,
    ScopedPtr<ValueExpression> _compiled,
    ScratchMemory* smem) :
    rep_level(_rep_level),
    compiled(std::move(_compiled)),
    instance(compiled->allocInstance(smem)) {}

CSTableScan::ExpressionRef::ExpressionRef(
    ExpressionRef&& other) :
    rep_level(other.rep_level),
    compiled(std::move(other.compiled)),
    instance(other.instance) {
  other.instance.scratch = nullptr;
}

CSTableScan::ExpressionRef::~ExpressionRef() {
  if (instance.scratch) {
    compiled->freeInstance(&instance);
  }
}

} // namespace csql
<commit_msg>handle FieldType::DOUBLE in CSTableScan<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <chartsql/CSTableScan.h>
#include <chartsql/qtree/ColumnReferenceNode.h>
#include <chartsql/runtime/defaultruntime.h>
#include <chartsql/runtime/compile.h>
#include <fnord/ieee754.h>

using namespace fnord;

namespace csql {

CSTableScan::CSTableScan(
    RefPtr<SequentialScanNode> stmt,
    cstable::CSTableReader&& cstable,
    QueryBuilder* runtime) :
    cstable_(std::move(cstable)),
    colindex_(0),
    aggr_strategy_(stmt->aggregationStrategy()) {
  Set<String> column_names;
  for (const auto& slnode : stmt->selectList()) {
    findColumns(slnode->expression(), &column_names);
    column_names_.emplace_back(slnode->columnName());
  }

  auto where_expr = stmt->whereExpression();
  if (!where_expr.isEmpty()) {
    findColumns(where_expr.get(), &column_names);
  }

  for (const auto& col : column_names) {
    columns_.emplace(col, ColumnRef(cstable_.getColumnReader(col), colindex_++));
  }

  for (auto& slnode : stmt->selectList()) {
    resolveColumns(slnode->expression());
  }

  for (const auto& slnode : stmt->selectList()) {
    select_list_.emplace_back(
        findMaxRepetitionLevel(slnode->expression()),
        runtime->buildValueExpression(slnode->expression()),
        &scratch_);
  }

  if (!where_expr.isEmpty()) {
    resolveColumns(where_expr.get());
    where_expr_ = runtime->buildValueExpression(where_expr.get());
  }
}

void CSTableScan::execute(
    ExecutionContext* context,
    Function<bool (int argc, const SValue* argv)> fn) {
  context->incrNumSubtasksTotal(1);

  if (columns_.empty()) {
    scanWithoutColumns(fn);
  } else {
    scan(fn);
  }
  context->incrNumSubtasksCompleted(1);
}

void CSTableScan::scan(
    Function<bool (int argc, const SValue* argv)> fn) {
  uint64_t select_level = 0;
  uint64_t fetch_level = 0;

  Vector<SValue> in_row(colindex_, SValue{});
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t num_records = 0;
  size_t total_records = cstable_.numRecords();
  while (num_records < total_records) {
    uint64_t next_level = 0;

    if (fetch_level == 0) {
      ++num_records;
    }

    for (auto& col : columns_) {
      auto nextr = col.second.reader->nextRepetitionLevel();

      if (nextr >= fetch_level) {
        auto& reader = col.second.reader;

        uint64_t r;
        uint64_t d;
        void* data;
        size_t size;
        reader->next(&r, &d, &data, &size);

        if (d < reader->maxDefinitionLevel()) {
          in_row[col.second.index] = SValue();
        } else {
          switch (col.second.reader->type()) {

            case msg::FieldType::STRING:
              in_row[col.second.index] =
                  SValue(SValue::StringType((char*) data, size));
              break;

            case msg::FieldType::UINT32:
            case msg::FieldType::UINT64:
              switch (size) {
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint32_t*) data)));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint64_t*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            case msg::FieldType::BOOLEAN:
              switch (size) {
                case sizeof(uint8_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint8_t*) data) > 0));
                  break;
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint32_t*) data) > 0));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint64_t*) data) > 0));
                  break;
                case 0:
                  in_row[col.second.index] = SValue(SValue::BoolType(false));
                  break;
              }
              break;

            case msg::FieldType::DOUBLE:
              switch (size) {
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::FloatType(
                          IEEE754::fromBytes(*((uint64_t*) data))));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            default:
              RAISE(kIllegalStateError);

          }
        }
      }

      next_level = std::max(
          next_level,
          col.second.reader->nextRepetitionLevel());
    }

    fetch_level = next_level;

    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(in_row.size(), in_row.data(), &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      for (int i = 0; i < select_list_.size(); ++i) {
        if (select_list_[i].rep_level >= select_level) {
          select_list_[i].compiled->accumulate(
              &select_list_[i].instance,
              in_row.size(),
              in_row.data());
        }
      }

      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
          if (next_level != 0) {
            break;
          }

          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->result(
                &select_list_[i].instance,
                &out_row[i]);

            select_list_[i].compiled->reset(&select_list_[i].instance);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                in_row.size(),
                in_row.data(),
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

      }

      select_level = fetch_level;
    } else {
      select_level = std::min(select_level, fetch_level);
    }

    for (const auto& col : columns_) {
      if (col.second.reader->maxRepetitionLevel() >= select_level) {
        in_row[col.second.index] = SValue();
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::scanWithoutColumns(
    Function<bool (int argc, const SValue* argv)> fn) {
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t total_records = cstable_.numRecords();
  for (size_t i = 0; i < total_records; ++i) {
    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(0, nullptr, &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->accumulate(
                &select_list_[i].instance,
                0,
                nullptr);
          }
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                0,
                nullptr,
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }
          break;
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::findColumns(
    RefPtr<ValueExpressionNode> expr,
    Set<String>* column_names) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    column_names->emplace(fieldref->fieldName());
  }

  for (const auto& e : expr->arguments()) {
    findColumns(e, column_names);
  }
}

void CSTableScan::resolveColumns(RefPtr<ValueExpressionNode> expr) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    fieldref->setColumnIndex(col->second.index);
  }

  for (const auto& e : expr->arguments()) {
    resolveColumns(e);
  }
}

uint64_t CSTableScan::findMaxRepetitionLevel(
    RefPtr<ValueExpressionNode> expr) const {
  uint64_t max_level = 0;

  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    auto col_level = col->second.reader->maxRepetitionLevel();
    if (col_level > max_level) {
      max_level = col_level;
    }
  }

  for (const auto& e : expr->arguments()) {
    auto e_level = findMaxRepetitionLevel(e);
    if (e_level > max_level) {
      max_level = e_level;
    }
  }

  return max_level;
}

Vector<String> CSTableScan::columnNames() const {
  return column_names_;
}

size_t CSTableScan::numColumns() const {
  return column_names_.size();
}

CSTableScan::ColumnRef::ColumnRef(
    RefPtr<cstable::ColumnReader> r,
    size_t i) :
    reader(r),
    index(i) {}

CSTableScan::ExpressionRef::ExpressionRef(
    size_t _rep_level,
    ScopedPtr<ValueExpression> _compiled,
    ScratchMemory* smem) :
    rep_level(_rep_level),
    compiled(std::move(_compiled)),
    instance(compiled->allocInstance(smem)) {}

CSTableScan::ExpressionRef::ExpressionRef(
    ExpressionRef&& other) :
    rep_level(other.rep_level),
    compiled(std::move(other.compiled)),
    instance(other.instance) {
  other.instance.scratch = nullptr;
}

CSTableScan::ExpressionRef::~ExpressionRef() {
  if (instance.scratch) {
    compiled->freeInstance(&instance);
  }
}

} // namespace csql
<|endoftext|>


<commit_before>/*
 * Copyright 2017, Max Planck Society.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/* Created by Edgar Klenske <edgar.klenske@tuebingen.mpg.de>
 */

#include "gaussian_process_guider.h"
#include "guide_performance_tools.h"

int main(int argc, char** argv)
{
    if (argc < 15)
        return -1;

    GaussianProcessGuider* GPG;

    GaussianProcessGuider::guide_parameters parameters;

    // use parameters from command line
    parameters.control_gain_ = std::stod(argv[2]);
    parameters.min_periods_for_inference_ = std::stod(argv[3]);
    parameters.min_move_ = std::stod(argv[4]);
    parameters.SE0KLengthScale_ = std::stod(argv[5]);
    parameters.SE0KSignalVariance_ = std::stod(argv[6]);
    parameters.PKLengthScale_ = std::stod(argv[7]);
    parameters.PKPeriodLength_ = std::stod(argv[8]);
    parameters.PKSignalVariance_ = std::stod(argv[9]);
    parameters.SE1KLengthScale_ = std::stod(argv[10]);
    parameters.SE1KSignalVariance_ = std::stod(argv[11]);
    parameters.min_periods_for_period_estimation_ = std::stod(argv[12]);
    parameters.points_for_approximation_ = std::floor(std::stod(argv[13]));
    parameters.prediction_gain_ = std::stod(argv[14]);
    parameters.compute_period_ = true;

    GPG = new GaussianProcessGuider(parameters);

    GAHysteresis GAH;

    std::string filename;

    filename = argv[1];
    double improvement = calculate_improvement(filename, GAH, GPG);

    std::cout << improvement << std::endl;

    return 0;
}
<commit_msg>fix compiler warning<commit_after>/*
 * Copyright 2017, Max Planck Society.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/* Created by Edgar Klenske <edgar.klenske@tuebingen.mpg.de>
 */

#include "gaussian_process_guider.h"
#include "guide_performance_tools.h"

int main(int argc, char** argv)
{
    if (argc < 15)
        return -1;

    GaussianProcessGuider* GPG;

    GaussianProcessGuider::guide_parameters parameters;

    // use parameters from command line
    parameters.control_gain_ = std::stod(argv[2]);
    parameters.min_periods_for_inference_ = std::stod(argv[3]);
    parameters.min_move_ = std::stod(argv[4]);
    parameters.SE0KLengthScale_ = std::stod(argv[5]);
    parameters.SE0KSignalVariance_ = std::stod(argv[6]);
    parameters.PKLengthScale_ = std::stod(argv[7]);
    parameters.PKPeriodLength_ = std::stod(argv[8]);
    parameters.PKSignalVariance_ = std::stod(argv[9]);
    parameters.SE1KLengthScale_ = std::stod(argv[10]);
    parameters.SE1KSignalVariance_ = std::stod(argv[11]);
    parameters.min_periods_for_period_estimation_ = std::stod(argv[12]);
    parameters.points_for_approximation_ = static_cast<int>(std::floor(std::stod(argv[13])));
    parameters.prediction_gain_ = std::stod(argv[14]);
    parameters.compute_period_ = true;

    GPG = new GaussianProcessGuider(parameters);

    GAHysteresis GAH;

    std::string filename;

    filename = argv[1];
    double improvement = calculate_improvement(filename, GAH, GPG);

    std::cout << improvement << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/extensions/extension_installed_bubble.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/location_bar_view.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/image_button.h"
#include "views/controls/label.h"
#include "views/standard_layout.h"
#include "views/view.h"

namespace {

const int kIconSize = 43;

const int kRightColumnWidth = 285;

// The InfoBubble uses a BubbleBorder which adds about 6 pixels of whitespace
// around the content view. We compensate by reducing our outer borders by this
// amount + 4px.
const int kOuterMarginInset = 10;
const int kHorizOuterMargin = kPanelHorizMargin - kOuterMarginInset;
const int kVertOuterMargin = kPanelVertMargin - kOuterMarginInset;

// Interior vertical margin is 8px smaller than standard
const int kVertInnerMargin = kPanelVertMargin - 8;

// The image we use for the close button has three pixels of whitespace padding.
const int kCloseButtonPadding = 3;

// We want to shift the right column (which contains the header and text) up
// 4px to align with icon.
const int kRightcolumnVerticalShift = -4;

// How long to wait for browser action animations to complete before retrying.
const int kAnimationWaitTime = 50;

// How often we retry when waiting for browser action animation to end.
const int kAnimationWaitMaxRetry = 10;

// InstalledBubbleContent is the content view which is placed in the
// ExtensionInstalledBubble. It displays the install icon and explanatory
// text about the installed extension.
class InstalledBubbleContent : public views::View,
                               public views::ButtonListener {
 public:
  InstalledBubbleContent(Extension* extension,
                         ExtensionInstalledBubble::BubbleType type,
                         SkBitmap* icon)
      : type_(type),
        info_(NULL) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont);

    // Scale down to 43x43, but allow smaller icons (don't scale up).
    gfx::Size size(icon->width(), icon->height());
    if (size.width() > kIconSize || size.height() > kIconSize)
      size = gfx::Size(kIconSize, kIconSize);
    icon_ = new views::ImageView();
    icon_->SetImageSize(size);
    icon_->SetImage(*icon);
    AddChildView(icon_);

    heading_ = new views::Label(
        l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_HEADING,
                              UTF8ToWide(extension->name())));
    heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL));
    heading_->SetMultiLine(true);
    heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    AddChildView(heading_);

    if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
      info_ = new views::Label(l10n_util::GetString(
          IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO));
      info_->SetFont(font);
      info_->SetMultiLine(true);
      info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
      AddChildView(info_);
    }

    manage_ = new views::Label(l10n_util::GetString(
      IDS_EXTENSION_INSTALLED_MANAGE_INFO));
    manage_->SetFont(font);
    manage_->SetMultiLine(true);
    manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    AddChildView(manage_);

    close_button_ = new views::ImageButton(this);
    close_button_->SetImage(views::CustomButton::BS_NORMAL,
        rb.GetBitmapNamed(IDR_CLOSE_BAR));
    close_button_->SetImage(views::CustomButton::BS_HOT,
        rb.GetBitmapNamed(IDR_CLOSE_BAR_H));
    close_button_->SetImage(views::CustomButton::BS_PUSHED,
        rb.GetBitmapNamed(IDR_CLOSE_BAR_P));
    AddChildView(close_button_);
  }

  virtual void ButtonPressed(
      views::Button* sender,
      const views::Event& event) {
    GetWidget()->Close();
  }

 private:
  virtual gfx::Size GetPreferredSize() {
    int width = kHorizOuterMargin;
    width += kIconSize;
    width += kPanelHorizMargin;
    width += kRightColumnWidth;
    width += 2*kPanelHorizMargin;
    width += kHorizOuterMargin;

    int height = kVertOuterMargin;
    height += heading_->GetHeightForWidth(kRightColumnWidth);
    height += kVertInnerMargin;
    if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
      height += info_->GetHeightForWidth(kRightColumnWidth);
      height += kVertInnerMargin;
    }
    height += manage_->GetHeightForWidth(kRightColumnWidth);
    height += kVertOuterMargin;
    return gfx::Size(width, std::max(height, kIconSize + 2 * kVertOuterMargin));
  }

  virtual void Layout() {
    int x = kHorizOuterMargin;
    int y = kVertOuterMargin;

    icon_->SetBounds(x, y, kIconSize, kIconSize);
    x += kIconSize;
    x += kPanelHorizMargin;

    y += kRightcolumnVerticalShift;
    heading_->SizeToFit(kRightColumnWidth);
    heading_->SetX(x);
    heading_->SetY(y);
    y += heading_->height();
    y += kVertInnerMargin;

    if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
      info_->SizeToFit(kRightColumnWidth);
      info_->SetX(x);
      info_->SetY(y);
      y += info_->height();
      y += kVertInnerMargin;
    }

    manage_->SizeToFit(kRightColumnWidth);
    manage_->SetX(x);
    manage_->SetY(y);

    x += kRightColumnWidth + 2*kPanelHorizMargin + kHorizOuterMargin -
        close_button_->GetPreferredSize().width();
    y = kVertOuterMargin;
    gfx::Size sz = close_button_->GetPreferredSize();
    // x-1 & y-1 is just slop to get the close button visually aligned with the
    // title text and bubble arrow.
    close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height());
}

  ExtensionInstalledBubble::BubbleType type_;
  views::ImageView* icon_;
  views::Label* heading_;
  views::Label* info_;
  views::Label* manage_;
  views::ImageButton* close_button_;

  DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent);
};

}  // namespace

void ExtensionInstalledBubble::Show(Extension *extension, Browser *browser,
                                    SkBitmap icon) {
  new ExtensionInstalledBubble(extension, browser, icon);
}

ExtensionInstalledBubble::ExtensionInstalledBubble(Extension *extension,
                                                   Browser *browser,
                                                   SkBitmap icon)
    : extension_(extension),
      browser_(browser),
      icon_(icon),
      animation_wait_retries_(0) {
  AddRef();  // Balanced in InfoBubbleClosing.

  if (extension_->browser_action()) {
    type_ = BROWSER_ACTION;
  } else if (extension->page_action() &&
             !extension->page_action()->default_icon_path().empty()) {
    type_ = PAGE_ACTION;
  } else {
    type_ = GENERIC;
  }

  // |extension| has been initialized but not loaded at this point. We need
  // to wait on showing the Bubble until not only the EXTENSION_LOADED gets
  // fired, but all of the EXTENSION_LOADED Observers have run. Only then can we
  // be sure that a BrowserAction or PageAction has had views created which we
  // can inspect for the purpose of previewing of pointing to them.
  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
      NotificationService::AllSources());
}

void ExtensionInstalledBubble::Observe(NotificationType type,
                                       const NotificationSource& source,
                                       const NotificationDetails& details) {
  if (type == NotificationType::EXTENSION_LOADED) {
    Extension* extension = Details<Extension>(details).ptr();
    if (extension == extension_) {
      animation_wait_retries_ = 0;
      // PostTask to ourself to allow all EXTENSION_LOADED Observers to run.
      MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
          &ExtensionInstalledBubble::ShowInternal));
    }
  } else {
    NOTREACHED() << L"Received unexpected notification";
  }
}

void ExtensionInstalledBubble::ShowInternal() {
  BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
      browser_->window()->GetNativeHandle());

  const views::View* reference_view = NULL;
  if (type_ == BROWSER_ACTION) {
    BrowserActionsContainer* container =
        browser_view->GetToolbarView()->browser_actions();
    if (container->animating() &&
        animation_wait_retries_++ < kAnimationWaitMaxRetry) {
      // We don't know where the view will be until the container has stopped
      // animating, so check back in a little while.
      MessageLoopForUI::current()->PostDelayedTask(
          FROM_HERE, NewRunnableMethod(this,
          &ExtensionInstalledBubble::ShowInternal), kAnimationWaitTime);
      return;
    }
    reference_view = container->GetBrowserActionView(extension_);
    // If the view is not visible then it is in the chevron, so point the
    // install bubble to the chevron instead.
    if (!reference_view->IsVisible())
      reference_view = container->chevron();
    DCHECK(reference_view);
  } else if (type_ == PAGE_ACTION) {
    LocationBarView* location_bar_view = browser_view->GetLocationBarView();
    location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
                                                   true);  // preview_enabled
    reference_view = location_bar_view->GetPageActionView(
        extension_->page_action());
    DCHECK(reference_view);
  }

  // Default case.
  if (reference_view == NULL)
    reference_view = browser_view->GetToolbarView()->app_menu();

  gfx::Point origin;
  views::View::ConvertPointToScreen(reference_view, &origin);
  gfx::Rect bounds = reference_view->bounds();
  bounds.set_x(origin.x());
  bounds.set_y(origin.y());

  views::View* bubble_content = new InstalledBubbleContent(extension_, type_,
      &icon_);
  InfoBubble::Show(browser_view->GetWindow(), bounds, bubble_content, this);
}

// InfoBubbleDelegate
void ExtensionInstalledBubble::InfoBubbleClosing(InfoBubble* info_bubble,
                                                 bool closed_by_escape) {
  if (extension_->page_action()) {
    BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
        browser_->window()->GetNativeHandle());
    browser_view->GetLocationBarView()->SetPreviewEnabledPageAction(
        extension_->page_action(),
        false);  // preview_enabled
  }
  Release();  // Balanced in ctor.
}
<commit_msg>Fix a crash when installing an extension from incognito mode.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/extensions/extension_installed_bubble.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/location_bar_view.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/image_button.h"
#include "views/controls/label.h"
#include "views/standard_layout.h"
#include "views/view.h"

namespace {

const int kIconSize = 43;

const int kRightColumnWidth = 285;

// The InfoBubble uses a BubbleBorder which adds about 6 pixels of whitespace
// around the content view. We compensate by reducing our outer borders by this
// amount + 4px.
const int kOuterMarginInset = 10;
const int kHorizOuterMargin = kPanelHorizMargin - kOuterMarginInset;
const int kVertOuterMargin = kPanelVertMargin - kOuterMarginInset;

// Interior vertical margin is 8px smaller than standard
const int kVertInnerMargin = kPanelVertMargin - 8;

// The image we use for the close button has three pixels of whitespace padding.
const int kCloseButtonPadding = 3;

// We want to shift the right column (which contains the header and text) up
// 4px to align with icon.
const int kRightcolumnVerticalShift = -4;

// How long to wait for browser action animations to complete before retrying.
const int kAnimationWaitTime = 50;

// How often we retry when waiting for browser action animation to end.
const int kAnimationWaitMaxRetry = 10;

// InstalledBubbleContent is the content view which is placed in the
// ExtensionInstalledBubble. It displays the install icon and explanatory
// text about the installed extension.
class InstalledBubbleContent : public views::View,
                               public views::ButtonListener {
 public:
  InstalledBubbleContent(Extension* extension,
                         ExtensionInstalledBubble::BubbleType type,
                         SkBitmap* icon)
      : type_(type),
        info_(NULL) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont);

    // Scale down to 43x43, but allow smaller icons (don't scale up).
    gfx::Size size(icon->width(), icon->height());
    if (size.width() > kIconSize || size.height() > kIconSize)
      size = gfx::Size(kIconSize, kIconSize);
    icon_ = new views::ImageView();
    icon_->SetImageSize(size);
    icon_->SetImage(*icon);
    AddChildView(icon_);

    heading_ = new views::Label(
        l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_HEADING,
                              UTF8ToWide(extension->name())));
    heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL));
    heading_->SetMultiLine(true);
    heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    AddChildView(heading_);

    if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
      info_ = new views::Label(l10n_util::GetString(
          IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO));
      info_->SetFont(font);
      info_->SetMultiLine(true);
      info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
      AddChildView(info_);
    }

    manage_ = new views::Label(l10n_util::GetString(
      IDS_EXTENSION_INSTALLED_MANAGE_INFO));
    manage_->SetFont(font);
    manage_->SetMultiLine(true);
    manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    AddChildView(manage_);

    close_button_ = new views::ImageButton(this);
    close_button_->SetImage(views::CustomButton::BS_NORMAL,
        rb.GetBitmapNamed(IDR_CLOSE_BAR));
    close_button_->SetImage(views::CustomButton::BS_HOT,
        rb.GetBitmapNamed(IDR_CLOSE_BAR_H));
    close_button_->SetImage(views::CustomButton::BS_PUSHED,
        rb.GetBitmapNamed(IDR_CLOSE_BAR_P));
    AddChildView(close_button_);
  }

  virtual void ButtonPressed(
      views::Button* sender,
      const views::Event& event) {
    GetWidget()->Close();
  }

 private:
  virtual gfx::Size GetPreferredSize() {
    int width = kHorizOuterMargin;
    width += kIconSize;
    width += kPanelHorizMargin;
    width += kRightColumnWidth;
    width += 2*kPanelHorizMargin;
    width += kHorizOuterMargin;

    int height = kVertOuterMargin;
    height += heading_->GetHeightForWidth(kRightColumnWidth);
    height += kVertInnerMargin;
    if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
      height += info_->GetHeightForWidth(kRightColumnWidth);
      height += kVertInnerMargin;
    }
    height += manage_->GetHeightForWidth(kRightColumnWidth);
    height += kVertOuterMargin;
    return gfx::Size(width, std::max(height, kIconSize + 2 * kVertOuterMargin));
  }

  virtual void Layout() {
    int x = kHorizOuterMargin;
    int y = kVertOuterMargin;

    icon_->SetBounds(x, y, kIconSize, kIconSize);
    x += kIconSize;
    x += kPanelHorizMargin;

    y += kRightcolumnVerticalShift;
    heading_->SizeToFit(kRightColumnWidth);
    heading_->SetX(x);
    heading_->SetY(y);
    y += heading_->height();
    y += kVertInnerMargin;

    if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
      info_->SizeToFit(kRightColumnWidth);
      info_->SetX(x);
      info_->SetY(y);
      y += info_->height();
      y += kVertInnerMargin;
    }

    manage_->SizeToFit(kRightColumnWidth);
    manage_->SetX(x);
    manage_->SetY(y);

    x += kRightColumnWidth + 2*kPanelHorizMargin + kHorizOuterMargin -
        close_button_->GetPreferredSize().width();
    y = kVertOuterMargin;
    gfx::Size sz = close_button_->GetPreferredSize();
    // x-1 & y-1 is just slop to get the close button visually aligned with the
    // title text and bubble arrow.
    close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height());
}

  ExtensionInstalledBubble::BubbleType type_;
  views::ImageView* icon_;
  views::Label* heading_;
  views::Label* info_;
  views::Label* manage_;
  views::ImageButton* close_button_;

  DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent);
};

}  // namespace

void ExtensionInstalledBubble::Show(Extension *extension, Browser *browser,
                                    SkBitmap icon) {
  new ExtensionInstalledBubble(extension, browser, icon);
}

ExtensionInstalledBubble::ExtensionInstalledBubble(Extension *extension,
                                                   Browser *browser,
                                                   SkBitmap icon)
    : extension_(extension),
      browser_(browser),
      icon_(icon),
      animation_wait_retries_(0) {
  AddRef();  // Balanced in InfoBubbleClosing.

  if (extension_->browser_action()) {
    type_ = BROWSER_ACTION;
  } else if (extension->page_action() &&
             !extension->page_action()->default_icon_path().empty()) {
    type_ = PAGE_ACTION;
  } else {
    type_ = GENERIC;
  }

  // |extension| has been initialized but not loaded at this point. We need
  // to wait on showing the Bubble until not only the EXTENSION_LOADED gets
  // fired, but all of the EXTENSION_LOADED Observers have run. Only then can we
  // be sure that a BrowserAction or PageAction has had views created which we
  // can inspect for the purpose of previewing of pointing to them.
  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
      NotificationService::AllSources());
}

void ExtensionInstalledBubble::Observe(NotificationType type,
                                       const NotificationSource& source,
                                       const NotificationDetails& details) {
  if (type == NotificationType::EXTENSION_LOADED) {
    Extension* extension = Details<Extension>(details).ptr();
    if (extension == extension_) {
      animation_wait_retries_ = 0;
      // PostTask to ourself to allow all EXTENSION_LOADED Observers to run.
      MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
          &ExtensionInstalledBubble::ShowInternal));
    }
  } else {
    NOTREACHED() << L"Received unexpected notification";
  }
}

void ExtensionInstalledBubble::ShowInternal() {
  BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
      browser_->window()->GetNativeHandle());

  const views::View* reference_view = NULL;
  if (type_ == BROWSER_ACTION) {
    BrowserActionsContainer* container =
        browser_view->GetToolbarView()->browser_actions();
    if (container->animating() &&
        animation_wait_retries_++ < kAnimationWaitMaxRetry) {
      // We don't know where the view will be until the container has stopped
      // animating, so check back in a little while.
      MessageLoopForUI::current()->PostDelayedTask(
          FROM_HERE, NewRunnableMethod(this,
          &ExtensionInstalledBubble::ShowInternal), kAnimationWaitTime);
      return;
    }
    reference_view = container->GetBrowserActionView(extension_);
    // If the view is not visible then it is in the chevron, so point the
    // install bubble to the chevron instead. If this is an incognito window,
    // both could be invisible.
    if (!reference_view || !reference_view->IsVisible()) {
      reference_view = container->chevron();
      if (!reference_view || !reference_view->IsVisible())
        reference_view = NULL;  // fall back to app menu below.
    }
  } else if (type_ == PAGE_ACTION) {
    LocationBarView* location_bar_view = browser_view->GetLocationBarView();
    location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
                                                   true);  // preview_enabled
    reference_view = location_bar_view->GetPageActionView(
        extension_->page_action());
    DCHECK(reference_view);
  }

  // Default case.
  if (reference_view == NULL)
    reference_view = browser_view->GetToolbarView()->app_menu();

  gfx::Point origin;
  views::View::ConvertPointToScreen(reference_view, &origin);
  gfx::Rect bounds = reference_view->bounds();
  bounds.set_x(origin.x());
  bounds.set_y(origin.y());

  views::View* bubble_content = new InstalledBubbleContent(extension_, type_,
      &icon_);
  InfoBubble::Show(browser_view->GetWindow(), bounds, bubble_content, this);
}

// InfoBubbleDelegate
void ExtensionInstalledBubble::InfoBubbleClosing(InfoBubble* info_bubble,
                                                 bool closed_by_escape) {
  if (extension_->page_action()) {
    BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
        browser_->window()->GetNativeHandle());
    browser_view->GetLocationBarView()->SetPreviewEnabledPageAction(
        extension_->page_action(),
        false);  // preview_enabled
  }
  Release();  // Balanced in ctor.
}
<|endoftext|>