<commit_before>/*
 * LootManagerImplementation.cpp
 *
 *  Created on: Jun 20, 2011
 *      Author: Kyle
 */

#include "engine/engine.h"

#include "LootManager.h"
#include "server/zone/objects/scene/SceneObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/creature/AiAgent.h"
#include "server/zone/managers/crafting/CraftingManager.h"
#include "server/zone/managers/templates/TemplateManager.h"
#include "server/zone/templates/LootItemTemplate.h"
#include "server/zone/ZoneServer.h"
#include "server/zone/managers/stringid/StringIdManager.h"
#include "LootGroupMap.h"

void LootManagerImplementation::initialize() {

	lua = new Lua();
	lua->init();

	info("Loading configuration.");

	if(!loadConfigData()) {

		loadDefaultConfig();

		info("***** ERROR in configuration, using default values");
	}

	lootGroupMap = LootGroupMap::instance();
	lootGroupMap->initialize();

	info("Loaded " + String::valueOf(lootGroupMap->getTotalItems()) + " loot items.", true);
	info("Loaded " + String::valueOf(lootGroupMap->getTotalGroups()) + " loot groups.", true);

	info("Initialized.");
}

bool LootManagerImplementation::loadConfigFile() {
	return lua->runFile("scripts/managers/loot_manager.lua");
}

bool LootManagerImplementation::loadConfigData() {
	if (!loadConfigFile())
		return false;

	exceptionalChance = lua->getGlobalFloat("exceptionalChance");
	exceptionalModifier = lua->getGlobalFloat("exceptionalModifier");
	legendaryChance = lua->getGlobalFloat("legendaryChance");
	legendaryModifier = lua->getGlobalFloat("legendaryModifier");

	LuaObject lootableModsTable = lua->getGlobalObject("lootableStatMods");

	if (!lootableModsTable.isValidTable())
		return false;

	for (int i = 1; i <= lootableModsTable.getTableSize(); ++i) {
		String mod = lootableModsTable.getStringAt(i);
		lootableMods.put(mod);
	}

	lootableModsTable.pop();

	info("Loaded " + String::valueOf(lootableMods.size()) + " lootable stat mods.", true);

	return true;
}

void LootManagerImplementation::loadDefaultConfig() {

}

void LootManagerImplementation::setInitialObjectStats(LootItemTemplate* templateObject, CraftingValues* craftingValues, TangibleObject* prototype) {
	SharedTangibleObjectTemplate* tanoTemplate = dynamic_cast<SharedTangibleObjectTemplate*>(prototype->getObjectTemplate());

	if (tanoTemplate != NULL) {
		Vector<String>* props = tanoTemplate->getExperimentalSubGroupTitles();
		Vector<int>* mins = tanoTemplate->getExperimentalMin();
		Vector<int>* maxs = tanoTemplate->getExperimentalMax();
		Vector<short>* prec = tanoTemplate->getExperimentalPrecision();

		for (int i = 0; i < props->size(); ++i) {
			String property = props->get(i);

			if (craftingValues->hasProperty(property))
				continue;

			craftingValues->addExperimentalProperty(property, property, mins->get(i), maxs->get(i), prec->get(i), false);
		}
	}

	Vector<String>* customizationData = templateObject->getCustomizationStringNames();
	Vector<Vector<int> >* customizationValues = templateObject->getCustomizationValues();

	for (int i = 0; i < customizationData->size(); ++i) {
		String customizationString = customizationData->get(i);
		Vector<int>* values = &customizationValues->get(i);

		int idx = customizationString.lastIndexOf("/");

		if (idx != -1)
			customizationString = customizationString.subString(idx + 1);

		if (values->size() > 0) {
			int randomValue = values->get(System::random(values->size() - 1));

			prototype->setCustomizationVariable(customizationString, randomValue, false);
		}
	}
}

void LootManagerImplementation::setCustomObjectName(TangibleObject* object, LootItemTemplate* templateObject) {
	String customName = templateObject->getCustomObjectName();

	if (!customName.isEmpty()) {
		if (customName.charAt(0) == '@') {
			StringId stringId(customName);

			object->setObjectName(stringId);
		} else {
			object->setCustomObjectName(customName, false);
		}
	}
}

int LootManagerImplementation::calculateLootCredits(int level) {
	int maxcredits = (int) round((.03f * level * level) + (3 * level) + 50);
	int mincredits = (int) round((((float) maxcredits) * .5f) + (2.0f * level));

	int credits = mincredits + System::random(maxcredits - mincredits);

	return credits;
}

SceneObject* LootManagerImplementation::createLootObject(LootItemTemplate* templateObject, int level) {
	String directTemplateObject = templateObject->getDirectObjectTemplate();

	ManagedReference<TangibleObject*> prototype = dynamic_cast<TangibleObject*> (zoneServer->createObject(directTemplateObject.hashCode(), 2));

	if (prototype == NULL)
		return NULL;

	prototype->createChildObjects();

	CraftingValues craftingValues = templateObject->getCraftingValuesCopy();

	setInitialObjectStats(templateObject, &craftingValues, prototype);

	setCustomObjectName(prototype, templateObject);

	float excMod = 1.0;

	if (System::random(exceptionalChance) == exceptionalChance) {
		UnicodeString objectName = prototype->getCustomObjectName();
		uint32 bitmask = prototype->getOptionsBitmask() | 0x20;

		if (objectName.isEmpty())
			objectName = StringIdManager::instance()->getStringId(prototype->getObjectName()->getFullPath().hashCode());

		UnicodeString newName = objectName + " (Exceptional)";
		prototype->setCustomObjectName(newName, false);

		excMod = exceptionalModifier;

		prototype->setOptionsBitmask(bitmask, false);
	} else if (System::random(legendaryChance) == legendaryChance) {
		UnicodeString objectName = prototype->getCustomObjectName();
		uint32 bitmask = prototype->getOptionsBitmask() | 0x20;

		if (objectName.isEmpty())
			objectName = StringIdManager::instance()->getStringId(prototype->getObjectName()->getFullPath().hashCode());

		UnicodeString newName = objectName + " (Legendary)";
		prototype->setCustomObjectName(newName, false);

		excMod = legendaryModifier;

		prototype->setOptionsBitmask(bitmask, false);
	}

	String subtitle;

	float percentage = System::random(10000) / 10000.f; //Generate a base percentage. We will deviate slightly from this on each stat.

	for (int i = 0; i < craftingValues.getExperimentalPropertySubtitleSize(); ++i) {
		subtitle = craftingValues.getExperimentalPropertySubtitle(i);

		if (subtitle == "hitpoints")
			continue;

		float min = craftingValues.getMinValue(subtitle);
		float max = craftingValues.getMaxValue(subtitle);

		float minMod = (max >= min) ? 2000.f : -2000.f;
		float maxMod = (max >= min) ? 500.f : -500.f;

		min = (min * level / minMod) + min;
		max = (max * level / maxMod) + max;

		if (max >= min) {
			min *= excMod;
			max *= excMod;
		} else {
			min /= excMod;
			max /= excMod;
		}

		craftingValues.setMinValue(subtitle, min);
		craftingValues.setMaxValue(subtitle, max);

		float deviation = (((float) System::random(400)) - 200) / 1000.f; //Deviate up to 2%

		craftingValues.setCurrentPercentage(subtitle, percentage + deviation);
	}

	// Use percentages to recalculate the values
	craftingValues.recalculateValues(false);

	craftingValues.addExperimentalProperty("creatureLevel", "creatureLevel", level, level, 0, false);

	// Update the Tano with new values
	prototype->updateCraftingValues(&craftingValues, false);

	return prototype;
}

void LootManagerImplementation::createLoot(SceneObject* container, AiAgent* creature) {
	LootGroupCollection* lootGroups = creature->getLootGroups();
	int lootChance = creature->getLootChance();

	if (lootGroups == NULL || lootChance <= 0)
		return;

	//First roll is on what loot group, if any, to use.
	int roll = System::random(10000000); //100.00000% with 5 decimal precision

	if (roll > lootChance) {
		//The creature isn't dropping loot because the roll was in the "no drop" zone of the percentage.
		return;
	}

	int tempChance = 0; //Start at 0.

	//Now loop through the lootgroups to figure out which lootgroup to use.
	for (int i = 0; i < lootGroups->size(); ++i) {
		LootGroupEntry entry = lootGroups->get(i);

		tempChance += entry.getWeight();

		//Is this entry lower than the roll? If yes, then we want to try the next entry.
		if (tempChance < roll)
			continue;

		createLoot(container, entry.getItemTemplate(), creature->getLevel());

		return; //If we got here, then we found the entry we were looking for.
	}
}

void LootManagerImplementation::createLoot(SceneObject* container, const String& lootGroup, int level) {
	if (container->hasFullContainerObjects())
		return;

	Reference<LootGroup*> group = lootGroupMap->get(lootGroup);

	if (group == NULL)
		return;

	//Now we do the second roll for the item out of the group.
	int roll = System::random(10000000);

	int tempChance = 0;

	for (int i = 0; i < group->size(); ++i) {
		if (container->hasFullContainerObjects())
			return;

		LootGroupEntry entry = group->get(i);

		tempChance += entry.getWeight();

		if (tempChance < roll)
			continue; //If the roll is greater than this item, move on to the next one.

		String item = entry.getItemTemplate();

		LootItemTemplate* itemTemplate = lootGroupMap->getLootItem(item);

		if (itemTemplate != NULL) {
			//int minLevel = itemTemplate->getMinimumLevel();
			//int maxLevel = itemTemplate->getMaximumLevel();

			//if (level != -1) {
				//if (minLevel != -1 && level < minLevel)
					//continue;

				//if (maxLevel != -1 && level > maxLevel)
					//continue;
			//}

			SceneObject* obj = createLootObject(itemTemplate, level);

			if (obj != NULL) {
				if (container->transferObject(obj, -1, false))
					container->broadcastObject(obj, true);
			}

		} else {
			error(item + " loot item template not found");
		}

		return;
	}
}
<commit_msg>[fixed] Using optionbitmask class for yellow name.<commit_after>/*
 * LootManagerImplementation.cpp
 *
 *  Created on: Jun 20, 2011
 *      Author: Kyle
 */

#include "engine/engine.h"

#include "LootManager.h"
#include "server/zone/objects/scene/SceneObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/creature/AiAgent.h"
#include "server/zone/managers/crafting/CraftingManager.h"
#include "server/zone/managers/templates/TemplateManager.h"
#include "server/zone/templates/LootItemTemplate.h"
#include "server/zone/ZoneServer.h"
#include "server/zone/managers/stringid/StringIdManager.h"
#include "LootGroupMap.h"

