<commit_before>#include "phune_rest_jamp.h"

static s3eCallback onResultPending;
static PhuneMatch *currentMatch = NULL;

static int32 onNullReturn(void *, void*){
	return 0;
}

static int32 onStartMatchReturn(void *data, void* userData){
	currentMatch = static_cast<PhuneMatch*>(data);
	onResultPending(NULL, userData);
	return 0;
}

int32 PhuneRestJamp::Init(s3eCallback onResult, s3eCallback onError, void *userData){
	return PhuneRest::Init(onResult, onError, userData);
}

int32 PhuneRestJamp::Login(s3eWebView* g_WebView, s3eCallback onResult, s3eCallback onError, void *userData){
	return PhuneRest::Login(g_WebView, onResult, onError, userData);
}

int32 PhuneRestJamp::GetMe(s3eCallback onResult, s3eCallback onError, void *userData){
	return PhuneRest::GetMe(onResult, onError, userData);
}

int32 PhuneRestJamp::StartMatch(JampGameId gameId, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);
	onResultPending = onResult;
	return PhuneRest::StartMatch(s.c_str(), onStartMatchReturn, onError, userData);
}

int32 PhuneRestJamp::EndMatch(JampGameId gameId, std::string level, JampScore score, PlayerStatus status, s3eCallback onResult, s3eCallback onError, void *userData){
    if (currentMatch == NULL){
        onError(NULL, NULL);
        return 0;
    }
    char buffer[50];
    sprintf(buffer, "%d", gameId);
    std::string s = std::string(buffer);

    std::string s3 = std::string(SCORE_LEVEL_KEY_PREFIX);
    s3.append(level);

    score.matchId = currentMatch->matchId;

    PhunePlayer player;
    player.score = score.score;
    player.status = status;
    player.id = currentMatch->playerId;

    int64 t = getCurrentTime();

    //Send the result of the match
    PhuneRest::EndMatch(score.matchId, player, onResult, onError, userData);

    IwTrace(PHUNE, ("Creating map begin"));
    std::map<int64, JsonListObject<JsonString> > map;
    int consecutivePerfects = 0;
    int bestSequence = -1;
    bool allPerfects = true;
    //aggregate cells performance
    for (std::vector<JampCellPerformance>::iterator it = score.cellsPerformance.elements.begin(); it != score.cellsPerformance.elements.end(); it++){

        //Use the notes for events
        if(it->useNoteEvaluation){
            for (std::vector<JampNotePerformance>::iterator it2 = it->notesPerformance.elements.begin(); it2 != it->notesPerformance.elements.end(); it2++){

                if (it2->classification == PERFECT) {
                    consecutivePerfects++;
                }
                else{
                    allPerfects = false;
                    if(consecutivePerfects > 3 && consecutivePerfects > bestSequence){
                        bestSequence = consecutivePerfects;
                    }
                    consecutivePerfects = 0;
                }
            }

        }
        //use the cell for events
        else{
            if (it->classification == PERFECT) {
                consecutivePerfects++;
            }
            else{
                allPerfects = false;
                if(consecutivePerfects > 3 && consecutivePerfects > bestSequence){
                    bestSequence = consecutivePerfects;
                }
                consecutivePerfects = 0;
            }
        }

        //found
        if (map.find(it->cellId) == map.end()) {
            JsonListObject<JsonString> list;
            it->timeStamp = t;
            JsonString js;
            js.Deserialize(it->Serialize());
            list.pushElement(js);
            map.insert(std::make_pair(it->cellId,list));
        }
        else {
            it->timeStamp = t;
            std::string aux2;
            JsonString js2;
            js2.Deserialize(it->Serialize());
            map.find(it->cellId)->second.pushElement(js2);
        }
    }

    if(consecutivePerfects > 3 && consecutivePerfects > bestSequence){
        bestSequence = consecutivePerfects;
    }

    IwTrace(PHUNE, ("Creating map end"));
    IwTrace(PHUNE, ("Sending cells begin"));
    //store the Cell performances
    for (std::map<int64, JsonListObject<JsonString> >::iterator itMap = map.begin(); itMap != map.end(); itMap++){

        if (itMap->first > 0) {

            char buffer4[50];
            sprintf(buffer4, "%s%lld", CELL_PERFORMACE_PREFIX, itMap->first);
            std::string key_cell = std::string(buffer4);

            std::string out = itMap->second.Serialize();

            IwTrace(PHUNE, ("Sending cell %lld begin", itMap->first));

            PhuneRestBase::StoreGameDataJsonBatch(s.c_str(), key_cell.c_str(), itMap->second.Serialize().c_str(), onNullReturn, onError, userData, true);

            IwTrace(PHUNE, ("Sending cell %lld end", itMap->first));
        }
        else{
            IwTrace(PHUNE, ("Cell with invalid id:%lld. Ignoring...", itMap->first));
        }

    }
    IwTrace(PHUNE, ("Sending cells end"));

    //Send the events

    JsonListObject<GameTriggerdEvent> events;

    //consecutive perfects
    if(bestSequence != -1){
        ConsecutivePerfectsEvent cpe(bestSequence, gameId);

        cpe.playerId = currentMatch->playerId;

        events.pushElement(cpe);
    }

    //all perfects
    if(allPerfects){
        AllPerfectsEvent ape(gameId, level);
        ape.playerId = currentMatch->playerId;

        events.pushElement(ape);
    }

    if(events.elements.size() > 0){
        PhuneRest::StoreMatchEvents(events, score.matchId, onNullReturn, onError);
    }

    //store the score for the match
    score.timeStamp = t;
    PhuneRestBase::StoreGameDataJson(s.c_str(), s3.c_str(), score.Serialize().c_str(), onNullReturn, onError, NULL, true);

    currentMatch = NULL;

	return 0;
}

int32 PhuneRestJamp::GetHistoricScoreForLevelInGame(JampGameId gameId, const char *level, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	std::string key_score = std::string(SCORE_LEVEL_KEY_PREFIX);
	key_score.append(level);
	return PhuneRestBase::GetGameDataJsonList(s.c_str(), key_score.c_str(), onResult, onError, userData);
}

int32 PhuneRestJamp::StorePackInfoInGame(JampGameId gameId, JampPack pack, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	char buffer2[50];
	sprintf(buffer2, "%s%d", PACK_PREFIX, gameId);
	std::string s2 = std::string(buffer2);

	return PhuneRestBase::StoreGameDataJson(s.c_str(), s2.c_str(), pack.Serialize().c_str(), onResult, onError, userData);
}

int32 PhuneRestJamp::GetPackInfoInGame(JampGameId gameId, int64 packid, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	char buffer2[50];
	sprintf(buffer2, "%s%d", PACK_PREFIX, gameId);
	std::string s2 = std::string(buffer2);

	return PhuneRestBase::GetGameDataJson(s.c_str(), s2.c_str(), onResult, onError, userData);
}

int32 PhuneRestJamp::StorePacksInGame(JampGameId gameId, JsonListObject<JampPack> packs, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

    int64 totalStars = 0;
    int64 starsWon = 0;

    for (std::vector<JampPack>::iterator it = packs.elements.begin(); it != packs.elements.end(); it++){
        totalStars += it->starsMax;
        starsWon += it->starsWon;
    }

    JampGameProgress gp;

    gp.progress = (starsWon/(float)totalStars)*100;

    PhuneRestBase::StoreGameDataJson(s.c_str(), GAME_PROGRESS_KEY, gp.Serialize().c_str(), onNullReturn, onError, NULL);

	return PhuneRestBase::StoreGameDataJsonList(s.c_str(), PACKS_KEY, packs, onResult, onError, userData);
}

int32 PhuneRestJamp::GetPacksInGame(JampGameId gameId, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	return PhuneRestBase::GetGameDataJsonList(s.c_str(), PACKS_KEY, onResult, onError, userData);
}
<commit_msg>JAMP: changed order in send package information<commit_after>#include "phune_rest_jamp.h"

static s3eCallback onResultPending;
static PhuneMatch *currentMatch = NULL;

static int32 onNullReturn(void *, void*){
	return 0;
}

static int32 onStartMatchReturn(void *data, void* userData){
	currentMatch = static_cast<PhuneMatch*>(data);
	onResultPending(NULL, userData);
	return 0;
}

int32 PhuneRestJamp::Init(s3eCallback onResult, s3eCallback onError, void *userData){
	return PhuneRest::Init(onResult, onError, userData);
}

int32 PhuneRestJamp::Login(s3eWebView* g_WebView, s3eCallback onResult, s3eCallback onError, void *userData){
	return PhuneRest::Login(g_WebView, onResult, onError, userData);
}

int32 PhuneRestJamp::GetMe(s3eCallback onResult, s3eCallback onError, void *userData){
	return PhuneRest::GetMe(onResult, onError, userData);
}

int32 PhuneRestJamp::StartMatch(JampGameId gameId, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);
	onResultPending = onResult;
	return PhuneRest::StartMatch(s.c_str(), onStartMatchReturn, onError, userData);
}

