cocos-engine-external/sources/android-gamesdk/GameController/GameControllerMappingUtils.cpp

180 lines
7.4 KiB
C++

/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "GameControllerMappingUtils.h"
#include "GameControllerManager.h"
namespace paddleboat {
MappingTableSearch::MappingTableSearch()
: mappingRoot(nullptr),
vendorId(0),
productId(0),
minApi(0),
maxApi(0),
tableIndex(0),
mapEntryCount(0),
tableEntryCount(0),
tableMaxEntryCount(GameControllerManager::getRemapTableSize()) {}
MappingTableSearch::MappingTableSearch(
Paddleboat_Controller_Mapping_Data *mapRoot, int32_t entryCount)
: mappingRoot(mapRoot),
vendorId(0),
productId(0),
minApi(0),
maxApi(0),
tableIndex(0),
mapEntryCount(0),
tableEntryCount(entryCount),
tableMaxEntryCount(GameControllerManager::getRemapTableSize()) {}
void MappingTableSearch::initSearchParameters(const int32_t newVendorId,
const int32_t newProductId,
const int32_t newMinApi,
const int32_t newMaxApi) {
vendorId = newVendorId;
productId = newProductId;
minApi = newMinApi;
maxApi = newMaxApi;
tableIndex = 0;
}
bool GameControllerMappingUtils::findMatchingMapEntry(
MappingTableSearch *searchEntry) {
int32_t currentIndex = 0;
// Starting out with a linear search. Updating the map table is something
// that should only ever be done once at startup, if it actually takes an
// appreciable time to execute when working with a big remap dictionary,
// this is low-hanging fruit to optimize.
const Paddleboat_Controller_Mapping_Data *mapRoot =
searchEntry->mappingRoot;
while (currentIndex < searchEntry->tableEntryCount) {
const Paddleboat_Controller_Mapping_Data &mapEntry =
mapRoot[currentIndex];
if (mapEntry.vendorId > searchEntry->vendorId) {
// Passed by the search vendorId value, so we don't already exist in
// the table, set the current index as the insert point and bail
searchEntry->tableIndex = currentIndex;
return false;
} else if (searchEntry->vendorId == mapEntry.vendorId) {
if (mapEntry.productId > searchEntry->productId) {
// Passed by the search productId value, so we don't already
// exist in the table, set the current index as the insert point
// and bail
searchEntry->tableIndex = currentIndex;
return false;
} else if (searchEntry->productId == mapEntry.productId) {
// Any overlap of the min/max API range is treated as matching
// an existing entry
if ((searchEntry->minApi >= mapEntry.minimumEffectiveApiLevel &&
searchEntry->minApi <=
mapEntry.maximumEffectiveApiLevel) ||
(searchEntry->minApi >= mapEntry.minimumEffectiveApiLevel &&
mapEntry.maximumEffectiveApiLevel == 0)) {
searchEntry->tableIndex = currentIndex;
return true;
}
}
}
++currentIndex;
}
searchEntry->tableIndex = currentIndex;
return false;
}
bool GameControllerMappingUtils::insertMapEntry(
const Paddleboat_Controller_Mapping_Data *mappingData,
MappingTableSearch *searchEntry) {
bool insertSuccess = false;
// Verify there is room in the table for another entry
if (searchEntry->tableEntryCount < searchEntry->tableMaxEntryCount &&
searchEntry->tableIndex < searchEntry->tableMaxEntryCount) {
// Empty table, or inserting at the end, no relocation of existing data
// required, otherwise shift existing data down starting at the insert
// index.
if (!(searchEntry->tableEntryCount == 0 ||
searchEntry->tableIndex == searchEntry->tableEntryCount)) {
const size_t copySize =
(searchEntry->tableEntryCount - searchEntry->tableIndex) *
sizeof(Paddleboat_Controller_Mapping_Data);
memmove(&searchEntry->mappingRoot[searchEntry->tableIndex + 1],
&searchEntry->mappingRoot[searchEntry->tableIndex],
copySize);
}
// Insert the new data
memcpy(&searchEntry->mappingRoot[searchEntry->tableIndex], mappingData,
sizeof(Paddleboat_Controller_Mapping_Data));
insertSuccess = true;
}
return insertSuccess;
}
const Paddleboat_Controller_Mapping_Data *
GameControllerMappingUtils::validateMapTable(
const Paddleboat_Controller_Mapping_Data *mappingRoot,
const int32_t tableEntryCount) {
// The map table is always assumed to be sorted by increasing vendorId. Each
// sequence of entries with the same vendorId are sorted by increasing
// productId. Multiple entries with the same vendorId/productId range are
// sorted by increasing min/max API ranges. vendorId
// productId
// minApi
int32_t currentIndex = 0;
int32_t previousVendorId = -1;
while (currentIndex < tableEntryCount) {
if (mappingRoot[currentIndex].vendorId < previousVendorId) {
// failure in vendorId order, return the offending entry
return &mappingRoot[currentIndex];
}
int32_t previousProductId = mappingRoot[currentIndex].productId;
int32_t previousMinApi =
mappingRoot[currentIndex].minimumEffectiveApiLevel;
int32_t previousMaxApi =
mappingRoot[currentIndex].maximumEffectiveApiLevel;
previousVendorId = mappingRoot[currentIndex++].vendorId;
while (currentIndex < tableEntryCount &&
mappingRoot[currentIndex].vendorId == previousVendorId) {
while (currentIndex < tableEntryCount &&
mappingRoot[currentIndex].productId == previousProductId) {
if (mappingRoot[currentIndex].minimumEffectiveApiLevel <
previousMinApi ||
mappingRoot[currentIndex].minimumEffectiveApiLevel <
previousMaxApi) {
// failure in API order, return the offending entry
return &mappingRoot[currentIndex];
}
previousMinApi =
mappingRoot[currentIndex].minimumEffectiveApiLevel;
previousMaxApi =
mappingRoot[currentIndex++].maximumEffectiveApiLevel;
}
if (mappingRoot[currentIndex].productId < previousProductId) {
// failure in productId order, return the offending entry
return &mappingRoot[currentIndex];
}
previousProductId = mappingRoot[currentIndex++].productId;
}
}
// Validation success, return nullptr (no offending entries to return)
return nullptr;
}
} // namespace paddleboat