void LootManagerImplementation::initialize() {

	lua = new Lua();
	lua->init();

	info("Loading configuration.");

	if(!loadConfigData()) {

		loadDefaultConfig();

		info("***** ERROR in configuration, using default values");
	}

	lootGroupMap = LootGroupMap::instance();
	lootGroupMap->initialize();

	info("Loaded " + String::valueOf(lootGroupMap->getTotalItems()) + " loot items.", true);
	info("Loaded " + String::valueOf(lootGroupMap->getTotalGroups()) + " loot groups.", true);

	info("Initialized.");
}

bool LootManagerImplementation::loadConfigFile() {
	return lua->runFile("scripts/managers/loot_manager.lua");
}

bool LootManagerImplementation::loadConfigData() {
	if (!loadConfigFile())
		return false;

	exceptionalChance = lua->getGlobalFloat("exceptionalChance");
	exceptionalModifier = lua->getGlobalFloat("exceptionalModifier");
	legendaryChance = lua->getGlobalFloat("legendaryChance");
	legendaryModifier = lua->getGlobalFloat("legendaryModifier");

	LuaObject lootableModsTable = lua->getGlobalObject("lootableStatMods");

	if (!lootableModsTable.isValidTable())
		return false;

	for (int i = 1; i <= lootableModsTable.getTableSize(); ++i) {
		String mod = lootableModsTable.getStringAt(i);
		lootableMods.put(mod);
	}

	lootableModsTable.pop();

	info("Loaded " + String::valueOf(lootableMods.size()) + " lootable stat mods.", true);

	return true;
}

void LootManagerImplementation::loadDefaultConfig() {

}

void LootManagerImplementation::setInitialObjectStats(LootItemTemplate* templateObject, CraftingValues* craftingValues, TangibleObject* prototype) {
	SharedTangibleObjectTemplate* tanoTemplate = dynamic_cast<SharedTangibleObjectTemplate*>(prototype->getObjectTemplate());

	if (tanoTemplate != NULL) {
		Vector<String>* props = tanoTemplate->getExperimentalSubGroupTitles();
		Vector<int>* mins = tanoTemplate->getExperimentalMin();
		Vector<int>* maxs = tanoTemplate->getExperimentalMax();
		Vector<short>* prec = tanoTemplate->getExperimentalPrecision();

		for (int i = 0; i < props->size(); ++i) {
			String property = props->get(i);

			if (craftingValues->hasProperty(property))
				continue;

			craftingValues->addExperimentalProperty(property, property, mins->get(i), maxs->get(i), prec->get(i), false);
		}
	}

	Vector<String>* customizationData = templateObject->getCustomizationStringNames();
	Vector<Vector<int> >* customizationValues = templateObject->getCustomizationValues();

	for (int i = 0; i < customizationData->size(); ++i) {
		String customizationString = customizationData->get(i);
		Vector<int>* values = &customizationValues->get(i);

		int idx = customizationString.lastIndexOf("/");

		if (idx != -1)
			customizationString = customizationString.subString(idx + 1);

		if (values->size() > 0) {
			int randomValue = values->get(System::random(values->size() - 1));

			prototype->setCustomizationVariable(customizationString, randomValue, false);
		}
	}
}

void LootManagerImplementation::setCustomObjectName(TangibleObject* object, LootItemTemplate* templateObject) {
	String customName = templateObject->getCustomObjectName();

	if (!customName.isEmpty()) {
		if (customName.charAt(0) == '@') {
			StringId stringId(customName);

			object->setObjectName(stringId);
		} else {
			object->setCustomObjectName(customName, false);
		}
	}
}

int LootManagerImplementation::calculateLootCredits(int level) {
	int maxcredits = (int) round((.03f * level * level) + (3 * level) + 50);
	int mincredits = (int) round((((float) maxcredits) * .5f) + (2.0f * level));

	int credits = mincredits + System::random(maxcredits - mincredits);

	return credits;
}

SceneObject* LootManagerImplementation::createLootObject(LootItemTemplate* templateObject, int level) {
	String directTemplateObject = templateObject->getDirectObjectTemplate();

	ManagedReference<TangibleObject*> prototype = dynamic_cast<TangibleObject*> (zoneServer->createObject(directTemplateObject.hashCode(), 2));

	if (prototype == NULL)
		return NULL;

	prototype->createChildObjects();

	CraftingValues craftingValues = templateObject->getCraftingValuesCopy();

	setInitialObjectStats(templateObject, &craftingValues, prototype);

	setCustomObjectName(prototype, templateObject);

	float excMod = 1.0;

	if (System::random(exceptionalChance) == exceptionalChance) {
		UnicodeString objectName = prototype->getCustomObjectName();
		uint32 bitmask = prototype->getOptionsBitmask() | OptionBitmask::YELLOW;

		if (objectName.isEmpty())
			objectName = StringIdManager::instance()->getStringId(prototype->getObjectName()->getFullPath().hashCode());

		UnicodeString newName = objectName + " (Exceptional)";
		prototype->setCustomObjectName(newName, false);

		excMod = exceptionalModifier;

		prototype->setOptionsBitmask(bitmask, false);
	} else if (System::random(legendaryChance) == legendaryChance) {
		UnicodeString objectName = prototype->getCustomObjectName();
		uint32 bitmask = prototype->getOptionsBitmask() | OptionBitmask::YELLOW;

		if (objectName.isEmpty())
			objectName = StringIdManager::instance()->getStringId(prototype->getObjectName()->getFullPath().hashCode());

		UnicodeString newName = objectName + " (Legendary)";
		prototype->setCustomObjectName(newName, false);

		excMod = legendaryModifier;

		prototype->setOptionsBitmask(bitmask, false);
	}

	String subtitle;

	float percentage = System::random(10000) / 10000.f; //Generate a base percentage. We will deviate slightly from this on each stat.

	for (int i = 0; i < craftingValues.getExperimentalPropertySubtitleSize(); ++i) {
		subtitle = craftingValues.getExperimentalPropertySubtitle(i);

		if (subtitle == "hitpoints")
			continue;

		float min = craftingValues.getMinValue(subtitle);
		float max = craftingValues.getMaxValue(subtitle);

		float minMod = (max >= min) ? 2000.f : -2000.f;
		float maxMod = (max >= min) ? 500.f : -500.f;

		min = (min * level / minMod) + min;
		max = (max * level / maxMod) + max;

		if (max >= min) {
			min *= excMod;
			max *= excMod;
		} else {
			min /= excMod;
			max /= excMod;
		}

		craftingValues.setMinValue(subtitle, min);
		craftingValues.setMaxValue(subtitle, max);

		float deviation = (((float) System::random(400)) - 200) / 1000.f; //Deviate up to 2%

		craftingValues.setCurrentPercentage(subtitle, percentage + deviation);
	}

	// Use percentages to recalculate the values
	craftingValues.recalculateValues(false);

	craftingValues.addExperimentalProperty("creatureLevel", "creatureLevel", level, level, 0, false);

	// Update the Tano with new values
	prototype->updateCraftingValues(&craftingValues, false);

	return prototype;
}

void LootManagerImplementation::createLoot(SceneObject* container, AiAgent* creature) {
	LootGroupCollection* lootGroups = creature->getLootGroups();
	int lootChance = creature->getLootChance();

	if (lootGroups == NULL || lootChance <= 0)
		return;

	//First roll is on what loot group, if any, to use.
	int roll = System::random(10000000); //100.00000% with 5 decimal precision

	if (roll > lootChance) {
		//The creature isn't dropping loot because the roll was in the "no drop" zone of the percentage.
		return;
	}

	int tempChance = 0; //Start at 0.

	//Now loop through the lootgroups to figure out which lootgroup to use.
	for (int i = 0; i < lootGroups->size(); ++i) {
		LootGroupEntry entry = lootGroups->get(i);

		tempChance += entry.getWeight();

		//Is this entry lower than the roll? If yes, then we want to try the next entry.
		if (tempChance < roll)
			continue;

		createLoot(container, entry.getItemTemplate(), creature->getLevel());

		return; //If we got here, then we found the entry we were looking for.
	}
}

void LootManagerImplementation::createLoot(SceneObject* container, const String& lootGroup, int level) {
	if (container->hasFullContainerObjects())
		return;

	Reference<LootGroup*> group = lootGroupMap->get(lootGroup);

	if (group == NULL)
		return;

	//Now we do the second roll for the item out of the group.
	int roll = System::random(10000000);

	int tempChance = 0;

	for (int i = 0; i < group->size(); ++i) {
		if (container->hasFullContainerObjects())
			return;

		LootGroupEntry entry = group->get(i);

		tempChance += entry.getWeight();

		if (tempChance < roll)
			continue; //If the roll is greater than this item, move on to the next one.

		String item = entry.getItemTemplate();

		LootItemTemplate* itemTemplate = lootGroupMap->getLootItem(item);

		if (itemTemplate != NULL) {
			//int minLevel = itemTemplate->getMinimumLevel();
			//int maxLevel = itemTemplate->getMaximumLevel();

			//if (level != -1) {
				//if (minLevel != -1 && level < minLevel)
					//continue;

				//if (maxLevel != -1 && level > maxLevel)
					//continue;
			//}

			SceneObject* obj = createLootObject(itemTemplate, level);

			if (obj != NULL) {
				if (container->transferObject(obj, -1, false))
					container->broadcastObject(obj, true);
			}

		} else {
			error(item + " loot item template not found");
		}

		return;
	}
}
<|endoftext|>


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

#include "chrome/browser/extensions/api/notification_provider/notification_provider_api.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/notification_provider.h"

typedef ExtensionApiTest NotificationProviderApiTest;

IN_PROC_BROWSER_TEST_F(NotificationProviderApiTest, Events) {
  std::string sender_id1 = "SenderId1";
  std::string notification_id1 = "NotificationId1";

  extensions::api::notifications::NotificationOptions options;
  options.type = extensions::api::notifications::ParseTemplateType("basic");
  options.icon_url = scoped_ptr<std::string>(new std::string("icon.png"));
  options.title = scoped_ptr<std::string>(new std::string("Title"));
  options.message =
      scoped_ptr<std::string>(new std::string("Here goes the message"));

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());

  // Test notification provider extension
  const extensions::Extension* extension =
      LoadExtension(test_data_dir_.AppendASCII("notification_provider/events"));
  ASSERT_TRUE(extension);

  extensions::NotificationProviderEventRouter* event_router =
      new extensions::NotificationProviderEventRouter(browser()->profile());

  event_router->CreateNotification(
      extension->id(), sender_id1, notification_id1, options);
  event_router->UpdateNotification(
      extension->id(), sender_id1, notification_id1, options);
  event_router->ClearNotification(
      extension->id(), sender_id1, notification_id1);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<commit_msg>Fix memory leak in NotificationProviderApiTest.Events.<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/api/notification_provider/notification_provider_api.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/notification_provider.h"

typedef ExtensionApiTest NotificationProviderApiTest;