int32 PhuneRestJamp::EndMatch(JampGameId gameId, std::string level, JampScore score, PlayerStatus status, s3eCallback onResult, s3eCallback onError, void *userData){
    if (currentMatch == NULL){
        onError(NULL, NULL);
        return 0;
    }
    char buffer[50];
    sprintf(buffer, "%d", gameId);
    std::string s = std::string(buffer);

    std::string s3 = std::string(SCORE_LEVEL_KEY_PREFIX);
    s3.append(level);

    score.matchId = currentMatch->matchId;

    PhunePlayer player;
    player.score = score.score;
    player.status = status;
    player.id = currentMatch->playerId;

    int64 t = getCurrentTime();

    //Send the result of the match
    PhuneRest::EndMatch(score.matchId, player, onResult, onError, userData);

    IwTrace(PHUNE, ("Creating map begin"));
    std::map<int64, JsonListObject<JsonString> > map;
    int consecutivePerfects = 0;
    int bestSequence = -1;
    bool allPerfects = true;
    //aggregate cells performance
    for (std::vector<JampCellPerformance>::iterator it = score.cellsPerformance.elements.begin(); it != score.cellsPerformance.elements.end(); it++){

        //Use the notes for events
        if(it->useNoteEvaluation){
            for (std::vector<JampNotePerformance>::iterator it2 = it->notesPerformance.elements.begin(); it2 != it->notesPerformance.elements.end(); it2++){

                if (it2->classification == PERFECT) {
                    consecutivePerfects++;
                }
                else{
                    allPerfects = false;
                    if(consecutivePerfects > 3 && consecutivePerfects > bestSequence){
                        bestSequence = consecutivePerfects;
                    }
                    consecutivePerfects = 0;
                }
            }

        }
        //use the cell for events
        else{
            if (it->classification == PERFECT) {
                consecutivePerfects++;
            }
            else{
                allPerfects = false;
                if(consecutivePerfects > 3 && consecutivePerfects > bestSequence){
                    bestSequence = consecutivePerfects;
                }
                consecutivePerfects = 0;
            }
        }

        //found
        if (map.find(it->cellId) == map.end()) {
            JsonListObject<JsonString> list;
            it->timeStamp = t;
            JsonString js;
            js.Deserialize(it->Serialize());
            list.pushElement(js);
            map.insert(std::make_pair(it->cellId,list));
        }
        else {
            it->timeStamp = t;
            std::string aux2;
            JsonString js2;
            js2.Deserialize(it->Serialize());
            map.find(it->cellId)->second.pushElement(js2);
        }
    }

    if(consecutivePerfects > 3 && consecutivePerfects > bestSequence){
        bestSequence = consecutivePerfects;
    }

    IwTrace(PHUNE, ("Creating map end"));
    IwTrace(PHUNE, ("Sending cells begin"));
    //store the Cell performances
    for (std::map<int64, JsonListObject<JsonString> >::iterator itMap = map.begin(); itMap != map.end(); itMap++){

        if (itMap->first > 0) {

            char buffer4[50];
            sprintf(buffer4, "%s%lld", CELL_PERFORMACE_PREFIX, itMap->first);
            std::string key_cell = std::string(buffer4);

            std::string out = itMap->second.Serialize();

            IwTrace(PHUNE, ("Sending cell %lld begin", itMap->first));

            PhuneRestBase::StoreGameDataJsonBatch(s.c_str(), key_cell.c_str(), itMap->second.Serialize().c_str(), onNullReturn, onError, userData, true);

            IwTrace(PHUNE, ("Sending cell %lld end", itMap->first));
        }
        else{
            IwTrace(PHUNE, ("Cell with invalid id:%lld. Ignoring...", itMap->first));
        }

    }
    IwTrace(PHUNE, ("Sending cells end"));

    //Send the events

    JsonListObject<GameTriggerdEvent> events;

    //consecutive perfects
    if(bestSequence != -1){
        ConsecutivePerfectsEvent cpe(bestSequence, gameId);

        cpe.playerId = currentMatch->playerId;

        events.pushElement(cpe);
    }

    //all perfects
    if(allPerfects){
        AllPerfectsEvent ape(gameId, level);
        ape.playerId = currentMatch->playerId;

        events.pushElement(ape);
    }

    if(events.elements.size() > 0){
        PhuneRest::StoreMatchEvents(events, score.matchId, onNullReturn, onError);
    }

    //store the score for the match
    score.timeStamp = t;
    PhuneRestBase::StoreGameDataJson(s.c_str(), s3.c_str(), score.Serialize().c_str(), onNullReturn, onError, NULL, true);

    currentMatch = NULL;

	return 0;
}

int32 PhuneRestJamp::GetHistoricScoreForLevelInGame(JampGameId gameId, const char *level, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	std::string key_score = std::string(SCORE_LEVEL_KEY_PREFIX);
	key_score.append(level);
	return PhuneRestBase::GetGameDataJsonList(s.c_str(), key_score.c_str(), onResult, onError, userData);
}

int32 PhuneRestJamp::StorePackInfoInGame(JampGameId gameId, JampPack pack, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	char buffer2[50];
	sprintf(buffer2, "%s%d", PACK_PREFIX, gameId);
	std::string s2 = std::string(buffer2);

	return PhuneRestBase::StoreGameDataJson(s.c_str(), s2.c_str(), pack.Serialize().c_str(), onResult, onError, userData);
}

int32 PhuneRestJamp::GetPackInfoInGame(JampGameId gameId, int64 packid, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	char buffer2[50];
	sprintf(buffer2, "%s%d", PACK_PREFIX, gameId);
	std::string s2 = std::string(buffer2);

	return PhuneRestBase::GetGameDataJson(s.c_str(), s2.c_str(), onResult, onError, userData);
}

int32 PhuneRestJamp::StorePacksInGame(JampGameId gameId, JsonListObject<JampPack> packs, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

    int64 totalStars = 0;
    int64 starsWon = 0;

    for (std::vector<JampPack>::iterator it = packs.elements.begin(); it != packs.elements.end(); it++){
        totalStars += it->starsMax;
        starsWon += it->starsWon;
    }

    JampGameProgress gp;

    gp.progress = (starsWon/(float)totalStars)*100;

    PhuneRestBase::StoreGameDataJsonList(s.c_str(), PACKS_KEY, packs, onResult, onError, userData);

    PhuneRestBase::StoreGameDataJson(s.c_str(), GAME_PROGRESS_KEY, gp.Serialize().c_str(), onNullReturn, onError, NULL, false);

    return 0;
}

int32 PhuneRestJamp::GetPacksInGame(JampGameId gameId, s3eCallback onResult, s3eCallback onError, void *userData){
	char buffer[50];
	sprintf(buffer, "%d", gameId);
	std::string s = std::string(buffer);

	return PhuneRestBase::GetGameDataJsonList(s.c_str(), PACKS_KEY, onResult, onError, userData);
}
<|endoftext|>


<commit_before>#include "xchainer/python/array.h"

#include <algorithm>

#include <pybind11/numpy.h>

#include "xchainer/array.h"
#include "xchainer/dtype.h"
#include "xchainer/error.h"

namespace xchainer {

namespace py = pybind11;

Dtype NumpyDtypeToDtype(py::dtype npdtype) {
    switch (npdtype.kind()) {
        case 'b':
            return Dtype::kBool;
        case 'i':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kInt8;
                case 2:
                    return Dtype::kInt16;
                case 4:
                    return Dtype::kInt32;
                case 8:
                    return Dtype::kInt64;
                default:
                    break;
            }
            break;
        case 'u':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kUInt8;
                default:
                    break;
            }
            break;
        case 'f':
            switch (npdtype.itemsize()) {
                case 4:
                    return Dtype::kFloat32;
                case 8:
                    return Dtype::kFloat64;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    throw DtypeError("unsupported NumPy dtype");
}

Array MakeArrayFromList(const Shape& shape, Dtype dtype, py::list list) {
    auto total_size = shape.total_size();
    auto bytes = GetElementSize(dtype) * total_size;
    if (static_cast<size_t>(total_size) != list.size()) {
        throw DimensionError("Invalid data length");
    }

    std::shared_ptr<void> ptr = std::make_unique<uint8_t[]>(bytes);
    auto func = [&](auto dummy) {
        using T = decltype(dummy);
        std::transform(list.begin(), list.end(), reinterpret_cast<T*>(ptr.get()), [](auto& item) { return py::cast<T>(item); });
    };
    switch (dtype) {
        case Dtype::kBool:
            func(static_cast<bool>(0));
            break;
        case Dtype::kInt8:
            func(static_cast<int8_t>(0));
            break;
        case Dtype::kInt16:
            func(static_cast<int16_t>(0));
            break;
        case Dtype::kInt32:
            func(static_cast<int32_t>(0));
            break;
        case Dtype::kInt64:
            func(static_cast<int64_t>(0));
            break;
        case Dtype::kUInt8:
            func(static_cast<uint8_t>(0));
            break;
        case Dtype::kFloat32:
            func(static_cast<float>(0));
            break;
        case Dtype::kFloat64:
            func(static_cast<double>(0));
            break;
        default:
            assert(0);
    }
    return Array{shape, dtype, ptr};
}

std::unique_ptr<Array> MakeArrayFromNumpyArray(py::array array) {
    if (!(array.flags() & py::array::c_style)) {
        throw DimensionError("cannot convert non-contiguous NumPy array to Array");
    }

    // TODO(hvy): When Unified Memory Array creation and its Python binding is in-place, create the Array on the correct device
    Dtype dtype = NumpyDtypeToDtype(array.dtype());
    py::buffer_info info = array.request();
    Shape shape(info.shape);
    std::shared_ptr<void> data(std::make_shared<py::array>(std::move(array)), array.mutable_data());

    return std::make_unique<Array>(shape, dtype, data);
}

void InitXchainerArray(pybind11::module& m) {
    py::class_<Array>{m, "Array"}
        .def(py::init(&MakeArrayFromList))
        .def(py::init(&MakeArrayFromNumpyArray))
        .def("__repr__", static_cast<std::string (Array::*)() const>(&Array::ToString))
        .def_property_readonly("dtype", &Array::dtype)
        .def_property_readonly("shape", &Array::shape)
        .def_property_readonly("is_contiguous", &Array::is_contiguous)
        .def_property_readonly("total_size", &Array::total_size)
        .def_property_readonly("element_bytes", &Array::element_bytes)
        .def_property_readonly("total_bytes", &Array::total_bytes)
        .def_property_readonly("offset", &Array::offset)
        .def_property_readonly("debug_flat_data",
                               [](const Array& self) {  // This method is a stub for testing
                                   py::list list;
                                   auto size = self.total_size();
                                   auto func = [&](auto dummy) {
                                       using T = decltype(dummy);
                                       const T& data = *std::static_pointer_cast<const T>(self.data());
                                       for (int64_t i = 0; i < size; ++i) {
                                           list.append((&data)[i]);
                                       }
                                   };
                                   switch (self.dtype()) {
                                       case Dtype::kBool:
                                           func(static_cast<bool>(0));
                                           break;
                                       case Dtype::kInt8:
                                           func(static_cast<int8_t>(0));
                                           break;
                                       case Dtype::kInt16:
                                           func(static_cast<int16_t>(0));
                                           break;
                                       case Dtype::kInt32:
                                           func(static_cast<int32_t>(0));
                                           break;
                                       case Dtype::kInt64:
                                           func(static_cast<int64_t>(0));
                                           break;
                                       case Dtype::kUInt8:
                                           func(static_cast<uint8_t>(0));
                                           break;
                                       case Dtype::kFloat32:
                                           func(static_cast<float>(0));
                                           break;
                                       case Dtype::kFloat64:
                                           func(static_cast<double>(0));
                                           break;
                                       default:
                                           assert(0);
                                   }
                                   return list;
                               })
        .def("__add__", static_cast<Array (Array::*)(const Array&) const>(&Array::Add))
        .def("__iadd__", static_cast<Array& (Array::*)(const Array&)>(&Array::IAdd))
        .def("__mul__", static_cast<Array (Array::*)(const Array&) const>(&Array::Mul))
        .def("__imul__", static_cast<Array& (Array::*)(const Array&)>(&Array::IMul));
}

}  // namespace xchainer
<commit_msg>Add pybind comment<commit_after>#include "xchainer/python/array.h"