IN_PROC_BROWSER_TEST_F(NotificationProviderApiTest, Events) {
  std::string sender_id1 = "SenderId1";
  std::string notification_id1 = "NotificationId1";

  extensions::api::notifications::NotificationOptions options;
  options.type = extensions::api::notifications::ParseTemplateType("basic");
  options.icon_url = scoped_ptr<std::string>(new std::string("icon.png"));
  options.title = scoped_ptr<std::string>(new std::string("Title"));
  options.message =
      scoped_ptr<std::string>(new std::string("Here goes the message"));

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());

  // Test notification provider extension
  const extensions::Extension* extension =
      LoadExtension(test_data_dir_.AppendASCII("notification_provider/events"));
  ASSERT_TRUE(extension);

  scoped_ptr<extensions::NotificationProviderEventRouter> event_router(
      new extensions::NotificationProviderEventRouter(browser()->profile()));

  event_router->CreateNotification(
      extension->id(), sender_id1, notification_id1, options);
  event_router->UpdateNotification(
      extension->id(), sender_id1, notification_id1, options);
  event_router->ClearNotification(
      extension->id(), sender_id1, notification_id1);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#ifndef ERROR_HANDLING_HPP
#define ERROR_HANDLING_HPP

#include <string>
#include <realm.hpp>
#include "realm_error_type.hpp"

namespace realm {
struct NativeException {
    RealmErrorType type;
    std::string message;

    struct Marshallable {
        RealmErrorType type;
        const char* messagesBytes;
        size_t messageLength;
    };

    Marshallable for_marshalling() const {
        auto messageCopy = new char[message.size()];
        message.copy(messageCopy, message.length());

        return {
            type,
            messageCopy,
            message.size()
        };
    }
};

class RowDetachedException : public std::runtime_error {
public:
    RowDetachedException() : std::runtime_error("Attempted to access detached row") {}
};

NativeException convert_exception();

void throw_managed_exception(const NativeException& exception);

template <class T>
struct Default {
    static T default_value() {
        return T{};
    }
};
template <>
struct Default<void> {
    static void default_value() {}
};

template <class F>
auto handle_errors(F&& func) -> decltype(func())
{
    using RetVal = decltype(func());
    try {
        return func();
    }
    catch (...) {
        throw_managed_exception(convert_exception());
        return Default<RetVal>::default_value();
    }
}

template <class F>
auto handle_errors_param(F&& func, NativeException::Marshallable& ex) -> decltype(func())
{
    using RetVal = decltype(func());
    ex.type = RealmErrorType::NoError;
    try {
        return func();
    }
    catch (...) {
        ex = convert_exception().for_marshalling();
        return Default<RetVal>::default_value();
    }
}

} // namespace realm

#endif // ERROR_HANDLING_HPP
<commit_msg>Make NativeException::Marshallable::messageBytes a void* instead of a char*<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#ifndef ERROR_HANDLING_HPP
#define ERROR_HANDLING_HPP

#include <string>
#include <new>
#include <realm.hpp>
#include "realm_error_type.hpp"

namespace realm {
struct NativeException {
    RealmErrorType type;
    std::string message;

    struct Marshallable {
        RealmErrorType type;
        void* messagesBytes;
        size_t messageLength;
    };

    Marshallable for_marshalling() const {
        auto messageCopy = ::operator new (message.size());
        message.copy(reinterpret_cast<char*>(messageCopy), message.length());

        return {
            type,
            messageCopy,
            message.size()
        };
    }
};

class RowDetachedException : public std::runtime_error {
public:
    RowDetachedException() : std::runtime_error("Attempted to access detached row") {}
};

NativeException convert_exception();

void throw_managed_exception(const NativeException& exception);

template <class T>
struct Default {
    static T default_value() {
        return T{};
    }
};
template <>
struct Default<void> {
    static void default_value() {}
};

template <class F>
auto handle_errors(F&& func) -> decltype(func())
{
    using RetVal = decltype(func());
    try {
        return func();
    }
    catch (...) {
        throw_managed_exception(convert_exception());
        return Default<RetVal>::default_value();
    }
}

template <class F>
auto handle_errors_param(F&& func, NativeException::Marshallable& ex) -> decltype(func())
{
    using RetVal = decltype(func());
    ex.type = RealmErrorType::NoError;
    try {
        return func();
    }
    catch (...) {
        ex = convert_exception().for_marshalling();
        return Default<RetVal>::default_value();
    }
}

} // namespace realm

#endif // ERROR_HANDLING_HPP
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: networkdomain.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 13:57:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_framework.hxx"

#ifndef __FRAMEWORK_HELPER_NETWORKDOMAIN_HXX_
#include <helper/networkdomain.hxx>
#endif

namespace framework
{

#ifdef WNT
//_________________________________________________________________________________________________________________
//  Windows
//_________________________________________________________________________________________________________________

#define UNICODE
#include <windows.h>

//_________________________________________________________________________________________________________________
//  Win NT, Win 2000, Win XP
//_________________________________________________________________________________________________________________

static DWORD WINAPI GetUserDomainW_NT( LPWSTR lpBuffer, DWORD nSize )
{
    return GetEnvironmentVariable( TEXT("USERDOMAIN"), lpBuffer, nSize );
}

//_________________________________________________________________________________________________________________
//  Win 9x,Win ME
//_________________________________________________________________________________________________________________

static DWORD WINAPI GetUserDomainW_WINDOWS( LPWSTR lpBuffer, DWORD nSize )
{
    HKEY    hkeyLogon;
    HKEY    hkeyWorkgroup;
    DWORD   dwResult = 0;

    if ( ERROR_SUCCESS  == RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        TEXT("Network\\Logon"),
        0, KEY_READ, &hkeyLogon ) )
    {
        DWORD   dwLogon = 0;
        DWORD   dwLogonSize = sizeof(dwLogon);
        LONG    lResult = RegQueryValueEx( hkeyLogon, TEXT("LMLogon"), 0, NULL, (LPBYTE)&dwLogon, &dwLogonSize );
        RegCloseKey( hkeyLogon );

        if ( dwLogon )
        {
            HKEY    hkeyNetworkProvider;

            if ( ERROR_SUCCESS  == RegOpenKeyEx(
                HKEY_LOCAL_MACHINE,
                TEXT("SYSTEM\\CurrentControlSet\\Services\\MSNP32\\NetworkProvider"),
                0, KEY_READ, &hkeyNetworkProvider ) )
            {
                DWORD   dwBufferSize = nSize;
                LONG    lResult = RegQueryValueEx( hkeyNetworkProvider, TEXT("AuthenticatingAgent"), 0, NULL, (LPBYTE)lpBuffer, &dwBufferSize );

                if ( ERROR_SUCCESS == lResult || ERROR_MORE_DATA == lResult )
                    dwResult = dwBufferSize / sizeof(TCHAR);

                RegCloseKey( hkeyNetworkProvider );
            }
        }
    }
    else if ( ERROR_SUCCESS == RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        TEXT("SYSTEM\\CurrentControlSet\\Services\\VxD\\VNETSUP"),
        0, KEY_READ, &hkeyWorkgroup ) )
    {
        DWORD   dwBufferSize = nSize;
        LONG    lResult = RegQueryValueEx( hkeyWorkgroup, TEXT("Workgroup"), 0, NULL, (LPBYTE)lpBuffer, &dwBufferSize );

        if ( ERROR_SUCCESS == lResult || ERROR_MORE_DATA == lResult )
            dwResult = dwBufferSize / sizeof(TCHAR);

        RegCloseKey( hkeyWorkgroup );
    }

    return dwResult;
}

static rtl::OUString GetUserDomain()
{
    sal_Unicode aBuffer[256];

    long    nVersion = GetVersion();
    DWORD   nResult;

    if ( nVersion < 0 )
        nResult = GetUserDomainW_WINDOWS( aBuffer, sizeof( aBuffer ) );
    else
        nResult = GetUserDomainW_NT( aBuffer, sizeof( aBuffer ) );

    if ( nResult > 0 )
        return rtl::OUString( aBuffer );
    else
        return rtl::OUString();
}

//_________________________________________________________________________________________________________________
//  Windows
//_________________________________________________________________________________________________________________

rtl::OUString NetworkDomain::GetYPDomainName()
{
    return ::rtl::OUString();
}

rtl::OUString NetworkDomain::GetNTDomainName()
{
    return GetUserDomain();
}

#elif defined( UNIX )

#include <rtl/ustring.h>
#include <stdlib.h>
#include <errno.h>
#include <osl/thread.h>

//_________________________________________________________________________________________________________________
//  Unix
//_________________________________________________________________________________________________________________

#if defined( SOLARIS )

//_________________________________________________________________________________________________________________
//  Solaris
//_________________________________________________________________________________________________________________

#include <sys/systeminfo.h>
#include <sal/alloca.h>

static rtl_uString *getDomainName()
{
    /* Initialize and assume failure */
    rtl_uString *ustrDomainName = NULL;

    char    szBuffer[256];

    long    nCopied = sizeof(szBuffer);
    char    *pBuffer = szBuffer;
    long    nBufSize;

    do
    {
        nBufSize = nCopied;
        nCopied = sysinfo( SI_SRPC_DOMAIN, pBuffer, nBufSize );

        /*  If nCopied is greater than buffersize we need to allocate
            a buffer with suitable size */

        if ( nCopied > nBufSize )
            pBuffer = (char *)alloca( nCopied );

    } while ( nCopied > nBufSize );

    if ( -1 != nCopied  )
    {
        rtl_string2UString(
            &ustrDomainName,
            pBuffer,
            nCopied - 1,
            osl_getThreadTextEncoding(),
            OSTRING_TO_OUSTRING_CVTFLAGS );
    }

    return ustrDomainName;
}

#elif defined( LINUX ) /* endif SOLARIS */

//_________________________________________________________________________________________________________________
//  Linux
//_________________________________________________________________________________________________________________

#include <unistd.h>
#include <string.h>

static rtl_uString *getDomainName()
{
    /* Initialize and assume failure */
    rtl_uString *ustrDomainName = NULL;

    char    *pBuffer;
    int     result;
    size_t  nBufSize = 0;

    do
    {
        nBufSize += 256; /* Increase buffer size by steps of 256 bytes */
        pBuffer = (char *)alloca( nBufSize );
        result = getdomainname( pBuffer, nBufSize );
        /* If buffersize in not large enough -1 is returned and errno
        is set to EINVAL. This only applies to libc. With glibc the name
        is truncated. */
    } while ( -1 == result && EINVAL == errno );

    if ( 0 == result )
    {
        rtl_string2UString(
            &ustrDomainName,
            pBuffer,
            strlen( pBuffer ),
            osl_getThreadTextEncoding(),
            OSTRING_TO_OUSTRING_CVTFLAGS );
    }

    return ustrDomainName;
}

#else /* LINUX */

//_________________________________________________________________________________________________________________
//  Other Unix
//_________________________________________________________________________________________________________________

static rtl_uString *getDomainName()
{
    return NULL;
}

#endif

//_________________________________________________________________________________________________________________
//  Unix
//_________________________________________________________________________________________________________________

rtl::OUString NetworkDomain::GetYPDomainName()
{
    rtl_uString* pResult = getDomainName();
    if ( pResult )
        return rtl::OUString( pResult );
    else
        return rtl::OUString();
}

rtl::OUString NetworkDomain::GetNTDomainName()
{
    return ::rtl::OUString();
}

#else /* UNIX */

//_________________________________________________________________________________________________________________
//  Other operating systems (non-Windows and non-Unix)
//_________________________________________________________________________________________________________________

rtl::OUString NetworkDomain::GetYPDomainName()
{
    return rtl::OUString();
}

rtl::OUString NetworkDomain::GetNTDomainName()
{
    return rtl::OUString();
}

#endif

} // namespace framework
<commit_msg>INTEGRATION: CWS sb59 (1.5.142); FILE MERGED 2006/08/10 08:16:20 sb 1.5.142.1: #i67487# Made code warning-free (wntmsci10).<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: networkdomain.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 10:40:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_framework.hxx"

#ifndef __FRAMEWORK_HELPER_NETWORKDOMAIN_HXX_
#include <helper/networkdomain.hxx>
#endif

namespace framework
{

#ifdef WNT
//_________________________________________________________________________________________________________________
//  Windows
//_________________________________________________________________________________________________________________

#define UNICODE
#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#include <windows.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif

//_________________________________________________________________________________________________________________
//  Win NT, Win 2000, Win XP
//_________________________________________________________________________________________________________________

static DWORD WINAPI GetUserDomainW_NT( LPWSTR lpBuffer, DWORD nSize )
{
    return GetEnvironmentVariable( TEXT("USERDOMAIN"), lpBuffer, nSize );
}

//_________________________________________________________________________________________________________________
//  Win 9x,Win ME
//_________________________________________________________________________________________________________________

static DWORD WINAPI GetUserDomainW_WINDOWS( LPWSTR lpBuffer, DWORD nSize )
{
    HKEY    hkeyLogon;
    HKEY    hkeyWorkgroup;
    DWORD   dwResult = 0;

    if ( ERROR_SUCCESS  == RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        TEXT("Network\\Logon"),
        0, KEY_READ, &hkeyLogon ) )
    {
        DWORD   dwLogon = 0;
        DWORD   dwLogonSize = sizeof(dwLogon);
        RegQueryValueEx( hkeyLogon, TEXT("LMLogon"), 0, NULL, (LPBYTE)&dwLogon, &dwLogonSize );
        RegCloseKey( hkeyLogon );

        if ( dwLogon )
        {
            HKEY    hkeyNetworkProvider;

            if ( ERROR_SUCCESS  == RegOpenKeyEx(
                HKEY_LOCAL_MACHINE,
                TEXT("SYSTEM\\CurrentControlSet\\Services\\MSNP32\\NetworkProvider"),
                0, KEY_READ, &hkeyNetworkProvider ) )
            {
                DWORD   dwBufferSize = nSize;
                LONG    lResult = RegQueryValueEx( hkeyNetworkProvider, TEXT("AuthenticatingAgent"), 0, NULL, (LPBYTE)lpBuffer, &dwBufferSize );

                if ( ERROR_SUCCESS == lResult || ERROR_MORE_DATA == lResult )
                    dwResult = dwBufferSize / sizeof(TCHAR);

                RegCloseKey( hkeyNetworkProvider );
            }
        }
    }
    else if ( ERROR_SUCCESS == RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        TEXT("SYSTEM\\CurrentControlSet\\Services\\VxD\\VNETSUP"),
        0, KEY_READ, &hkeyWorkgroup ) )
    {
        DWORD   dwBufferSize = nSize;
        LONG    lResult = RegQueryValueEx( hkeyWorkgroup, TEXT("Workgroup"), 0, NULL, (LPBYTE)lpBuffer, &dwBufferSize );

        if ( ERROR_SUCCESS == lResult || ERROR_MORE_DATA == lResult )
            dwResult = dwBufferSize / sizeof(TCHAR);

        RegCloseKey( hkeyWorkgroup );
    }

    return dwResult;
}

static rtl::OUString GetUserDomain()
{
    sal_Unicode aBuffer[256];

    long    nVersion = GetVersion();
    DWORD   nResult;

    if ( nVersion < 0 )
        nResult = GetUserDomainW_WINDOWS( aBuffer, sizeof( aBuffer ) );
    else
        nResult = GetUserDomainW_NT( aBuffer, sizeof( aBuffer ) );

    if ( nResult > 0 )
        return rtl::OUString( aBuffer );
    else
        return rtl::OUString();
}

//_________________________________________________________________________________________________________________
//  Windows
//_________________________________________________________________________________________________________________

rtl::OUString NetworkDomain::GetYPDomainName()
{
    return ::rtl::OUString();
}

rtl::OUString NetworkDomain::GetNTDomainName()
{
    return GetUserDomain();
}

#elif defined( UNIX )

#include <rtl/ustring.h>
#include <stdlib.h>
#include <errno.h>
#include <osl/thread.h>

//_________________________________________________________________________________________________________________
//  Unix
//_________________________________________________________________________________________________________________

#if defined( SOLARIS )

//_________________________________________________________________________________________________________________
//  Solaris
//_________________________________________________________________________________________________________________

#include <sys/systeminfo.h>
#include <sal/alloca.h>

static rtl_uString *getDomainName()
{
    /* Initialize and assume failure */
    rtl_uString *ustrDomainName = NULL;

    char    szBuffer[256];

    long    nCopied = sizeof(szBuffer);
    char    *pBuffer = szBuffer;
    long    nBufSize;

    do
    {
        nBufSize = nCopied;
        nCopied = sysinfo( SI_SRPC_DOMAIN, pBuffer, nBufSize );

        /*  If nCopied is greater than buffersize we need to allocate
            a buffer with suitable size */

        if ( nCopied > nBufSize )
            pBuffer = (char *)alloca( nCopied );

    } while ( nCopied > nBufSize );

    if ( -1 != nCopied  )
    {
        rtl_string2UString(
            &ustrDomainName,
            pBuffer,
            nCopied - 1,
            osl_getThreadTextEncoding(),
            OSTRING_TO_OUSTRING_CVTFLAGS );
    }

    return ustrDomainName;
}

#elif defined( LINUX ) /* endif SOLARIS */

//_________________________________________________________________________________________________________________
//  Linux
//_________________________________________________________________________________________________________________

#include <unistd.h>
#include <string.h>

static rtl_uString *getDomainName()
{
    /* Initialize and assume failure */
    rtl_uString *ustrDomainName = NULL;

    char    *pBuffer;
    int     result;
    size_t  nBufSize = 0;

    do
    {
        nBufSize += 256; /* Increase buffer size by steps of 256 bytes */
        pBuffer = (char *)alloca( nBufSize );
        result = getdomainname( pBuffer, nBufSize );
        /* If buffersize in not large enough -1 is returned and errno
        is set to EINVAL. This only applies to libc. With glibc the name
        is truncated. */
    } while ( -1 == result && EINVAL == errno );

    if ( 0 == result )
    {
        rtl_string2UString(
            &ustrDomainName,
            pBuffer,
            strlen( pBuffer ),
            osl_getThreadTextEncoding(),
            OSTRING_TO_OUSTRING_CVTFLAGS );
    }

    return ustrDomainName;
}

#else /* LINUX */

//_________________________________________________________________________________________________________________
//  Other Unix
//_________________________________________________________________________________________________________________

static rtl_uString *getDomainName()
{
    return NULL;
}

#endif

//_________________________________________________________________________________________________________________
//  Unix
//_________________________________________________________________________________________________________________

rtl::OUString NetworkDomain::GetYPDomainName()
{
    rtl_uString* pResult = getDomainName();
    if ( pResult )
        return rtl::OUString( pResult );
    else
        return rtl::OUString();
}

rtl::OUString NetworkDomain::GetNTDomainName()
{
    return ::rtl::OUString();
}

#else /* UNIX */

//_________________________________________________________________________________________________________________
//  Other operating systems (non-Windows and non-Unix)
//_________________________________________________________________________________________________________________

rtl::OUString NetworkDomain::GetYPDomainName()
{
    return rtl::OUString();
}

rtl::OUString NetworkDomain::GetNTDomainName()
{
    return rtl::OUString();
}

#endif

} // namespace framework
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "AirMapRulesetsManager.h"
#include "AirMapManager.h"
#include <QSettings>

using namespace airmap;

static const char* kAirMapFeatureGroup = "AirMapFeatureGroup";

//-----------------------------------------------------------------------------
AirMapRuleFeature::AirMapRuleFeature(QObject* parent)
    : AirspaceRuleFeature(parent)
{
}

//-----------------------------------------------------------------------------
AirMapRuleFeature::AirMapRuleFeature(airmap::RuleSet::Feature feature, QObject* parent)
    : AirspaceRuleFeature(parent)
    , _feature(feature)
{
    //-- Restore persisted value (if it exists)
    QSettings settings;
    settings.beginGroup(kAirMapFeatureGroup);
    switch(_feature.type) {
    case RuleSet::Feature::Type::boolean:
        _value = settings.value(name(), false);
        break;;
    case RuleSet::Feature::Type::floating_point:
        _value = settings.value(name(), 0.0f);
        break;;
    case RuleSet::Feature::Type::string:
        _value = settings.value(name(), QString());
        break;;
    default:
        break;
    }
    settings.endGroup();
}

//-----------------------------------------------------------------------------
AirspaceRuleFeature::Type
AirMapRuleFeature::type()
{
    switch(_feature.type) {
    case RuleSet::Feature::Type::boolean:
        return AirspaceRuleFeature::Boolean;
    case RuleSet::Feature::Type::floating_point:
        return AirspaceRuleFeature::Float;
    case RuleSet::Feature::Type::string:
        return AirspaceRuleFeature::String;
    default:
        break;
    }
    return AirspaceRuleFeature::Unknown;
}

//-----------------------------------------------------------------------------
AirspaceRuleFeature::Unit
AirMapRuleFeature::unit()
{
    switch(_feature.unit) {
    case RuleSet::Feature::Unit::kilograms:
        return AirspaceRuleFeature::Kilogram;
    case RuleSet::Feature::Unit::meters:
        return AirspaceRuleFeature::Meters;
    case RuleSet::Feature::Unit::meters_per_sec:
        return AirspaceRuleFeature::MetersPerSecond;
    default:
        break;
    }
    return AirspaceRuleFeature::UnknownUnit;
}

//-----------------------------------------------------------------------------
AirspaceRuleFeature::Measurement
AirMapRuleFeature::measurement()
{
    switch(_feature.measurement) {
    case RuleSet::Feature::Measurement::speed:
        return AirspaceRuleFeature::Speed;
    case RuleSet::Feature::Measurement::weight:
        return AirspaceRuleFeature::Weight;
    case RuleSet::Feature::Measurement::distance:
        return AirspaceRuleFeature::Distance;
    default:
        break;
    }
    return AirspaceRuleFeature::UnknownMeasurement;
}