#include <algorithm>

#include <pybind11/numpy.h>

#include "xchainer/array.h"
#include "xchainer/dtype.h"
#include "xchainer/error.h"

namespace xchainer {

namespace py = pybind11;

Dtype NumpyDtypeToDtype(py::dtype npdtype) {
    switch (npdtype.kind()) {
        case 'b':
            return Dtype::kBool;
        case 'i':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kInt8;
                case 2:
                    return Dtype::kInt16;
                case 4:
                    return Dtype::kInt32;
                case 8:
                    return Dtype::kInt64;
                default:
                    break;
            }
            break;
        case 'u':
            switch (npdtype.itemsize()) {
                case 1:
                    return Dtype::kUInt8;
                default:
                    break;
            }
            break;
        case 'f':
            switch (npdtype.itemsize()) {
                case 4:
                    return Dtype::kFloat32;
                case 8:
                    return Dtype::kFloat64;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    throw DtypeError("unsupported NumPy dtype");
}

Array MakeArrayFromList(const Shape& shape, Dtype dtype, py::list list) {
    auto total_size = shape.total_size();
    auto bytes = GetElementSize(dtype) * total_size;
    if (static_cast<size_t>(total_size) != list.size()) {
        throw DimensionError("Invalid data length");
    }

    std::shared_ptr<void> ptr = std::make_unique<uint8_t[]>(bytes);
    auto func = [&](auto dummy) {
        using T = decltype(dummy);
        std::transform(list.begin(), list.end(), reinterpret_cast<T*>(ptr.get()), [](auto& item) { return py::cast<T>(item); });
    };
    switch (dtype) {
        case Dtype::kBool:
            func(static_cast<bool>(0));
            break;
        case Dtype::kInt8:
            func(static_cast<int8_t>(0));
            break;
        case Dtype::kInt16:
            func(static_cast<int16_t>(0));
            break;
        case Dtype::kInt32:
            func(static_cast<int32_t>(0));
            break;
        case Dtype::kInt64:
            func(static_cast<int64_t>(0));
            break;
        case Dtype::kUInt8:
            func(static_cast<uint8_t>(0));
            break;
        case Dtype::kFloat32:
            func(static_cast<float>(0));
            break;
        case Dtype::kFloat64:
            func(static_cast<double>(0));
            break;
        default:
            assert(0);
    }
    return Array{shape, dtype, ptr};
}

std::unique_ptr<Array> MakeArrayFromNumpyArray(py::array array) {
    if (!(array.flags() & py::array::c_style)) {
        throw DimensionError("cannot convert non-contiguous NumPy array to Array");
    }

    // TODO(hvy): When Unified Memory Array creation and its Python binding is in-place, create the Array on the correct device
    Dtype dtype = NumpyDtypeToDtype(array.dtype());
    py::buffer_info info = array.request();
    Shape shape(info.shape);

    // Assuming pybind increases the reference count to the underlying NumPy object, we choose not to copy the data
    std::shared_ptr<void> data(std::make_shared<py::array>(std::move(array)), array.mutable_data());

    return std::make_unique<Array>(shape, dtype, data);
}

void InitXchainerArray(pybind11::module& m) {
    py::class_<Array>{m, "Array"}
        .def(py::init(&MakeArrayFromList))
        .def(py::init(&MakeArrayFromNumpyArray))
        .def("__repr__", static_cast<std::string (Array::*)() const>(&Array::ToString))
        .def_property_readonly("dtype", &Array::dtype)
        .def_property_readonly("shape", &Array::shape)
        .def_property_readonly("is_contiguous", &Array::is_contiguous)
        .def_property_readonly("total_size", &Array::total_size)
        .def_property_readonly("element_bytes", &Array::element_bytes)
        .def_property_readonly("total_bytes", &Array::total_bytes)
        .def_property_readonly("offset", &Array::offset)
        .def_property_readonly("debug_flat_data",
                               [](const Array& self) {  // This method is a stub for testing
                                   py::list list;
                                   auto size = self.total_size();
                                   auto func = [&](auto dummy) {
                                       using T = decltype(dummy);
                                       const T& data = *std::static_pointer_cast<const T>(self.data());
                                       for (int64_t i = 0; i < size; ++i) {
                                           list.append((&data)[i]);
                                       }
                                   };
                                   switch (self.dtype()) {
                                       case Dtype::kBool:
                                           func(static_cast<bool>(0));
                                           break;
                                       case Dtype::kInt8:
                                           func(static_cast<int8_t>(0));
                                           break;
                                       case Dtype::kInt16:
                                           func(static_cast<int16_t>(0));
                                           break;
                                       case Dtype::kInt32:
                                           func(static_cast<int32_t>(0));
                                           break;
                                       case Dtype::kInt64:
                                           func(static_cast<int64_t>(0));
                                           break;
                                       case Dtype::kUInt8:
                                           func(static_cast<uint8_t>(0));
                                           break;
                                       case Dtype::kFloat32:
                                           func(static_cast<float>(0));
                                           break;
                                       case Dtype::kFloat64:
                                           func(static_cast<double>(0));
                                           break;
                                       default:
                                           assert(0);
                                   }
                                   return list;
                               })
        .def("__add__", static_cast<Array (Array::*)(const Array&) const>(&Array::Add))
        .def("__iadd__", static_cast<Array& (Array::*)(const Array&)>(&Array::IAdd))
        .def("__mul__", static_cast<Array (Array::*)(const Array&) const>(&Array::Mul))
        .def("__imul__", static_cast<Array& (Array::*)(const Array&)>(&Array::IMul));
}

}  // namespace xchainer
<|endoftext|>


<commit_before>#include "xchainer/python/shape.h"

#include <algorithm>

#include <pybind11/operators.h>

#include "xchainer/shape.h"

#include "xchainer/python/common.h"

namespace xchainer {

namespace py = pybind11;

void InitXchainerShape(pybind11::module& m) {
    py::class_<Shape>{m, "Shape"}
            .def(py::init([](py::tuple tup) {  // __init__ by a tuple
                std::vector<int64_t> v;
                std::transform(tup.begin(), tup.end(), std::back_inserter(v), [](auto& item) { return py::cast<int64_t>(item); });
                return Shape(v);
            }))
            .def(py::self == py::self)  // NOLINT
            .def("__eq__",              // Equality with a tuple
                 [](const Shape& self, const py::tuple& tup) {
                     if (static_cast<size_t>(self.ndim()) != tup.size()) {
                         return false;
                     }
                     try {
                         return std::equal(self.begin(), self.end(), tup.begin(), tup.end(), [](const auto& dim, const auto& item) {
                             int64_t dim2 = py::cast<int64_t>(item);
                             return dim == dim2;
                         });
                     } catch (const py::cast_error& e) {
                         return false;
                     }
                 })
            .def("__repr__", static_cast<std::string (Shape::*)() const>(&Shape::ToString))
            .def_property_readonly("ndim", &Shape::ndim)
            .def_property_readonly("total_size", &Shape::GetTotalSize);

    py::implicitly_convertible<py::tuple, Shape>();
}

}  // namespace xchainer
<commit_msg>xchainer/python/shape.cc:18:  Add #include <vector> for vector<>  [build/include_what_you_use] [4] xchainer/python/shape.cc:37:  Add #include <string> for string  [build/include_what_you_use] [4]<commit_after>#include "xchainer/python/shape.h"

#include <algorithm>
#include <string>
#include <vector>

#include <pybind11/operators.h>

#include "xchainer/shape.h"

#include "xchainer/python/common.h"

namespace xchainer {

namespace py = pybind11;

void InitXchainerShape(pybind11::module& m) {
    py::class_<Shape>{m, "Shape"}
            .def(py::init([](py::tuple tup) {  // __init__ by a tuple
                std::vector<int64_t> v;
                std::transform(tup.begin(), tup.end(), std::back_inserter(v), [](auto& item) { return py::cast<int64_t>(item); });
                return Shape(v);
            }))
            .def(py::self == py::self)  // NOLINT
            .def("__eq__",              // Equality with a tuple
                 [](const Shape& self, const py::tuple& tup) {
                     if (static_cast<size_t>(self.ndim()) != tup.size()) {
                         return false;
                     }
                     try {
                         return std::equal(self.begin(), self.end(), tup.begin(), tup.end(), [](const auto& dim, const auto& item) {
                             int64_t dim2 = py::cast<int64_t>(item);
                             return dim == dim2;
                         });
                     } catch (const py::cast_error& e) {
                         return false;
                     }
                 })
            .def("__repr__", static_cast<std::string (Shape::*)() const>(&Shape::ToString))
            .def_property_readonly("ndim", &Shape::ndim)
            .def_property_readonly("total_size", &Shape::GetTotalSize);

    py::implicitly_convertible<py::tuple, Shape>();
}

}  // namespace xchainer
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "basefilefind.h"

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/filemanager.h>
#include <find/textfindconstants.h>
#include <find/searchresultwindow.h>
#include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h>
#include <utils/stylehelper.h>

#include <QtCore/QDebug>
#include <QtCore/QDirIterator>
#include <QtCore/QSettings>
#include <QtGui/QFileDialog>
#include <QtGui/QCheckBox>
#include <QtGui/QComboBox>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QTextBlock>

using namespace Utils;
using namespace Find;
using namespace TextEditor;

BaseFileFind::BaseFileFind(SearchResultWindow *resultWindow)
  : m_resultWindow(resultWindow),
    m_isSearching(false),
    m_resultLabel(0),
    m_filterCombo(0)
{
    m_watcher.setPendingResultsLimit(1);
    connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
    connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
}

bool BaseFileFind::isEnabled() const
{
    return !m_isSearching;
}

bool BaseFileFind::canCancel() const
{
    return m_isSearching;
}

void BaseFileFind::cancel()
{
    m_watcher.cancel();
}

QStringList BaseFileFind::fileNameFilters() const
{
    QStringList filters;
    if (m_filterCombo && !m_filterCombo->currentText().isEmpty()) {
        const QStringList parts = m_filterCombo->currentText().split(QLatin1Char(','));
        foreach (const QString &part, parts) {
            const QString filter = part.trimmed();
            if (!filter.isEmpty()) {
                filters << filter;
            }
        }
    }
    return filters;
}

void BaseFileFind::findAll(const QString &txt, Find::FindFlags findFlags)
{
    m_isSearching = true;
    emit changed();
    if (m_filterCombo)
        updateComboEntries(m_filterCombo, true);
    m_watcher.setFuture(QFuture<FileSearchResultList>());
    SearchResult *result = m_resultWindow->startNewSearch();
    connect(result, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem)));
    m_resultWindow->popup(true);
    if (findFlags & Find::FindRegularExpression) {
        m_watcher.setFuture(Utils::findInFilesRegExp(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    } else {
        m_watcher.setFuture(Utils::findInFiles(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    }
    Core::FutureProgress *progress =
        Core::ICore::instance()->progressManager()->addTask(m_watcher.future(),
                                                                        "Search",
                                                                        Constants::TASK_SEARCH);
    progress->setWidget(createProgressWidget());
    connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
}

void BaseFileFind::replaceAll(const QString &txt, Find::FindFlags findFlags)
{
    m_isSearching = true;
    emit changed();
    if (m_filterCombo)
        updateComboEntries(m_filterCombo, true);
    m_watcher.setFuture(QFuture<FileSearchResultList>());
    SearchResult *result = m_resultWindow->startNewSearch(SearchResultWindow::SearchAndReplace);
    connect(result, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem)));
    connect(result, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
            this, SLOT(doReplace(QString,QList<Find::SearchResultItem>)));
    m_resultWindow->popup(true);
    if (findFlags & Find::FindRegularExpression) {
        m_watcher.setFuture(Utils::findInFilesRegExp(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    } else {
        m_watcher.setFuture(Utils::findInFiles(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    }
    Core::FutureProgress *progress =
        Core::ICore::instance()->progressManager()->addTask(m_watcher.future(),
                                                                        "Search",
                                                                        Constants::TASK_SEARCH);
    progress->setWidget(createProgressWidget());
    connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
}

void BaseFileFind::doReplace(const QString &text,
                               const QList<Find::SearchResultItem> &items)
{
    QStringList files = replaceAll(text, items);
    Core::FileManager *fileManager = Core::ICore::instance()->fileManager();
    if (!files.isEmpty()) {
        fileManager->notifyFilesChangedInternally(files);
        m_resultWindow->hide();
    }
}

void BaseFileFind::displayResult(int index) {
    Utils::FileSearchResultList results = m_watcher.future().resultAt(index);
    QList<Find::SearchResultItem> items; // this conversion is stupid...
    foreach (const Utils::FileSearchResult &result, results) {
        Find::SearchResultItem item;
        item.path = QStringList() << QDir::toNativeSeparators(result.fileName);
        item.lineNumber = result.lineNumber;
        item.text = result.matchingLine;
        item.textMarkLength = result.matchLength;
        item.textMarkPos = result.matchStart;
        item.useTextEditorFont = true;
        item.userData = result.regexpCapturedTexts;
        items << item;
    }
    m_resultWindow->addResults(items, Find::SearchResultWindow::AddOrdered);
    if (m_resultLabel)
        m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
}

void BaseFileFind::searchFinished()
{
    m_resultWindow->finishSearch();
    m_isSearching = false;
    m_resultLabel = 0;
    emit changed();
}

QWidget *BaseFileFind::createProgressWidget()
{
    m_resultLabel = new QLabel;
    m_resultLabel->setAlignment(Qt::AlignCenter);
    // ### TODO this setup should be done by style
    QFont f = m_resultLabel->font();
    f.setBold(true);
    f.setPointSizeF(StyleHelper::sidebarFontSize());
    m_resultLabel->setFont(f);
    m_resultLabel->setPalette(StyleHelper::sidebarFontPalette(m_resultLabel->palette()));
    m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
    return m_resultLabel;
}

QWidget *BaseFileFind::createPatternWidget()
{
    QString filterToolTip = tr("List of comma separated wildcard filters");
    m_filterCombo = new QComboBox;
    m_filterCombo->setEditable(true);
    m_filterCombo->setModel(&m_filterStrings);
    m_filterCombo->setMaxCount(10);
    m_filterCombo->setMinimumContentsLength(10);
    m_filterCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
    m_filterCombo->setInsertPolicy(QComboBox::InsertAtBottom);
    m_filterCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    m_filterCombo->setToolTip(filterToolTip);
    syncComboWithSettings(m_filterCombo, m_filterSetting);
    return m_filterCombo;
}

void BaseFileFind::writeCommonSettings(QSettings *settings)
{
    settings->setValue("filters", m_filterStrings.stringList());
    if (m_filterCombo)
        settings->setValue("currentFilter", m_filterCombo->currentText());
}

void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter)
{
    QStringList filters = settings->value("filters").toStringList();
    m_filterSetting = settings->value("currentFilter").toString();
    if (filters.isEmpty())
        filters << defaultFilter;
    if (m_filterSetting.isEmpty())
        m_filterSetting = filters.first();
    m_filterStrings.setStringList(filters);
    if (m_filterCombo)
        syncComboWithSettings(m_filterCombo, m_filterSetting);
}

void BaseFileFind::syncComboWithSettings(QComboBox *combo, const QString &setting)
{
    if (!combo)
        return;
    int index = combo->findText(setting);
    if (index < 0)
        combo->setEditText(setting);
    else
        combo->setCurrentIndex(index);
}

void BaseFileFind::updateComboEntries(QComboBox *combo, bool onTop)
{
    int index = combo->findText(combo->currentText());
    if (index < 0) {
        if (onTop) {
            combo->insertItem(0, combo->currentText());
        } else {
            combo->addItem(combo->currentText());
        }
        combo->setCurrentIndex(combo->findText(combo->currentText()));
    }
}

void BaseFileFind::openEditor(const Find::SearchResultItem &item)
{
    if (item.path.size() > 0) {
        TextEditor::BaseTextEditor::openEditorAt(item.path.first(), item.lineNumber, item.textMarkPos,
                                                 QString(), Core::EditorManager::ModeSwitch);
    } else {
        Core::EditorManager::instance()->openEditor(item.text, QString(), Core::EditorManager::ModeSwitch);
    }
}

// #pragma mark Static methods

static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
{
    QList<QPair<QTextCursor, QString> > changes;

    foreach (const Find::SearchResultItem &item, items) {
        const int blockNumber = item.lineNumber - 1;
        QTextCursor tc(doc->findBlockByNumber(blockNumber));

        const int cursorPosition = tc.position() + item.textMarkPos;

        int cursorIndex = 0;
        for (; cursorIndex < changes.size(); ++cursorIndex) {
            const QTextCursor &otherTc = changes.at(cursorIndex).first;

            if (otherTc.position() == cursorPosition)
                break;
        }

        if (cursorIndex != changes.size())
            continue; // skip this change.

        tc.setPosition(cursorPosition);
        tc.setPosition(tc.position() + item.textMarkLength,
                       QTextCursor::KeepAnchor);
        QString substitutionText;
        if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty())
            substitutionText = Utils::expandRegExpReplacement(text, item.userData.toStringList());
        else
            substitutionText = text;
        changes.append(QPair<QTextCursor, QString>(tc, substitutionText));
    }

    for (int i = 0; i < changes.size(); ++i) {
        QPair<QTextCursor, QString> &cursor = changes[i];
        cursor.first.insertText(cursor.second);
    }
}

QStringList BaseFileFind::replaceAll(const QString &text,
                               const QList<Find::SearchResultItem> &items)
{
    if (text.isEmpty() || items.isEmpty())
        return QStringList();

    QHash<QString, QList<Find::SearchResultItem> > changes;

    foreach (const Find::SearchResultItem &item, items)
        changes[item.path.first()].append(item);

    Core::EditorManager *editorManager = Core::EditorManager::instance();

    QHashIterator<QString, QList<Find::SearchResultItem> > it(changes);
    while (it.hasNext()) {
        it.next();

        const QString fileName = it.key();
        const QList<Find::SearchResultItem> changeItems = it.value();

        const QList<Core::IEditor *> editors = editorManager->editorsForFileName(fileName);
        TextEditor::BaseTextEditor *textEditor = 0;
        foreach (Core::IEditor *editor, editors) {
            textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
            if (textEditor != 0)
                break;
        }

        if (textEditor != 0) {
            QTextCursor tc = textEditor->textCursor();
            tc.beginEditBlock();
            applyChanges(textEditor->document(), text, changeItems);
            tc.endEditBlock();
        } else {
            QFile file(fileName);

            if (file.open(QFile::ReadOnly)) {
                QTextStream stream(&file);
                // ### set the encoding
                const QString plainText = stream.readAll();
                file.close();

                QTextDocument doc;
                doc.setPlainText(plainText);

                applyChanges(&doc, text, changeItems);

                QFile newFile(fileName);
                if (newFile.open(QFile::WriteOnly)) {
                    QTextStream stream(&newFile);
                    // ### set the encoding
                    stream << doc.toPlainText();
                }
            }
        }
    }

    return changes.keys();
}
<commit_msg>Open files from search result list with right encoding, even on Windows.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "basefilefind.h"

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/filemanager.h>
#include <find/textfindconstants.h>
#include <find/searchresultwindow.h>
#include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h>
#include <utils/stylehelper.h>

#include <QtCore/QDebug>
#include <QtCore/QDirIterator>
#include <QtCore/QSettings>
#include <QtGui/QFileDialog>
#include <QtGui/QCheckBox>
#include <QtGui/QComboBox>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QTextBlock>

using namespace Utils;
using namespace Find;
using namespace TextEditor;

BaseFileFind::BaseFileFind(SearchResultWindow *resultWindow)
  : m_resultWindow(resultWindow),
    m_isSearching(false),
    m_resultLabel(0),
    m_filterCombo(0)
{
    m_watcher.setPendingResultsLimit(1);
    connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
    connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
}

bool BaseFileFind::isEnabled() const
{
    return !m_isSearching;
}

bool BaseFileFind::canCancel() const
{
    return m_isSearching;
}

void BaseFileFind::cancel()
{
    m_watcher.cancel();
}

QStringList BaseFileFind::fileNameFilters() const
{
    QStringList filters;
    if (m_filterCombo && !m_filterCombo->currentText().isEmpty()) {
        const QStringList parts = m_filterCombo->currentText().split(QLatin1Char(','));
        foreach (const QString &part, parts) {
            const QString filter = part.trimmed();
            if (!filter.isEmpty()) {
                filters << filter;
            }
        }
    }
    return filters;
}

void BaseFileFind::findAll(const QString &txt, Find::FindFlags findFlags)
{
    m_isSearching = true;
    emit changed();
    if (m_filterCombo)
        updateComboEntries(m_filterCombo, true);
    m_watcher.setFuture(QFuture<FileSearchResultList>());
    SearchResult *result = m_resultWindow->startNewSearch();
    connect(result, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem)));
    m_resultWindow->popup(true);
    if (findFlags & Find::FindRegularExpression) {
        m_watcher.setFuture(Utils::findInFilesRegExp(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    } else {
        m_watcher.setFuture(Utils::findInFiles(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    }
    Core::FutureProgress *progress =
        Core::ICore::instance()->progressManager()->addTask(m_watcher.future(),
                                                                        "Search",
                                                                        Constants::TASK_SEARCH);
    progress->setWidget(createProgressWidget());
    connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
}

void BaseFileFind::replaceAll(const QString &txt, Find::FindFlags findFlags)
{
    m_isSearching = true;
    emit changed();
    if (m_filterCombo)
        updateComboEntries(m_filterCombo, true);
    m_watcher.setFuture(QFuture<FileSearchResultList>());
    SearchResult *result = m_resultWindow->startNewSearch(SearchResultWindow::SearchAndReplace);
    connect(result, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem)));
    connect(result, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
            this, SLOT(doReplace(QString,QList<Find::SearchResultItem>)));
    m_resultWindow->popup(true);
    if (findFlags & Find::FindRegularExpression) {
        m_watcher.setFuture(Utils::findInFilesRegExp(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    } else {
        m_watcher.setFuture(Utils::findInFiles(txt, files(),
            textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
    }
    Core::FutureProgress *progress =
        Core::ICore::instance()->progressManager()->addTask(m_watcher.future(),
                                                                        "Search",
                                                                        Constants::TASK_SEARCH);
    progress->setWidget(createProgressWidget());
    connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
}

void BaseFileFind::doReplace(const QString &text,
                               const QList<Find::SearchResultItem> &items)
{
    QStringList files = replaceAll(text, items);
    Core::FileManager *fileManager = Core::ICore::instance()->fileManager();
    if (!files.isEmpty()) {
        fileManager->notifyFilesChangedInternally(files);
        m_resultWindow->hide();
    }
}

void BaseFileFind::displayResult(int index) {
    Utils::FileSearchResultList results = m_watcher.future().resultAt(index);
    QList<Find::SearchResultItem> items; // this conversion is stupid...
    foreach (const Utils::FileSearchResult &result, results) {
        Find::SearchResultItem item;
        item.path = QStringList() << QDir::toNativeSeparators(result.fileName);
        item.lineNumber = result.lineNumber;
        item.text = result.matchingLine;
        item.textMarkLength = result.matchLength;
        item.textMarkPos = result.matchStart;
        item.useTextEditorFont = true;
        item.userData = result.regexpCapturedTexts;
        items << item;
    }
    m_resultWindow->addResults(items, Find::SearchResultWindow::AddOrdered);
    if (m_resultLabel)
        m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
}

void BaseFileFind::searchFinished()
{
    m_resultWindow->finishSearch();
    m_isSearching = false;
    m_resultLabel = 0;
    emit changed();
}

QWidget *BaseFileFind::createProgressWidget()
{
    m_resultLabel = new QLabel;
    m_resultLabel->setAlignment(Qt::AlignCenter);
    // ### TODO this setup should be done by style
    QFont f = m_resultLabel->font();
    f.setBold(true);
    f.setPointSizeF(StyleHelper::sidebarFontSize());
    m_resultLabel->setFont(f);
    m_resultLabel->setPalette(StyleHelper::sidebarFontPalette(m_resultLabel->palette()));
    m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
    return m_resultLabel;
}

QWidget *BaseFileFind::createPatternWidget()
{
    QString filterToolTip = tr("List of comma separated wildcard filters");
    m_filterCombo = new QComboBox;
    m_filterCombo->setEditable(true);
    m_filterCombo->setModel(&m_filterStrings);
    m_filterCombo->setMaxCount(10);
    m_filterCombo->setMinimumContentsLength(10);
    m_filterCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
    m_filterCombo->setInsertPolicy(QComboBox::InsertAtBottom);
    m_filterCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    m_filterCombo->setToolTip(filterToolTip);
    syncComboWithSettings(m_filterCombo, m_filterSetting);
    return m_filterCombo;
}

void BaseFileFind::writeCommonSettings(QSettings *settings)
{
    settings->setValue("filters", m_filterStrings.stringList());
    if (m_filterCombo)
        settings->setValue("currentFilter", m_filterCombo->currentText());
}

void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter)
{
    QStringList filters = settings->value("filters").toStringList();
    m_filterSetting = settings->value("currentFilter").toString();
    if (filters.isEmpty())
        filters << defaultFilter;
    if (m_filterSetting.isEmpty())
        m_filterSetting = filters.first();
    m_filterStrings.setStringList(filters);
    if (m_filterCombo)
        syncComboWithSettings(m_filterCombo, m_filterSetting);
}

void BaseFileFind::syncComboWithSettings(QComboBox *combo, const QString &setting)
{
    if (!combo)
        return;
    int index = combo->findText(setting);
    if (index < 0)
        combo->setEditText(setting);
    else
        combo->setCurrentIndex(index);
}

void BaseFileFind::updateComboEntries(QComboBox *combo, bool onTop)
{
    int index = combo->findText(combo->currentText());
    if (index < 0) {
        if (onTop) {
            combo->insertItem(0, combo->currentText());
        } else {
            combo->addItem(combo->currentText());
        }
        combo->setCurrentIndex(combo->findText(combo->currentText()));
    }
}

void BaseFileFind::openEditor(const Find::SearchResultItem &item)
{
    if (item.path.size() > 0) {
        TextEditor::BaseTextEditor::openEditorAt(QDir::fromNativeSeparators(item.path.first()), item.lineNumber, item.textMarkPos,
                                                 QString(), Core::EditorManager::ModeSwitch);
    } else {
        Core::EditorManager::instance()->openEditor(item.text, QString(), Core::EditorManager::ModeSwitch);
    }
}

// #pragma mark Static methods

static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
{
    QList<QPair<QTextCursor, QString> > changes;

    foreach (const Find::SearchResultItem &item, items) {
        const int blockNumber = item.lineNumber - 1;
        QTextCursor tc(doc->findBlockByNumber(blockNumber));

        const int cursorPosition = tc.position() + item.textMarkPos;

        int cursorIndex = 0;
        for (; cursorIndex < changes.size(); ++cursorIndex) {
            const QTextCursor &otherTc = changes.at(cursorIndex).first;

            if (otherTc.position() == cursorPosition)
                break;
        }

        if (cursorIndex != changes.size())
            continue; // skip this change.

        tc.setPosition(cursorPosition);
        tc.setPosition(tc.position() + item.textMarkLength,
                       QTextCursor::KeepAnchor);
        QString substitutionText;
        if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty())
            substitutionText = Utils::expandRegExpReplacement(text, item.userData.toStringList());
        else
            substitutionText = text;
        changes.append(QPair<QTextCursor, QString>(tc, substitutionText));
    }

    for (int i = 0; i < changes.size(); ++i) {
        QPair<QTextCursor, QString> &cursor = changes[i];
        cursor.first.insertText(cursor.second);
    }
}

QStringList BaseFileFind::replaceAll(const QString &text,
                               const QList<Find::SearchResultItem> &items)
{
    if (text.isEmpty() || items.isEmpty())
        return QStringList();

    QHash<QString, QList<Find::SearchResultItem> > changes;

    foreach (const Find::SearchResultItem &item, items)
        changes[QDir::fromNativeSeparators(item.path.first())].append(item);

    Core::EditorManager *editorManager = Core::EditorManager::instance();

    QHashIterator<QString, QList<Find::SearchResultItem> > it(changes);
    while (it.hasNext()) {
        it.next();

        const QString fileName = it.key();
        const QList<Find::SearchResultItem> changeItems = it.value();

        const QList<Core::IEditor *> editors = editorManager->editorsForFileName(fileName);
        TextEditor::BaseTextEditor *textEditor = 0;
        foreach (Core::IEditor *editor, editors) {
            textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
            if (textEditor != 0)
                break;
        }

        if (textEditor != 0) {
            QTextCursor tc = textEditor->textCursor();
            tc.beginEditBlock();
            applyChanges(textEditor->document(), text, changeItems);
            tc.endEditBlock();
        } else {
            QFile file(fileName);

            if (file.open(QFile::ReadOnly)) {
                QTextStream stream(&file);
                // ### set the encoding
                const QString plainText = stream.readAll();
                file.close();

                QTextDocument doc;
                doc.setPlainText(plainText);

                applyChanges(&doc, text, changeItems);

                QFile newFile(fileName);
                if (newFile.open(QFile::WriteOnly)) {
                    QTextStream stream(&newFile);
                    // ### set the encoding
                    stream << doc.toPlainText();
                }
            }
        }
    }

    return changes.keys();
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// XFAIL: c++03

// <system_error>

// class error_code

// explicit operator bool() const;

#include <system_error>

bool test_func(void)
{
    const std::error_code ec(0, std::generic_category());
    return ec;   // conversion to bool is explicit; should fail.
}

int main()
{
    return 0;
}

<commit_msg>Extend XFAIL to c++98.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// XFAIL: c++98, c++03

// <system_error>

// class error_code

// explicit operator bool() const;

#include <system_error>

bool test_func(void)
{
    const std::error_code ec(0, std::generic_category());
    return ec;   // conversion to bool is explicit; should fail.
}

int main()
{
    return 0;
}

<|endoftext|>


<commit_before>// Infra.
#include <AMDTBaseTools/Include/gtString.h>
#include <AMDTOSWrappers/Include/osFilePath.h>
#include <AMDTOSWrappers/Include/osFile.h>
#include <AMDTOSWrappers/Include/osDirectory.h>

// Backend.
#include <RadeonGPUAnalyzerBackend/include/beStaticIsaAnalyzer.h>

// Local.
#include <RadeonGPUAnalyzerCLI/src/kcUtils.h>
#include <RadeonGPUAnalyzerCLI/src/kcCliStringConstants.h>
#include <RadeonGPUAnalyzerCLI/src/kcCLICommander.h>

using namespace beKA;

bool kcUtils::ValidateShaderFileName(const char* shaderType, const std::string& shaderFileName, std::stringstream& logMsg)
{
    bool isShaderNameValid = true;
    gtString shaderFileNameAsGtStr;
    shaderFileNameAsGtStr << shaderFileName.c_str();
    osFilePath shaderFile(shaderFileNameAsGtStr);

    if (!shaderFile.exists())
    {
        isShaderNameValid = false;
        logMsg << STR_ERR_CANNOT_FIND_SHADER_PREFIX << shaderType << STR_ERR_CANNOT_FIND_SHADER_SUFFIX << shaderFileName << std::endl;
    }

    return isShaderNameValid;
}

bool kcUtils::ValidateShaderOutputDir(const std::string& outputFileName, std::stringstream& logMsg)
{
    bool isShaderOutputDirValid = true;
    gtString shaderFileNameAsGtStr;
    shaderFileNameAsGtStr << outputFileName.c_str();
    osFilePath shaderFile(shaderFileNameAsGtStr);
    osDirectory outputDir;
    shaderFile.getFileDirectory(outputDir);
    if(outputDir.IsEmpty())
    {
        // If the directory is empty then we assume the output directory is the active directory which should exist.
        return true;
    }

    isShaderOutputDirValid = outputDir.exists();

    if (!isShaderOutputDirValid)
    {
        logMsg << STR_ERR_CANNOT_FIND_OUTPUT_DIR << outputDir.directoryPath().asString().asASCIICharArray() << std::endl;
    }

    return isShaderOutputDirValid;
}

void kcUtils::AdjustRenderingPipelineOutputFileNames(const std::string& baseOutputFileName, const std::string& device, beProgramPipeline& pipelineFiles)
{
    // Clear the existing pipeline.
    pipelineFiles.ClearAll();

    // Isolate the original file name.
    gtString outputFileAsGtStr;
    outputFileAsGtStr << baseOutputFileName.c_str();
    osFilePath outputFilePath(outputFileAsGtStr);

    // Directory.
    osDirectory outputDir;
    outputFilePath.getFileDirectory(outputDir);

    // File name.
    gtString originalFileName;
    outputFilePath.getFileName(originalFileName);

    // File extension.
    gtString originalFileExtension;
    outputFilePath.getFileExtension(originalFileExtension);

    // Make the adjustments.
    gtString fixedFileName;
    fixedFileName << outputDir.directoryPath().asString(true) << device.c_str() << "_";
    pipelineFiles.m_vertexShader << fixedFileName << KA_CLI_STR_VERTEX_ABBREVIATION;
    pipelineFiles.m_tessControlShader << fixedFileName << KA_CLI_STR_TESS_CTRL_ABBREVIATION;
    pipelineFiles.m_tessEvaluationShader << fixedFileName << KA_CLI_STR_TESS_EVAL_ABBREVIATION;
    pipelineFiles.m_geometryShader << fixedFileName << KA_CLI_STR_GEOMETRY_ABBREVIATION;
    pipelineFiles.m_fragmentShader << fixedFileName << KA_CLI_STR_FRAGMENT_ABBREVIATION;
    pipelineFiles.m_computeShader << fixedFileName << KA_CLI_STR_COMPUTE_ABBREVIATION;

    if (!originalFileName.isEmpty())
    {
        pipelineFiles.m_vertexShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_tessControlShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_tessEvaluationShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_geometryShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_fragmentShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_computeShader << "_" << originalFileName.asASCIICharArray();
    }

    if (!originalFileExtension.isEmpty())
    {
        pipelineFiles.m_vertexShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_tessControlShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_tessEvaluationShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_geometryShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_fragmentShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_computeShader << "." << originalFileExtension.asASCIICharArray();
    }
}

std::string kcUtils::DeviceStatisticsToCsvString(const Config& config, const std::string& device, const beKA::AnalysisData& statistics)
{
    std::stringstream output;

    // Device name.
    char csvSeparator = GetCsvSeparator(config);
    output << device << csvSeparator;

    // Scratch registers.
    output << statistics.maxScratchRegsNeeded << csvSeparator;

    // Work-items per work-group.
    output << statistics.numThreadPerGroup << csvSeparator;

    // Wavefront size.
    output << statistics.wavefrontSize << csvSeparator;

    // LDS available bytes.
    output << statistics.LDSSizeAvailable << csvSeparator;

    // LDS actual bytes.
    output << statistics.LDSSizeUsed << csvSeparator;

    // Available SGPRs.
    output << statistics.numSGPRsAvailable << csvSeparator;

    // Used SGPRs.
    output << statistics.numSGPRsUsed << csvSeparator;

    // Available VGPRs.
    output << statistics.numVGPRsAvailable << csvSeparator;

    // Used VGPRs.
    output << statistics.numVGPRsUsed << csvSeparator;

    // CL Work-group dimensions (for a unified format, to be revisited).
    output << statistics.numThreadPerGroupX << csvSeparator;
    output << statistics.numThreadPerGroupY << csvSeparator;
    output << statistics.numThreadPerGroupZ << csvSeparator;

    // ISA size.
    output << statistics.ISASize;

    output << std::endl;

    return output.str().c_str();
}

bool kcUtils::CreateStatisticsFile(const gtString& fileName, const Config& config,
                                   const std::map<std::string, beKA::AnalysisData>& analysisData, LoggingCallBackFunc_t pLogCallback)
{
    bool ret = false;

    // Get the separator for CSV list items.
    char csvSeparator = GetCsvSeparator(config);

    // Open output file.
    std::ofstream output;
    output.open(fileName.asASCIICharArray());

    if (output.is_open())
    {
        // Write the header.
        output << GetStatisticsCsvHeaderString(csvSeparator) << std::endl;

        // Write the device data.
        for (const auto& deviceStatsPair : analysisData)
        {
            // Write a line of CSV.
            output << DeviceStatisticsToCsvString(config, deviceStatsPair.first, deviceStatsPair.second);
        }

        output.close();
        ret = true;
    }
    else if (pLogCallback != nullptr)
    {
        std::stringstream s_Log;
        s_Log << STR_ERR_CANNOT_OPEN_FILE_FOR_WRITE_A << fileName.asASCIICharArray() <<
              STR_ERR_CANNOT_OPEN_FILE_FOR_WRITE_B << std::endl;
        pLogCallback(s_Log.str());
    }

    return ret;
}

std::string kcUtils::GetStatisticsCsvHeaderString(char csvSeparator)
{
    std::stringstream output;
    output << STR_CSV_HEADER_DEVICE << csvSeparator;
    output << STR_CSV_HEADER_SCRATCH_REGS << csvSeparator;
    output << STR_CSV_HEADER_THREADS_PER_WG << csvSeparator;
    output << STR_CSV_HEADER_WAVEFRONT_SIZE << csvSeparator;
    output << STR_CSV_HEADER_LDS_BYTES_MAX << csvSeparator;
    output << STR_CSV_HEADER_LDS_BYTES_ACTUAL << csvSeparator;
    output << STR_CSV_HEADER_SGPR_AVAILABLE << csvSeparator;
    output << STR_CSV_HEADER_SGPR_USED << csvSeparator;
    output << STR_CSV_HEADER_VGPR_AVAILABLE << csvSeparator;
    output << STR_CSV_HEADER_VGPR_USED << csvSeparator;
    output << STR_CSV_HEADER_CL_WORKGROUP_DIM_X << csvSeparator;
    output << STR_CSV_HEADER_CL_WORKGROUP_DIM_Y << csvSeparator;
    output << STR_CSV_HEADER_CL_WORKGROUP_DIM_Z << csvSeparator;
    output << STR_CSV_HEADER_ISA_SIZE_BYTES;
    return output.str().c_str();
}

void kcUtils::CreateStatisticsFile(const gtString& fileName, const Config& config, const std::string& device,
                                   const beKA::AnalysisData& deviceStatistics, LoggingCallBackFunc_t pLogCallback)
{
    // Create a temporary map and invoke the general routine.
    std::map<std::string, beKA::AnalysisData> tmpMap;
    tmpMap[device] = deviceStatistics;
    CreateStatisticsFile(fileName, config, tmpMap, pLogCallback);
}

char kcUtils::GetCsvSeparator(const Config& config)
{
    char csvSeparator;

    if (!config.m_CSVSeparator.empty())
    {
        csvSeparator = config.m_CSVSeparator[0];

        if (config.m_CSVSeparator[0] == '\\' && config.m_CSVSeparator.size() > 1)
        {
            switch (config.m_CSVSeparator[1])
            {
                case 'a': csvSeparator = '\a'; break;

                case 'b': csvSeparator = '\b'; break;

                case 'f': csvSeparator = '\f'; break;

                case 'n': csvSeparator = '\n'; break;

                case 'r': csvSeparator = '\r'; break;

                case 't': csvSeparator = '\t'; break;

                case 'v': csvSeparator = '\v'; break;

                default:
                    csvSeparator = config.m_CSVSeparator[1];
                    break;
            }
        }
    }
    else
    {
        // The default separator.
        csvSeparator = ',';
    }

    return csvSeparator;
}

bool kcUtils::DeleteFile(const gtString& fileFullPath)
{
    bool ret = false;
    osFilePath path(fileFullPath);

    if (path.exists())
    {
        osFile file(path);
        ret = file.deleteFile();
    }

    return ret;
}

void kcUtils::ReplaceStatisticsFile(const gtString& statisticsFile, const Config& config,
                                    const std::string& device, IStatisticsParser& statsParser, LoggingCallBackFunc_t logCb)
{
    // Parse the backend statistics.
    beKA::AnalysisData statistics;
    statsParser.ParseStatistics(statisticsFile, statistics);

    // Delete the older statistics file.
    kcUtils::DeleteFile(statisticsFile);

    // Create a new statistics file in the CLI format.
    kcUtils::CreateStatisticsFile(statisticsFile, config, device, statistics, logCb);
}

void kcUtils::PerformLiveRegisterAnalysis(const gtString& isaFileName,
                                          const gtString& outputFileName, LoggingCallBackFunc_t pCallback)
{
    // Call the backend.
    beStatus rc = beStaticIsaAnalyzer::PerformLiveRegisterAnalysis(isaFileName, outputFileName);

    if (rc != beStatus_SUCCESS && pCallback != nullptr)
    {
        // Inform the user in case of an error.
        std::stringstream msg;

        switch (rc)
        {
            case beKA::beStatus_shaeCannotLocateAnalyzer:
                // Failed to locate the ISA analyzer.
                msg << STR_ERR_CANNOT_LOCATE_LIVE_REG_ANALYZER << std::endl;
                break;

            case beKA::beStatus_shaeIsaFileNotFound:
                // ISA file not found.
                msg << STR_ERR_CANNOT_FIND_ISA_FILE << std::endl;
                break;

            case beKA::beStatus_shaeFailedToLaunch:
#ifndef __linux__
                // Failed to launch the ISA analyzer.
		// On Linux, there is an issue with this return code due to the
		// executable format that we use for the backend.
                msg << STR_ERR_CANNOT_LAUNCH_LIVE_REG_ANALYZER << std::endl;
#endif
                break;

            case beKA::beStatus_General_FAILED:
            default:
                // Generic error message.
                msg << STR_ERR_CANNOT_PERFORM_LIVE_REG_ANALYSIS << std::endl;
                break;
        }

        const std::string& errMsg = msg.str();

        if (!errMsg.empty() && pCallback != nullptr)
        {
            pCallback(errMsg);
        }
    }
}

void kcUtils::GenerateControlFlowGraph(const gtString& isaFileName, const gtString& outputFileName, LoggingCallBackFunc_t pCallback)
{
    // Call the backend.
    beStatus rc = beStaticIsaAnalyzer::GenerateControlFlowGraph(isaFileName, outputFileName);

    if (rc != beStatus_SUCCESS && pCallback != nullptr)
    {
        // Inform the user in case of an error.
        std::stringstream msg;

        switch (rc)
        {
            case beKA::beStatus_shaeCannotLocateAnalyzer:
                // Failed to locate the ISA analyzer.
                msg << STR_ERR_CANNOT_LOCATE_LIVE_REG_ANALYZER << std::endl;
                break;

            case beKA::beStatus_shaeIsaFileNotFound:
                // ISA file not found.
                msg << STR_ERR_CANNOT_FIND_ISA_FILE << std::endl;
                break;

            case beKA::beStatus_shaeFailedToLaunch:
                // Failed to launch the ISA analyzer.
                msg << STR_ERR_CANNOT_LAUNCH_CFG_ANALYZER << std::endl;
                break;

            case beKA::beStatus_General_FAILED:
            default:
                // Generic error message.
                msg << STR_ERR_CANNOT_PERFORM_LIVE_REG_ANALYSIS << std::endl;
                break;
        }

        const std::string& errMsg = msg.str();

        if (!errMsg.empty() && pCallback != nullptr)
        {
            pCallback(errMsg);
        }
    }

}

void kcUtils::ConstructOutputFileName(const std::string& baseOutputFileName, const std::string& defaultExtension, const std::string& kernelName, const std::string& deviceName, gtString& generatedFileName)
{
    // Convert the base output file name to gtString.
    gtString baseOutputFileNameAsGtStr;
    baseOutputFileNameAsGtStr << baseOutputFileName.c_str();
    osFilePath outputFilePath(baseOutputFileNameAsGtStr);

    // Extract the user's file name and extension.
    gtString fileName;
    if (!outputFilePath.isDirectory())
    {
        outputFilePath.getFileName(fileName);
    }
    else
    {
        osDirectory outputDir(baseOutputFileNameAsGtStr);
        outputFilePath.setFileDirectory(outputDir);
    }

    // Fix the user's file name to generate a unique output file name in the Analyzer CLI format.
    gtString fixedFileName;
    fixedFileName << deviceName.c_str();

    if (!kernelName.empty())
    {
        if (!fixedFileName.isEmpty())
        {
            fixedFileName << "_";
        }

        fixedFileName << kernelName.c_str();
    }

    if (!fileName.isEmpty())
    {
        if (!fixedFileName.isEmpty())
        {
            fixedFileName << "_";
        }

        fixedFileName << fileName;
    }

    outputFilePath.setFileName(fixedFileName);

    // Handle the default extension (unless the user specified an extension).
    gtString outputFileExtension;
    outputFilePath.getFileExtension(outputFileExtension);

    if (outputFileExtension.isEmpty())
    {
        outputFileExtension.fromASCIIString(defaultExtension.c_str());
        outputFilePath.setFileExtension(outputFileExtension);
    }

    // Set the output string.
    generatedFileName = outputFilePath.asString();
}

kcUtils::kcUtils()
{
}

kcUtils::~kcUtils()
{
}
<commit_msg>Fix check for empty directory string.<commit_after>// Infra.
#include <AMDTBaseTools/Include/gtString.h>
#include <AMDTOSWrappers/Include/osFilePath.h>
#include <AMDTOSWrappers/Include/osFile.h>
#include <AMDTOSWrappers/Include/osDirectory.h>

// Backend.
#include <RadeonGPUAnalyzerBackend/include/beStaticIsaAnalyzer.h>

// Local.
#include <RadeonGPUAnalyzerCLI/src/kcUtils.h>
#include <RadeonGPUAnalyzerCLI/src/kcCliStringConstants.h>
#include <RadeonGPUAnalyzerCLI/src/kcCLICommander.h>

using namespace beKA;

bool kcUtils::ValidateShaderFileName(const char* shaderType, const std::string& shaderFileName, std::stringstream& logMsg)
{
    bool isShaderNameValid = true;
    gtString shaderFileNameAsGtStr;
    shaderFileNameAsGtStr << shaderFileName.c_str();
    osFilePath shaderFile(shaderFileNameAsGtStr);

    if (!shaderFile.exists())
    {
        isShaderNameValid = false;
        logMsg << STR_ERR_CANNOT_FIND_SHADER_PREFIX << shaderType << STR_ERR_CANNOT_FIND_SHADER_SUFFIX << shaderFileName << std::endl;
    }

    return isShaderNameValid;
}

bool kcUtils::ValidateShaderOutputDir(const std::string& outputFileName, std::stringstream& logMsg)
{
    bool isShaderOutputDirValid = true;
    gtString shaderFileNameAsGtStr;
    shaderFileNameAsGtStr << outputFileName.c_str();
    osFilePath shaderFile(shaderFileNameAsGtStr);
    osDirectory outputDir;
    shaderFile.getFileDirectory(outputDir);

    // If the directory is empty then we assume the output directory is the active directory which should exist.
    isShaderOutputDirValid = outputDir.asString().isEmpty() || outputDir.exists();

    if (!isShaderOutputDirValid)
    {
        logMsg << STR_ERR_CANNOT_FIND_OUTPUT_DIR << outputDir.directoryPath().asString().asASCIICharArray() << std::endl;
    }

    return isShaderOutputDirValid;
}

void kcUtils::AdjustRenderingPipelineOutputFileNames(const std::string& baseOutputFileName, const std::string& device, beProgramPipeline& pipelineFiles)
{
    // Clear the existing pipeline.
    pipelineFiles.ClearAll();

    // Isolate the original file name.
    gtString outputFileAsGtStr;
    outputFileAsGtStr << baseOutputFileName.c_str();
    osFilePath outputFilePath(outputFileAsGtStr);

    // Directory.
    osDirectory outputDir;
    outputFilePath.getFileDirectory(outputDir);

    // File name.
    gtString originalFileName;
    outputFilePath.getFileName(originalFileName);

    // File extension.
    gtString originalFileExtension;
    outputFilePath.getFileExtension(originalFileExtension);

    // Make the adjustments.
    gtString fixedFileName;
    fixedFileName << outputDir.directoryPath().asString(true) << device.c_str() << "_";
    pipelineFiles.m_vertexShader << fixedFileName << KA_CLI_STR_VERTEX_ABBREVIATION;
    pipelineFiles.m_tessControlShader << fixedFileName << KA_CLI_STR_TESS_CTRL_ABBREVIATION;
    pipelineFiles.m_tessEvaluationShader << fixedFileName << KA_CLI_STR_TESS_EVAL_ABBREVIATION;
    pipelineFiles.m_geometryShader << fixedFileName << KA_CLI_STR_GEOMETRY_ABBREVIATION;
    pipelineFiles.m_fragmentShader << fixedFileName << KA_CLI_STR_FRAGMENT_ABBREVIATION;
    pipelineFiles.m_computeShader << fixedFileName << KA_CLI_STR_COMPUTE_ABBREVIATION;

    if (!originalFileName.isEmpty())
    {
        pipelineFiles.m_vertexShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_tessControlShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_tessEvaluationShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_geometryShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_fragmentShader << "_" << originalFileName.asASCIICharArray();
        pipelineFiles.m_computeShader << "_" << originalFileName.asASCIICharArray();
    }

    if (!originalFileExtension.isEmpty())
    {
        pipelineFiles.m_vertexShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_tessControlShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_tessEvaluationShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_geometryShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_fragmentShader << "." << originalFileExtension.asASCIICharArray();
        pipelineFiles.m_computeShader << "." << originalFileExtension.asASCIICharArray();
    }
}

std::string kcUtils::DeviceStatisticsToCsvString(const Config& config, const std::string& device, const beKA::AnalysisData& statistics)
{
    std::stringstream output;

    // Device name.
    char csvSeparator = GetCsvSeparator(config);
    output << device << csvSeparator;

    // Scratch registers.
    output << statistics.maxScratchRegsNeeded << csvSeparator;

    // Work-items per work-group.
    output << statistics.numThreadPerGroup << csvSeparator;

    // Wavefront size.
    output << statistics.wavefrontSize << csvSeparator;

    // LDS available bytes.
    output << statistics.LDSSizeAvailable << csvSeparator;

    // LDS actual bytes.
    output << statistics.LDSSizeUsed << csvSeparator;

    // Available SGPRs.
    output << statistics.numSGPRsAvailable << csvSeparator;

    // Used SGPRs.
    output << statistics.numSGPRsUsed << csvSeparator;

    // Available VGPRs.
    output << statistics.numVGPRsAvailable << csvSeparator;

    // Used VGPRs.
    output << statistics.numVGPRsUsed << csvSeparator;

    // CL Work-group dimensions (for a unified format, to be revisited).
    output << statistics.numThreadPerGroupX << csvSeparator;
    output << statistics.numThreadPerGroupY << csvSeparator;
    output << statistics.numThreadPerGroupZ << csvSeparator;

    // ISA size.
    output << statistics.ISASize;

    output << std::endl;

    return output.str().c_str();
}

bool kcUtils::CreateStatisticsFile(const gtString& fileName, const Config& config,
                                   const std::map<std::string, beKA::AnalysisData>& analysisData, LoggingCallBackFunc_t pLogCallback)
{
    bool ret = false;

    // Get the separator for CSV list items.
    char csvSeparator = GetCsvSeparator(config);

    // Open output file.
    std::ofstream output;
    output.open(fileName.asASCIICharArray());

    if (output.is_open())
    {
        // Write the header.
        output << GetStatisticsCsvHeaderString(csvSeparator) << std::endl;

        // Write the device data.
        for (const auto& deviceStatsPair : analysisData)
        {
            // Write a line of CSV.
            output << DeviceStatisticsToCsvString(config, deviceStatsPair.first, deviceStatsPair.second);
        }

        output.close();
        ret = true;
    }
    else if (pLogCallback != nullptr)
    {
        std::stringstream s_Log;
        s_Log << STR_ERR_CANNOT_OPEN_FILE_FOR_WRITE_A << fileName.asASCIICharArray() <<
              STR_ERR_CANNOT_OPEN_FILE_FOR_WRITE_B << std::endl;
        pLogCallback(s_Log.str());
    }

    return ret;
}

std::string kcUtils::GetStatisticsCsvHeaderString(char csvSeparator)
{
    std::stringstream output;
    output << STR_CSV_HEADER_DEVICE << csvSeparator;
    output << STR_CSV_HEADER_SCRATCH_REGS << csvSeparator;
    output << STR_CSV_HEADER_THREADS_PER_WG << csvSeparator;
    output << STR_CSV_HEADER_WAVEFRONT_SIZE << csvSeparator;
    output << STR_CSV_HEADER_LDS_BYTES_MAX << csvSeparator;
    output << STR_CSV_HEADER_LDS_BYTES_ACTUAL << csvSeparator;
    output << STR_CSV_HEADER_SGPR_AVAILABLE << csvSeparator;
    output << STR_CSV_HEADER_SGPR_USED << csvSeparator;
    output << STR_CSV_HEADER_VGPR_AVAILABLE << csvSeparator;
    output << STR_CSV_HEADER_VGPR_USED << csvSeparator;
    output << STR_CSV_HEADER_CL_WORKGROUP_DIM_X << csvSeparator;
    output << STR_CSV_HEADER_CL_WORKGROUP_DIM_Y << csvSeparator;
    output << STR_CSV_HEADER_CL_WORKGROUP_DIM_Z << csvSeparator;
    output << STR_CSV_HEADER_ISA_SIZE_BYTES;
    return output.str().c_str();
}

void kcUtils::CreateStatisticsFile(const gtString& fileName, const Config& config, const std::string& device,
                                   const beKA::AnalysisData& deviceStatistics, LoggingCallBackFunc_t pLogCallback)
{
    // Create a temporary map and invoke the general routine.
    std::map<std::string, beKA::AnalysisData> tmpMap;
    tmpMap[device] = deviceStatistics;
    CreateStatisticsFile(fileName, config, tmpMap, pLogCallback);
}

char kcUtils::GetCsvSeparator(const Config& config)
{
    char csvSeparator;

    if (!config.m_CSVSeparator.empty())
    {
        csvSeparator = config.m_CSVSeparator[0];

        if (config.m_CSVSeparator[0] == '\\' && config.m_CSVSeparator.size() > 1)
        {
            switch (config.m_CSVSeparator[1])
            {
                case 'a': csvSeparator = '\a'; break;

                case 'b': csvSeparator = '\b'; break;

                case 'f': csvSeparator = '\f'; break;

                case 'n': csvSeparator = '\n'; break;

                case 'r': csvSeparator = '\r'; break;

                case 't': csvSeparator = '\t'; break;

                case 'v': csvSeparator = '\v'; break;

                default:
                    csvSeparator = config.m_CSVSeparator[1];
                    break;
            }
        }
    }
    else
    {
        // The default separator.
        csvSeparator = ',';
    }

    return csvSeparator;
}

bool kcUtils::DeleteFile(const gtString& fileFullPath)
{
    bool ret = false;
    osFilePath path(fileFullPath);

    if (path.exists())
    {
        osFile file(path);
        ret = file.deleteFile();
    }

    return ret;
}

void kcUtils::ReplaceStatisticsFile(const gtString& statisticsFile, const Config& config,
                                    const std::string& device, IStatisticsParser& statsParser, LoggingCallBackFunc_t logCb)
{
    // Parse the backend statistics.
    beKA::AnalysisData statistics;
    statsParser.ParseStatistics(statisticsFile, statistics);

    // Delete the older statistics file.
    kcUtils::DeleteFile(statisticsFile);

    // Create a new statistics file in the CLI format.
    kcUtils::CreateStatisticsFile(statisticsFile, config, device, statistics, logCb);
}

void kcUtils::PerformLiveRegisterAnalysis(const gtString& isaFileName,
                                          const gtString& outputFileName, LoggingCallBackFunc_t pCallback)
{
    // Call the backend.
    beStatus rc = beStaticIsaAnalyzer::PerformLiveRegisterAnalysis(isaFileName, outputFileName);

    if (rc != beStatus_SUCCESS && pCallback != nullptr)
    {
        // Inform the user in case of an error.
        std::stringstream msg;

        switch (rc)
        {
            case beKA::beStatus_shaeCannotLocateAnalyzer:
                // Failed to locate the ISA analyzer.
                msg << STR_ERR_CANNOT_LOCATE_LIVE_REG_ANALYZER << std::endl;
                break;

            case beKA::beStatus_shaeIsaFileNotFound:
                // ISA file not found.
                msg << STR_ERR_CANNOT_FIND_ISA_FILE << std::endl;
                break;

            case beKA::beStatus_shaeFailedToLaunch:
#ifndef __linux__
                // Failed to launch the ISA analyzer.
		// On Linux, there is an issue with this return code due to the
		// executable format that we use for the backend.
                msg << STR_ERR_CANNOT_LAUNCH_LIVE_REG_ANALYZER << std::endl;
#endif
                break;

            case beKA::beStatus_General_FAILED:
            default:
                // Generic error message.
                msg << STR_ERR_CANNOT_PERFORM_LIVE_REG_ANALYSIS << std::endl;
                break;
        }

        const std::string& errMsg = msg.str();

        if (!errMsg.empty() && pCallback != nullptr)
        {
            pCallback(errMsg);
        }
    }
}

void kcUtils::GenerateControlFlowGraph(const gtString& isaFileName, const gtString& outputFileName, LoggingCallBackFunc_t pCallback)
{
    // Call the backend.
    beStatus rc = beStaticIsaAnalyzer::GenerateControlFlowGraph(isaFileName, outputFileName);

    if (rc != beStatus_SUCCESS && pCallback != nullptr)
    {
        // Inform the user in case of an error.
        std::stringstream msg;

        switch (rc)
        {
            case beKA::beStatus_shaeCannotLocateAnalyzer:
                // Failed to locate the ISA analyzer.
                msg << STR_ERR_CANNOT_LOCATE_LIVE_REG_ANALYZER << std::endl;
                break;

            case beKA::beStatus_shaeIsaFileNotFound:
                // ISA file not found.
                msg << STR_ERR_CANNOT_FIND_ISA_FILE << std::endl;
                break;

            case beKA::beStatus_shaeFailedToLaunch:
                // Failed to launch the ISA analyzer.
                msg << STR_ERR_CANNOT_LAUNCH_CFG_ANALYZER << std::endl;
                break;

            case beKA::beStatus_General_FAILED:
            default:
                // Generic error message.
                msg << STR_ERR_CANNOT_PERFORM_LIVE_REG_ANALYSIS << std::endl;
                break;
        }

        const std::string& errMsg = msg.str();

        if (!errMsg.empty() && pCallback != nullptr)
        {
            pCallback(errMsg);
        }
    }

}

void kcUtils::ConstructOutputFileName(const std::string& baseOutputFileName, const std::string& defaultExtension, const std::string& kernelName, const std::string& deviceName, gtString& generatedFileName)
{
    // Convert the base output file name to gtString.
    gtString baseOutputFileNameAsGtStr;
    baseOutputFileNameAsGtStr << baseOutputFileName.c_str();
    osFilePath outputFilePath(baseOutputFileNameAsGtStr);

    // Extract the user's file name and extension.
    gtString fileName;
    if (!outputFilePath.isDirectory())
    {
        outputFilePath.getFileName(fileName);
    }
    else
    {
        osDirectory outputDir(baseOutputFileNameAsGtStr);
        outputFilePath.setFileDirectory(outputDir);
    }

    // Fix the user's file name to generate a unique output file name in the Analyzer CLI format.
    gtString fixedFileName;
    fixedFileName << deviceName.c_str();

    if (!kernelName.empty())
    {
        if (!fixedFileName.isEmpty())
        {
            fixedFileName << "_";
        }

        fixedFileName << kernelName.c_str();
    }

    if (!fileName.isEmpty())
    {
        if (!fixedFileName.isEmpty())
        {
            fixedFileName << "_";
        }

        fixedFileName << fileName;
    }

    outputFilePath.setFileName(fixedFileName);

    // Handle the default extension (unless the user specified an extension).
    gtString outputFileExtension;
    outputFilePath.getFileExtension(outputFileExtension);

    if (outputFileExtension.isEmpty())
    {
        outputFileExtension.fromASCIIString(defaultExtension.c_str());
        outputFilePath.setFileExtension(outputFileExtension);
    }

    // Set the output string.
    generatedFileName = outputFilePath.asString();
}

kcUtils::kcUtils()
{
}

kcUtils::~kcUtils()
{
}
<|endoftext|>