//-----------------------------------------------------------------------------
void
AirMapRuleFeature::setValue(const QVariant val)
{
    _value = val;
    //-- Make value persistent
    QSettings settings;
    settings.beginGroup(kAirMapFeatureGroup);
    settings.setValue(name(), _value);
    settings.endGroup();
    emit valueChanged();
}

//-----------------------------------------------------------------------------
AirMapRule::AirMapRule(QObject* parent)
    : AirspaceRule(parent)
{
}

//-----------------------------------------------------------------------------
AirMapRule::AirMapRule(const airmap::RuleSet::Rule& rule, QObject* parent)
    : AirspaceRule(parent)
    , _rule(rule)
{
}

//-----------------------------------------------------------------------------
AirMapRule::~AirMapRule()
{
    _features.deleteListAndContents();
}

//-----------------------------------------------------------------------------
AirspaceRule::Status
AirMapRule::status()
{
    switch(_rule.status) {
    case RuleSet::Rule::Status::conflicting:
        return AirspaceRule::Conflicting;
    case RuleSet::Rule::Status::not_conflicting:
        return AirspaceRule::NotConflicting;
    case RuleSet::Rule::Status::missing_info:
        return AirspaceRule::MissingInfo;
    case RuleSet::Rule::Status::unknown:
    default:
        return AirspaceRule::Unknown;
    }
}

//-----------------------------------------------------------------------------
AirMapRuleSet::AirMapRuleSet(QObject* parent)
    : AirspaceRuleSet(parent)
    , _isDefault(false)
    , _selected(false)
    , _selectionType(AirspaceRuleSet::Optional)
{
}

//-----------------------------------------------------------------------------
AirMapRuleSet::~AirMapRuleSet()
{
    _rules.deleteListAndContents();
}

//-----------------------------------------------------------------------------
void
AirMapRuleSet::setSelected(bool sel)
{
    if(_selectionType != AirspaceRuleSet::Required) {
        _selected = sel;
    } else {
        _selected = true;
    }
    emit selectedChanged();
}

//-----------------------------------------------------------------------------
AirMapRulesetsManager::AirMapRulesetsManager(AirMapSharedState& shared)
    : _shared(shared)
{
}

//-----------------------------------------------------------------------------
static bool
rules_sort(QObject* a, QObject* b)
{
    AirMapRule* aa = qobject_cast<AirMapRule*>(a);
    AirMapRule* bb = qobject_cast<AirMapRule*>(b);
    if(!aa || !bb) return false;
    return (int)aa->order() > (int)bb->order();
}

//-----------------------------------------------------------------------------
void AirMapRulesetsManager::setROI(const QGCGeoBoundingCube& roi)
{
    if (!_shared.client()) {
        qCDebug(AirMapManagerLog) << "No AirMap client instance. Not updating Airspace";
        return;
    }
    if (_state != State::Idle) {
        qCWarning(AirMapManagerLog) << "AirMapRulesetsManager::updateROI: state not idle";
        return;
    }
    qCDebug(AirMapManagerLog) << "Rulesets Request (ROI Changed)";
    _valid = false;
    _ruleSets.clearAndDeleteContents();
    _state = State::RetrieveItems;
    RuleSets::Search::Parameters params;
    //-- Geometry: Polygon
    Geometry::Polygon polygon;
    for (const auto& qcoord : roi.polygon2D()) {
        Geometry::Coordinate coord;
        coord.latitude  = qcoord.latitude();
        coord.longitude = qcoord.longitude();
        polygon.outer_ring.coordinates.push_back(coord);
    }
    params.geometry = Geometry(polygon);
    std::weak_ptr<LifetimeChecker> isAlive(_instance);
    _shared.client()->rulesets().search(params,
            [this, isAlive](const RuleSets::Search::Result& result) {
        if (!isAlive.lock()) return;
        if (_state != State::RetrieveItems) return;
        if (result) {
            const std::vector<RuleSet> rulesets = result.value();
            qCDebug(AirMapManagerLog) << "Successful rulesets search. Items:" << rulesets.size();
            for (const auto& ruleset : rulesets) {
                AirMapRuleSet* pRuleSet = new AirMapRuleSet(this);
                connect(pRuleSet, &AirspaceRuleSet::selectedChanged, this, &AirMapRulesetsManager::_selectedChanged);
                pRuleSet->_id          = QString::fromStdString(ruleset.id);
                pRuleSet->_name        = QString::fromStdString(ruleset.name);
                pRuleSet->_shortName   = QString::fromStdString(ruleset.short_name);
                pRuleSet->_description = QString::fromStdString(ruleset.description);
                pRuleSet->_isDefault   = ruleset.is_default;
                //-- TODO: This should be persistent and if the new incoming set has the
                //   same, previosuly selected rulesets, it should "remember".
                if(pRuleSet->_isDefault) {
                    pRuleSet->_selected = true;
                }
                switch(ruleset.selection_type) {
                case RuleSet::SelectionType::pickone:
                    pRuleSet->_selectionType = AirspaceRuleSet::Pickone;
                    break;
                case RuleSet::SelectionType::required:
                    pRuleSet->_selectionType = AirspaceRuleSet::Required;
                    pRuleSet->_selected = true;
                    break;
                default:
                case RuleSet::SelectionType::optional:
                    pRuleSet->_selectionType = AirspaceRuleSet::Optional;
                    break;
                }
                //-- Iterate Rules
                for (const auto& rule : ruleset.rules) {
                    AirMapRule* pRule = new AirMapRule(rule, this);
                    //-- Iterate Rule Features
                    for (const auto& feature : rule.features) {
                        AirMapRuleFeature* pFeature = new AirMapRuleFeature(feature, this);
                        pRule->_features.append(pFeature);
                    }
                    pRuleSet->_rules.append(pRule);
                }
                //-- Sort rules by display order
                std::sort(pRuleSet->_rules.objectList()->begin(), pRuleSet->_rules.objectList()->end(), rules_sort);
                _ruleSets.append(pRuleSet);
                qCDebug(AirMapManagerLog) << "Adding ruleset" << pRuleSet->name();
                /*
                qDebug() << "------------------------------------------";
                qDebug() << "Jurisdiction:" << ruleset.jurisdiction.name.data() << (int)ruleset.jurisdiction.region;
                qDebug() << "Name:        " << ruleset.name.data();
                qDebug() << "Short Name:  " << ruleset.short_name.data();
                qDebug() << "Description: " << ruleset.description.data();
                qDebug() << "Is default:  " << ruleset.is_default;
                qDebug() << "Applicable to these airspace types:";
                for (const auto& airspaceType : ruleset.airspace_types) {
                    qDebug() << "  " << airspaceType.data();
                }
                qDebug() << "Rules:";
                for (const auto& rule : ruleset.rules) {
                    qDebug() << "    --------------------------------------";
                    qDebug() << "    short_text:   " << rule.short_text.data();
                    qDebug() << "    description:  " << rule.description.data();
                    qDebug() << "    display_order:" << rule.display_order;
                    qDebug() << "    status:       " << (int)rule.status;
                    qDebug() << "            ------------------------------";
                    qDebug() << "            Features:";
                    for (const auto& feature : rule.features) {
                        qDebug() << "            name:       " << feature.name.data();
                        qDebug() << "            description:" << feature.description.data();
                        qDebug() << "            status:     " << (int)feature.status;
                        qDebug() << "            type:       " << (int)feature.type;
                        qDebug() << "            measurement:" << (int)feature.measurement;
                        qDebug() << "            unit:       " << (int)feature.unit;
                    }
                }
                */
            }
            _valid = true;
        } else {
            QString description = QString::fromStdString(result.error().description() ? result.error().description().get() : "");
            emit error("Failed to retrieve RuleSets", QString::fromStdString(result.error().message()), description);
        }
        _state = State::Idle;
        emit ruleSetsChanged();
        emit selectedRuleSetsChanged();
    });
}

//-----------------------------------------------------------------------------
QString
AirMapRulesetsManager::selectedRuleSets()
{
    QString selection;
    for(int i = 0; i < _ruleSets.count(); i++) {
        AirMapRuleSet* rule = qobject_cast<AirMapRuleSet*>(_ruleSets.get(i));
        if(rule && rule->selected()) {
            selection += rule->shortName() + ", ";
        }
    }
    int idx = selection.lastIndexOf(", ");
    if(idx >= 0) {
        selection = selection.left(idx);
    }
    return selection;
}

//-----------------------------------------------------------------------------
void
AirMapRulesetsManager::_selectedChanged()
{
    emit selectedRuleSetsChanged();
    //-- TODO: Do whatever it is you do to select a rule
}
<commit_msg>Make all numeric values default to 1 (as opposed to 0) for the time being.<commit_after>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "AirMapRulesetsManager.h"
#include "AirMapManager.h"
#include <QSettings>

using namespace airmap;

static const char* kAirMapFeatureGroup = "AirMapFeatureGroup";

//-----------------------------------------------------------------------------
AirMapRuleFeature::AirMapRuleFeature(QObject* parent)
    : AirspaceRuleFeature(parent)
{
}

//-----------------------------------------------------------------------------
AirMapRuleFeature::AirMapRuleFeature(airmap::RuleSet::Feature feature, QObject* parent)
    : AirspaceRuleFeature(parent)
    , _feature(feature)
{
    //-- Restore persisted value (if it exists)
    QSettings settings;
    settings.beginGroup(kAirMapFeatureGroup);
    switch(_feature.type) {
    case RuleSet::Feature::Type::boolean:
        _value = settings.value(name(), false);
        break;;
    case RuleSet::Feature::Type::floating_point:
        //_value = settings.value(name(), 0.0f);
        //-- Default to 1 for now
        _value = settings.value(name(), 1.0f);
        break;;
    case RuleSet::Feature::Type::string:
        _value = settings.value(name(), QString());
        break;;
    default:
        break;
    }
    settings.endGroup();
}

//-----------------------------------------------------------------------------
AirspaceRuleFeature::Type
AirMapRuleFeature::type()
{
    switch(_feature.type) {
    case RuleSet::Feature::Type::boolean:
        return AirspaceRuleFeature::Boolean;
    case RuleSet::Feature::Type::floating_point:
        return AirspaceRuleFeature::Float;
    case RuleSet::Feature::Type::string:
        return AirspaceRuleFeature::String;
    default:
        break;
    }
    return AirspaceRuleFeature::Unknown;
}

//-----------------------------------------------------------------------------
AirspaceRuleFeature::Unit
AirMapRuleFeature::unit()
{
    switch(_feature.unit) {
    case RuleSet::Feature::Unit::kilograms:
        return AirspaceRuleFeature::Kilogram;
    case RuleSet::Feature::Unit::meters:
        return AirspaceRuleFeature::Meters;
    case RuleSet::Feature::Unit::meters_per_sec:
        return AirspaceRuleFeature::MetersPerSecond;
    default:
        break;
    }
    return AirspaceRuleFeature::UnknownUnit;
}

//-----------------------------------------------------------------------------
AirspaceRuleFeature::Measurement
AirMapRuleFeature::measurement()
{
    switch(_feature.measurement) {
    case RuleSet::Feature::Measurement::speed:
        return AirspaceRuleFeature::Speed;
    case RuleSet::Feature::Measurement::weight:
        return AirspaceRuleFeature::Weight;
    case RuleSet::Feature::Measurement::distance:
        return AirspaceRuleFeature::Distance;
    default:
        break;
    }
    return AirspaceRuleFeature::UnknownMeasurement;
}

//-----------------------------------------------------------------------------
void
AirMapRuleFeature::setValue(const QVariant val)
{
    _value = val;
    //-- Make value persistent
    QSettings settings;
    settings.beginGroup(kAirMapFeatureGroup);
    settings.setValue(name(), _value);
    settings.endGroup();
    emit valueChanged();
}

//-----------------------------------------------------------------------------
AirMapRule::AirMapRule(QObject* parent)
    : AirspaceRule(parent)
{
}

//-----------------------------------------------------------------------------
AirMapRule::AirMapRule(const airmap::RuleSet::Rule& rule, QObject* parent)
    : AirspaceRule(parent)
    , _rule(rule)
{
}

//-----------------------------------------------------------------------------
AirMapRule::~AirMapRule()
{
    _features.deleteListAndContents();
}

//-----------------------------------------------------------------------------
AirspaceRule::Status
AirMapRule::status()
{
    switch(_rule.status) {
    case RuleSet::Rule::Status::conflicting:
        return AirspaceRule::Conflicting;
    case RuleSet::Rule::Status::not_conflicting:
        return AirspaceRule::NotConflicting;
    case RuleSet::Rule::Status::missing_info:
        return AirspaceRule::MissingInfo;
    case RuleSet::Rule::Status::unknown:
    default:
        return AirspaceRule::Unknown;
    }
}

//-----------------------------------------------------------------------------
AirMapRuleSet::AirMapRuleSet(QObject* parent)
    : AirspaceRuleSet(parent)
    , _isDefault(false)
    , _selected(false)
    , _selectionType(AirspaceRuleSet::Optional)
{
}

//-----------------------------------------------------------------------------
AirMapRuleSet::~AirMapRuleSet()
{
    _rules.deleteListAndContents();
}

//-----------------------------------------------------------------------------
void
AirMapRuleSet::setSelected(bool sel)
{
    if(_selectionType != AirspaceRuleSet::Required) {
        _selected = sel;
    } else {
        _selected = true;
    }
    emit selectedChanged();
}

//-----------------------------------------------------------------------------
AirMapRulesetsManager::AirMapRulesetsManager(AirMapSharedState& shared)
    : _shared(shared)
{
}

//-----------------------------------------------------------------------------
static bool
rules_sort(QObject* a, QObject* b)
{
    AirMapRule* aa = qobject_cast<AirMapRule*>(a);
    AirMapRule* bb = qobject_cast<AirMapRule*>(b);
    if(!aa || !bb) return false;
    return (int)aa->order() > (int)bb->order();
}

//-----------------------------------------------------------------------------
void AirMapRulesetsManager::setROI(const QGCGeoBoundingCube& roi)
{
    if (!_shared.client()) {
        qCDebug(AirMapManagerLog) << "No AirMap client instance. Not updating Airspace";
        return;
    }
    if (_state != State::Idle) {
        qCWarning(AirMapManagerLog) << "AirMapRulesetsManager::updateROI: state not idle";
        return;
    }
    qCDebug(AirMapManagerLog) << "Rulesets Request (ROI Changed)";
    _valid = false;
    _ruleSets.clearAndDeleteContents();
    _state = State::RetrieveItems;
    RuleSets::Search::Parameters params;
    //-- Geometry: Polygon
    Geometry::Polygon polygon;
    for (const auto& qcoord : roi.polygon2D()) {
        Geometry::Coordinate coord;
        coord.latitude  = qcoord.latitude();
        coord.longitude = qcoord.longitude();
        polygon.outer_ring.coordinates.push_back(coord);
    }
    params.geometry = Geometry(polygon);
    std::weak_ptr<LifetimeChecker> isAlive(_instance);
    _shared.client()->rulesets().search(params,
            [this, isAlive](const RuleSets::Search::Result& result) {
        if (!isAlive.lock()) return;
        if (_state != State::RetrieveItems) return;
        if (result) {
            const std::vector<RuleSet> rulesets = result.value();
            qCDebug(AirMapManagerLog) << "Successful rulesets search. Items:" << rulesets.size();
            for (const auto& ruleset : rulesets) {
                AirMapRuleSet* pRuleSet = new AirMapRuleSet(this);
                connect(pRuleSet, &AirspaceRuleSet::selectedChanged, this, &AirMapRulesetsManager::_selectedChanged);
                pRuleSet->_id          = QString::fromStdString(ruleset.id);
                pRuleSet->_name        = QString::fromStdString(ruleset.name);
                pRuleSet->_shortName   = QString::fromStdString(ruleset.short_name);
                pRuleSet->_description = QString::fromStdString(ruleset.description);
                pRuleSet->_isDefault   = ruleset.is_default;
                //-- TODO: This should be persistent and if the new incoming set has the
                //   same, previosuly selected rulesets, it should "remember".
                if(pRuleSet->_isDefault) {
                    pRuleSet->_selected = true;
                }
                switch(ruleset.selection_type) {
                case RuleSet::SelectionType::pickone:
                    pRuleSet->_selectionType = AirspaceRuleSet::Pickone;
                    break;
                case RuleSet::SelectionType::required:
                    pRuleSet->_selectionType = AirspaceRuleSet::Required;
                    pRuleSet->_selected = true;
                    break;
                default:
                case RuleSet::SelectionType::optional:
                    pRuleSet->_selectionType = AirspaceRuleSet::Optional;
                    break;
                }
                //-- Iterate Rules
                for (const auto& rule : ruleset.rules) {
                    AirMapRule* pRule = new AirMapRule(rule, this);
                    //-- Iterate Rule Features
                    for (const auto& feature : rule.features) {
                        AirMapRuleFeature* pFeature = new AirMapRuleFeature(feature, this);
                        pRule->_features.append(pFeature);
                    }
                    pRuleSet->_rules.append(pRule);
                }
                //-- Sort rules by display order
                std::sort(pRuleSet->_rules.objectList()->begin(), pRuleSet->_rules.objectList()->end(), rules_sort);
                _ruleSets.append(pRuleSet);
                qCDebug(AirMapManagerLog) << "Adding ruleset" << pRuleSet->name();
                /*
                qDebug() << "------------------------------------------";
                qDebug() << "Jurisdiction:" << ruleset.jurisdiction.name.data() << (int)ruleset.jurisdiction.region;
                qDebug() << "Name:        " << ruleset.name.data();
                qDebug() << "Short Name:  " << ruleset.short_name.data();
                qDebug() << "Description: " << ruleset.description.data();
                qDebug() << "Is default:  " << ruleset.is_default;
                qDebug() << "Applicable to these airspace types:";
                for (const auto& airspaceType : ruleset.airspace_types) {
                    qDebug() << "  " << airspaceType.data();
                }
                qDebug() << "Rules:";
                for (const auto& rule : ruleset.rules) {
                    qDebug() << "    --------------------------------------";
                    qDebug() << "    short_text:   " << rule.short_text.data();
                    qDebug() << "    description:  " << rule.description.data();
                    qDebug() << "    display_order:" << rule.display_order;
                    qDebug() << "    status:       " << (int)rule.status;
                    qDebug() << "            ------------------------------";
                    qDebug() << "            Features:";
                    for (const auto& feature : rule.features) {
                        qDebug() << "            name:       " << feature.name.data();
                        qDebug() << "            description:" << feature.description.data();
                        qDebug() << "            status:     " << (int)feature.status;
                        qDebug() << "            type:       " << (int)feature.type;
                        qDebug() << "            measurement:" << (int)feature.measurement;
                        qDebug() << "            unit:       " << (int)feature.unit;
                    }
                }
                */
            }
            _valid = true;
        } else {
            QString description = QString::fromStdString(result.error().description() ? result.error().description().get() : "");
            emit error("Failed to retrieve RuleSets", QString::fromStdString(result.error().message()), description);
        }
        _state = State::Idle;
        emit ruleSetsChanged();
        emit selectedRuleSetsChanged();
    });
}

//-----------------------------------------------------------------------------
QString
AirMapRulesetsManager::selectedRuleSets()
{
    QString selection;
    for(int i = 0; i < _ruleSets.count(); i++) {
        AirMapRuleSet* rule = qobject_cast<AirMapRuleSet*>(_ruleSets.get(i));
        if(rule && rule->selected()) {
            selection += rule->shortName() + ", ";
        }
    }
    int idx = selection.lastIndexOf(", ");
    if(idx >= 0) {
        selection = selection.left(idx);
    }
    return selection;
}

//-----------------------------------------------------------------------------
void
AirMapRulesetsManager::_selectedChanged()
{
    emit selectedRuleSetsChanged();
    //-- TODO: Do whatever it is you do to select a rule
}
<|endoftext|>


<commit_before>#include <string.h>

#if defined(__SSE2__)
#include <emmintrin.h>
#endif
#if defined(__SSE4_1__)
#include <smmintrin.h>
#endif

#include "m_half.h"
#include "m_const.h"

namespace m {

static struct halfData {
    halfData();
    // 1536 bytes
    uint32_t baseTable[512];
    uint8_t shiftTable[512];
} gHalf;

halfData::halfData() {
    for (int i = 0, e = 0; i < 256; ++i) {
        e = i - 127;
        if (e < -24) {
            // When magnitude of the number is really small (2^-24 or smaller),
            // there is no possible half-float representation for the number, so
            // it must be mapped to zero (or negative zero). Setting the shift
            // table entries to 24 will shift all mantissa bits, leaving just zero.
            // Base tables store zero otherwise (0x8000 for negative zero case.)
            baseTable[i|0x000] = 0x0000;
            baseTable[i|0x100] = 0x8000;
            shiftTable[i|0x000] = 24;
            shiftTable[i|0x100] = 24;
        } else if (e < -14) {
            // When the number is small (< 2^-14), the value can only be
            // represented using a subnormal half-float. This is the most
            // complex case: first, the leading 1-bit, implicitly represented
            // in the normalized representation, must be explicitly added, then
            // the resulting mantissa must be shifted rightward, or over a number
            // of bit-positions as determined by the exponent. Here we prefer to
            // shift the original mantissa bits, and add the pre-shifted 1-bit to
            // it.
            //
            // Note: Shifting by -e-14 will never be negative, thus ensuring
            // proper conversion, an alternative method is to shift by 18-e, which
            // depends on implementation-defined behavior of unsigned shift.
            baseTable[i|0x000] = (0x0400 >> (-e-14));
            baseTable[i|0x100] = (0x0400 >> (-e-14)) | 0x8000;
            shiftTable[i|0x000] = -e-1;
            shiftTable[i|0x100] = -e-1;
        } else if (e <= 15) {
            // Normal numbers (smaller than 2^15), can be represented using half
            // floats, albeit with slightly less precision. The entries in the
            // base table are simply set to the bias-adjust exponent value, shifted
            // into the right position. A sign bit is added for the negative case.
            baseTable[i|0x000] = ((e+15) << 10);
            baseTable[i|0x100] = ((e+15) << 10) | 0x8000;
            shiftTable[i|0x000] = 13;
            shiftTable[i|0x100] = 13;
        } else if (e < 128) {
            // Large values (numbers less than 2^128) must be mapped to half-float
            // Infinity, They are too large to be represented as half-floats. In
            // this case the base table is set to 0x7C00 (with sign if negative)
            // and the mantissa is zeroed out, which is accomplished by shifting
            // out all mantissa bits.
            baseTable[i|0x000] = 0x7C00;
            baseTable[i|0x100] = 0xFC00;
            shiftTable[i|0x000] = 24;
            shiftTable[i|0x100] = 24;
        } else {
            // Remaining float numbers such as Infs and NaNs should stay Infs and
            // NaNs after conversion. The base table entries are exactly the same
            // as the previous case, except the mantissa-bits are to be preserved
            // as much as possible.
            baseTable[i|0x000] = 0x7C00;
            baseTable[i|0x100] = 0xFC00;
            shiftTable[i|0x000] = 13;
            shiftTable[i|0x100] = 13;
        }
    }
}

half convertToHalf(float in) {
    const floatShape shape = { in };
    return gHalf.baseTable[(shape.asInt >> 23) & 0x1FF] +
        ((shape.asInt & 0x007FFFFF) >> gHalf.shiftTable[(shape.asInt >> 23) & 0x1FF]);
}

float convertToFloat(half in) {
    static constexpr uint32_t kMagic = 113 << 23;
    static constexpr uint32_t kShiftedExp = 0x7C00 << 13; // exponent mask after shift
    static constexpr floatShape kMagicShape = { kMagic };

    floatShape out = { uint32_t(in & 0x7FFF) << 13 }; // exponent/mantissa bits
    const size_t exp = kShiftedExp & out.asInt; // exponent
    out.asInt += (127 - 15) << 23; // adjust exponent

    if (exp == kShiftedExp) {
        // extra adjustment of exponent for Inf/Nan?
        out.asInt += (128 - 16) << 23;
    } else if (exp == 0) {
        // extra adjustment of exponent for Zero/Denormal?
        out.asInt += 1 << 23;
        // renormalize
        out.asFloat -= kMagicShape.asFloat;
    }

    // sign bit
    out.asInt |= (in & 0x8000) << 16;
    return out.asFloat;
}

#if defined(__SSE2__)
union vectorShape {
    __m128i asVector;
    alignas(16) uint32_t asInt[4];
};

template <unsigned int I>
static inline uint32_t extractScalar(__m128i v) {
#if defined(__SSE4_1__)
    return _mm_extract_epi32(v, I);
#else
    // Not pretty
    vectorShape shape;
    shape.asVector = v;
    return shape.asInt[I];
#endif
}

static __m128i convertToHalfSSE2(__m128 f) {
    // ~15 SSE2 ops
    alignas(16) static const uint32_t kMaskAbsolute[4] = { 0x7fffffffu, 0x7fffffffu, 0x7fffffffu, 0x7fffffffu };
    alignas(16) static const uint32_t kInf32[4] = { 255 << 23, 255 << 23, 255 << 23, 255 << 23 };
    alignas(16) static const uint32_t kExpInf[4] = { (255 ^ 31) << 23, (255 ^ 31) << 23, (255 ^ 31) << 23, (255 ^ 31) << 23 };
    alignas(16) static const uint32_t kMax[4] = { (127 + 16) << 23, (127 + 16) << 23, (127 + 16) << 23, (127 + 16) << 23 };
    alignas(16) static const uint32_t kMagic[4] = { 15 << 23, 15 << 23, 15 << 23, 15 << 23 };

    const __m128  maskAbsolute = *(const __m128 *const)&kMaskAbsolute;
    const __m128  absolute     = _mm_and_ps(maskAbsolute, f);
    const __m128  justSign     = _mm_xor_ps(f, absolute);
    const __m128  max          = *(const __m128 *const)&kMax;
    const __m128  expInf       = *(const __m128 *const)&kExpInf;
    const __m128  infNanCase   = _mm_xor_ps(expInf, absolute);
    const __m128  clamped      = _mm_min_ps(max, absolute);
    const __m128  notNormal    = _mm_cmpnlt_ps(absolute, *(const __m128 *const)&kInf32);
    const __m128  scaled       = _mm_mul_ps(clamped, *(const __m128 *const)&kMagic);
    const __m128  merge1       = _mm_and_ps(infNanCase, notNormal);
    const __m128  merge2       = _mm_andnot_ps(notNormal, scaled);
    const __m128  merged       = _mm_or_ps(merge1, merge2);
    const __m128i shifted      = _mm_srli_epi32(_mm_castps_si128(merged), 13);
    const __m128i signShifted  = _mm_srli_epi32(_mm_castps_si128(justSign), 16);
    const __m128i value        = _mm_or_si128(shifted, signShifted);

    return value;
}

static __m128 convertToFloatSSE2(__m128i h) {
    // ~19 SSE2 ops
    alignas(16) static const uint32_t kMaskNoSign[4] = { 0x7fff, 0x7fff, 0x7fff, 0x7fff };
    alignas(16) static const uint32_t kSmallestNormal[4] = { 0x0400, 0x0400, 0x0400, 0x0400 };
    alignas(16) static const uint32_t kInfinity[4] = { 0x7c00, 0x7c00, 0x7c00, 0x7c00 };
    alignas(16) static const uint32_t kExpAdjustNormal[4] = { (127 - 15) << 23, (127 - 15) << 23, (127 - 15) << 23, (127 - 15) << 23, };
    alignas(16) static const uint32_t kMagicDenormal[4] = { 113 << 23, 113 << 23, 113 << 23, 113 << 23 };

    const __m128i noSign         = *(const __m128i *const)&kMaskNoSign;
    const __m128i exponentAdjust = *(const __m128i *const)&kExpAdjustNormal;
    const __m128i smallest       = *(const __m128i *const)&kSmallestNormal;
    const __m128i infinity       = *(const __m128i *const)&kInfinity;
    const __m128i expAnd         = _mm_and_si128(noSign, h);
    const __m128i justSign       = _mm_xor_si128(h, expAnd);
    const __m128i notInfNan      = _mm_cmpgt_epi32(infinity, expAnd);
    const __m128i isDenormal     = _mm_cmpgt_epi32(smallest, expAnd);
    const __m128i shifted        = _mm_slli_epi32(expAnd, 13);
    const __m128i adjustInfNan   = _mm_andnot_si128(notInfNan, exponentAdjust);
    const __m128i adjusted       = _mm_add_epi32(exponentAdjust, shifted);
    const __m128i denormal1      = _mm_add_epi32(shifted, *(const __m128i *const)&kMagicDenormal);
    const __m128i adjusted2      = _mm_add_epi32(adjusted, adjustInfNan);
    const __m128  denormal2      = _mm_sub_ps(_mm_castsi128_ps(denormal1), *(const __m128 *const)&kMagicDenormal);
    const __m128  adjusted3      = _mm_and_ps(denormal2, _mm_castsi128_ps(isDenormal));
    const __m128  adjusted4      = _mm_andnot_ps(_mm_castsi128_ps(isDenormal), _mm_castsi128_ps(adjusted2));
    const __m128  adjusted5      = _mm_or_ps(adjusted3, adjusted4);
    const __m128i sign           = _mm_slli_epi32(justSign, 16);
    const __m128  value          = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));

    return value;
}
#endif

u::vector<half> convertToHalf(const float *const input, size_t length) {
    u::vector<half> result(length);

    const float *in = input;
    U_ASSERT(((uintptr_t)(const void *)in) % 16 == 0);
    U_ASSUME_ALIGNED(in, 16);

#if defined(__SSE2__)
    const int blocks = int(length) / 4;
    const int remainder = int(length) % 4;
    int where = 0;
    for (int i = 0; i < blocks; i++) {
        const __m128 value = _mm_load_ps(&in[where]);
        const __m128i convert = convertToHalfSSE2(value);
        result[where++] = extractScalar<0>(convert);
        result[where++] = extractScalar<1>(convert);
        result[where++] = extractScalar<2>(convert);
        result[where++] = extractScalar<3>(convert);
    }
    for (int i = 0; i < remainder; i++)
        result[where+i] = convertToHalf(in[where+i]);
#else
    for (size_t i = 0; i < length; i++)
        result[i] = convertToHalf(in[i]);
#endif
    return result;
}

u::vector<float> convertToFloat(const half *const input, size_t length) {
    u::vector<float> result(length);

#if defined(__SSE2__)
    const half *in = input;
    U_ASSUME_ALIGNED(in, 16);
    const int blocks = int(length) / 4;
    const int remainder = int(length) % 4;
    int where = 0;
    for (int i = 0; i < blocks; i++, where += 4) {
        alignas(16) const __m128i value = _mm_set_epi32(in[where+0], in[where+1], in[where+2], in[where+3]);
        const __m128 convert = convertToFloatSSE2(value);
        memcpy(&result[where], &convert, sizeof convert);
    }
    for (int i = 0; i < remainder; i++)
        result[where+i] = convertToFloat(in[where+i]);
#else
    for (size_t i = 0; i < length; i++)
        result[i] = convertToFloat(in[i]);
#endif
    return result;
}

}
<commit_msg>Compiler flushes register to memory when extracting a lane - lets not do that.<commit_after>#include <string.h>

#if defined(__SSE2__)
#include <emmintrin.h>
#endif
#if defined(__SSE4_1__)
#include <smmintrin.h>
#endif

#include "m_half.h"
#include "m_const.h"

namespace m {

static struct halfData {
    halfData();
    // 1536 bytes
    uint32_t baseTable[512];
    uint8_t shiftTable[512];
} gHalf;

halfData::halfData() {
    for (int i = 0, e = 0; i < 256; ++i) {
        e = i - 127;
        if (e < -24) {
            // When magnitude of the number is really small (2^-24 or smaller),
            // there is no possible half-float representation for the number, so
            // it must be mapped to zero (or negative zero). Setting the shift
            // table entries to 24 will shift all mantissa bits, leaving just zero.
            // Base tables store zero otherwise (0x8000 for negative zero case.)
            baseTable[i|0x000] = 0x0000;
            baseTable[i|0x100] = 0x8000;
            shiftTable[i|0x000] = 24;
            shiftTable[i|0x100] = 24;
        } else if (e < -14) {
            // When the number is small (< 2^-14), the value can only be
            // represented using a subnormal half-float. This is the most
            // complex case: first, the leading 1-bit, implicitly represented
            // in the normalized representation, must be explicitly added, then
            // the resulting mantissa must be shifted rightward, or over a number
            // of bit-positions as determined by the exponent. Here we prefer to
            // shift the original mantissa bits, and add the pre-shifted 1-bit to
            // it.
            //
            // Note: Shifting by -e-14 will never be negative, thus ensuring
            // proper conversion, an alternative method is to shift by 18-e, which
            // depends on implementation-defined behavior of unsigned shift.
            baseTable[i|0x000] = (0x0400 >> (-e-14));
            baseTable[i|0x100] = (0x0400 >> (-e-14)) | 0x8000;
            shiftTable[i|0x000] = -e-1;
            shiftTable[i|0x100] = -e-1;
        } else if (e <= 15) {
            // Normal numbers (smaller than 2^15), can be represented using half
            // floats, albeit with slightly less precision. The entries in the
            // base table are simply set to the bias-adjust exponent value, shifted
            // into the right position. A sign bit is added for the negative case.
            baseTable[i|0x000] = ((e+15) << 10);
            baseTable[i|0x100] = ((e+15) << 10) | 0x8000;
            shiftTable[i|0x000] = 13;
            shiftTable[i|0x100] = 13;
        } else if (e < 128) {
            // Large values (numbers less than 2^128) must be mapped to half-float
            // Infinity, They are too large to be represented as half-floats. In
            // this case the base table is set to 0x7C00 (with sign if negative)
            // and the mantissa is zeroed out, which is accomplished by shifting
            // out all mantissa bits.
            baseTable[i|0x000] = 0x7C00;
            baseTable[i|0x100] = 0xFC00;
            shiftTable[i|0x000] = 24;
            shiftTable[i|0x100] = 24;
        } else {
            // Remaining float numbers such as Infs and NaNs should stay Infs and
            // NaNs after conversion. The base table entries are exactly the same
            // as the previous case, except the mantissa-bits are to be preserved
            // as much as possible.
            baseTable[i|0x000] = 0x7C00;
            baseTable[i|0x100] = 0xFC00;
            shiftTable[i|0x000] = 13;
            shiftTable[i|0x100] = 13;
        }
    }
}

half convertToHalf(float in) {
    const floatShape shape = { in };
    return gHalf.baseTable[(shape.asInt >> 23) & 0x1FF] +
        ((shape.asInt & 0x007FFFFF) >> gHalf.shiftTable[(shape.asInt >> 23) & 0x1FF]);
}

float convertToFloat(half in) {
    static constexpr uint32_t kMagic = 113 << 23;
    static constexpr uint32_t kShiftedExp = 0x7C00 << 13; // exponent mask after shift
    static constexpr floatShape kMagicShape = { kMagic };

    floatShape out = { uint32_t(in & 0x7FFF) << 13 }; // exponent/mantissa bits
    const size_t exp = kShiftedExp & out.asInt; // exponent
    out.asInt += (127 - 15) << 23; // adjust exponent

    if (exp == kShiftedExp) {
        // extra adjustment of exponent for Inf/Nan?
        out.asInt += (128 - 16) << 23;
    } else if (exp == 0) {
        // extra adjustment of exponent for Zero/Denormal?
        out.asInt += 1 << 23;
        // renormalize
        out.asFloat -= kMagicShape.asFloat;
    }

    // sign bit
    out.asInt |= (in & 0x8000) << 16;
    return out.asFloat;
}

#if defined(__SSE2__)
union vectorShape {
    __m128i asVector;
    alignas(16) uint32_t asInt[4];
};

template <unsigned int I>
static inline uint32_t extractScalar(__m128i v) {
#if defined(__SSE4_1__)
    return _mm_extract_epi32(v, I);
#else
    return _mm_cvtsi128_si32(_mm_shuffle_epi32(v, _MM_SHUFFLE(I,I,I,I)));
#endif
}

static __m128i convertToHalfSSE2(__m128 f) {
    // ~15 SSE2 ops
    alignas(16) static const uint32_t kMaskAbsolute[4] = { 0x7fffffffu, 0x7fffffffu, 0x7fffffffu, 0x7fffffffu };
    alignas(16) static const uint32_t kInf32[4] = { 255 << 23, 255 << 23, 255 << 23, 255 << 23 };
    alignas(16) static const uint32_t kExpInf[4] = { (255 ^ 31) << 23, (255 ^ 31) << 23, (255 ^ 31) << 23, (255 ^ 31) << 23 };
    alignas(16) static const uint32_t kMax[4] = { (127 + 16) << 23, (127 + 16) << 23, (127 + 16) << 23, (127 + 16) << 23 };
    alignas(16) static const uint32_t kMagic[4] = { 15 << 23, 15 << 23, 15 << 23, 15 << 23 };

    const __m128  maskAbsolute = *(const __m128 *const)&kMaskAbsolute;
    const __m128  absolute     = _mm_and_ps(maskAbsolute, f);
    const __m128  justSign     = _mm_xor_ps(f, absolute);
    const __m128  max          = *(const __m128 *const)&kMax;
    const __m128  expInf       = *(const __m128 *const)&kExpInf;
    const __m128  infNanCase   = _mm_xor_ps(expInf, absolute);
    const __m128  clamped      = _mm_min_ps(max, absolute);
    const __m128  notNormal    = _mm_cmpnlt_ps(absolute, *(const __m128 *const)&kInf32);
    const __m128  scaled       = _mm_mul_ps(clamped, *(const __m128 *const)&kMagic);
    const __m128  merge1       = _mm_and_ps(infNanCase, notNormal);
    const __m128  merge2       = _mm_andnot_ps(notNormal, scaled);
    const __m128  merged       = _mm_or_ps(merge1, merge2);
    const __m128i shifted      = _mm_srli_epi32(_mm_castps_si128(merged), 13);
    const __m128i signShifted  = _mm_srli_epi32(_mm_castps_si128(justSign), 16);
    const __m128i value        = _mm_or_si128(shifted, signShifted);

    return value;
}

static __m128 convertToFloatSSE2(__m128i h) {
    // ~19 SSE2 ops
    alignas(16) static const uint32_t kMaskNoSign[4] = { 0x7fff, 0x7fff, 0x7fff, 0x7fff };
    alignas(16) static const uint32_t kSmallestNormal[4] = { 0x0400, 0x0400, 0x0400, 0x0400 };
    alignas(16) static const uint32_t kInfinity[4] = { 0x7c00, 0x7c00, 0x7c00, 0x7c00 };
    alignas(16) static const uint32_t kExpAdjustNormal[4] = { (127 - 15) << 23, (127 - 15) << 23, (127 - 15) << 23, (127 - 15) << 23, };
    alignas(16) static const uint32_t kMagicDenormal[4] = { 113 << 23, 113 << 23, 113 << 23, 113 << 23 };

    const __m128i noSign         = *(const __m128i *const)&kMaskNoSign;
    const __m128i exponentAdjust = *(const __m128i *const)&kExpAdjustNormal;
    const __m128i smallest       = *(const __m128i *const)&kSmallestNormal;
    const __m128i infinity       = *(const __m128i *const)&kInfinity;
    const __m128i expAnd         = _mm_and_si128(noSign, h);
    const __m128i justSign       = _mm_xor_si128(h, expAnd);
    const __m128i notInfNan      = _mm_cmpgt_epi32(infinity, expAnd);
    const __m128i isDenormal     = _mm_cmpgt_epi32(smallest, expAnd);
    const __m128i shifted        = _mm_slli_epi32(expAnd, 13);
    const __m128i adjustInfNan   = _mm_andnot_si128(notInfNan, exponentAdjust);
    const __m128i adjusted       = _mm_add_epi32(exponentAdjust, shifted);
    const __m128i denormal1      = _mm_add_epi32(shifted, *(const __m128i *const)&kMagicDenormal);
    const __m128i adjusted2      = _mm_add_epi32(adjusted, adjustInfNan);
    const __m128  denormal2      = _mm_sub_ps(_mm_castsi128_ps(denormal1), *(const __m128 *const)&kMagicDenormal);
    const __m128  adjusted3      = _mm_and_ps(denormal2, _mm_castsi128_ps(isDenormal));
    const __m128  adjusted4      = _mm_andnot_ps(_mm_castsi128_ps(isDenormal), _mm_castsi128_ps(adjusted2));
    const __m128  adjusted5      = _mm_or_ps(adjusted3, adjusted4);
    const __m128i sign           = _mm_slli_epi32(justSign, 16);
    const __m128  value          = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));

    return value;
}
#endif

u::vector<half> convertToHalf(const float *const input, size_t length) {
    u::vector<half> result(length);

    const float *in = input;
    U_ASSERT(((uintptr_t)(const void *)in) % 16 == 0);
    U_ASSUME_ALIGNED(in, 16);

#if defined(__SSE2__)
    const int blocks = int(length) / 4;
    const int remainder = int(length) % 4;
    int where = 0;
    for (int i = 0; i < blocks; i++) {
        const __m128 value = _mm_load_ps(&in[where]);
        const __m128i convert = convertToHalfSSE2(value);
        result[where++] = extractScalar<0>(convert);
        result[where++] = extractScalar<1>(convert);
        result[where++] = extractScalar<2>(convert);
        result[where++] = extractScalar<3>(convert);
    }
    for (int i = 0; i < remainder; i++)
        result[where+i] = convertToHalf(in[where+i]);
#else
    for (size_t i = 0; i < length; i++)
        result[i] = convertToHalf(in[i]);
#endif
    return result;
}

u::vector<float> convertToFloat(const half *const input, size_t length) {
    u::vector<float> result(length);

#if defined(__SSE2__)
    const half *in = input;
    U_ASSUME_ALIGNED(in, 16);
    const int blocks = int(length) / 4;
    const int remainder = int(length) % 4;
    int where = 0;
    for (int i = 0; i < blocks; i++, where += 4) {
        alignas(16) const __m128i value = _mm_set_epi32(in[where+0], in[where+1], in[where+2], in[where+3]);
        const __m128 convert = convertToFloatSSE2(value);
        memcpy(&result[where], &convert, sizeof convert);
    }
    for (int i = 0; i < remainder; i++)
        result[where+i] = convertToFloat(in[where+i]);
#else
    for (size_t i = 0; i < length; i++)
        result[i] = convertToFloat(in[i]);
#endif
    return result;
}

}
<|endoftext|>