<commit_before>#include <clw/clw.h>
#include <iostream>
#include <string>

std::string deviceTypeName(clw::EDeviceType type)
{
    switch(type)
    {
    case clw::Cpu: return std::string("Cpu");
    case clw::Gpu: return std::string("Gpu");
    case clw::Accelerator: return std::string("Accelerator");
    case clw::Custom: return std::string("Custom");
    default: return std::string("Undefined");
    }
}

std::string boolName(bool v)
{
    return v ? std::string("yes") : std::string("no");
}

std::string cacheTypeName(clw::ECacheType type)
{
    switch(type)
    {
    case clw::Cache_NoChache: return "No chache";
    case clw::Cache_ReadOnlyCache: return "Read-only cache";
    case clw::Cache_ReadWriteCache: return "Read-write cache";
    default: return std::string("Undefined");
    }
}

std::string floatCapabilitiesName(clw::EFloatCapabilities caps)
{
    std::string accum;
    if(caps & clw::Capability_Denorm)
        accum += "Denorm ";
    if(caps & clw::Capability_InfinityAndNaN)
        accum += "InfinityAndNaN ";
    if(caps & clw::Capability_RoundToNearest)
        accum += "RoundToNearest ";
    if(caps & clw::Capability_RoundToZero)
        accum += "RoundToZero ";
    if(caps & clw::Capability_RoundToInf)
        accum += "RoundToInf ";
    if(caps & clw::Capability_FusedMultiplyAdd)
        accum += "FusedMultiplyAdd ";
    if(caps & clw::Capability_CorrectlyRoundedDivideSqrt)
        accum += "CorrectlyRoundedDivideSqrt ";
    if(caps & clw::Capability_SoftwareFloat)
        accum += "SoftwareFloat ";

    if(accum.empty())
        accum += "Not supported";
    return accum;
}

std::string memorySizeName(uint64_t memSize)
{
#if defined(_MSC_VER)
#  define snprintf _snprintf
#endif
    char buf[64];
    if(memSize >= 1024 * 1024)
        snprintf(buf, sizeof(buf)/sizeof(char), "%d MB", int(memSize / (1024 * 1024)));
    else
        snprintf(buf, sizeof(buf)/sizeof(char), "%d kB", int(memSize / 1024));
    return std::string(buf);
}

int main()
{
    auto platforms = clw::availablePlatforms();
    for(const clw::Platform& platform : platforms)
    {
        std::cout << "OpenCL Platform:\n";
        std::cout << "    Profile          : " << platform.profile() << std::endl;
        std::cout << "    Version          : " << platform.versionString() << std::endl;
        std::cout << "    Name             : " << platform.name() << std::endl;
        std::cout << "    Vendor           : " << platform.vendor() << std::endl;
        std::cout << "    Extension suffix : " << platform.extensionSuffix() << std::endl;

        auto exts = platform.extensions();
        std::cout << "    Extensions       : (" << exts.size() << ")\n";
        for(const std::string& extension : exts)
            std::cout << "        " << extension << std::endl;
        std::cout << "\n";

        auto devices = clw::devices(clw::All, platform);
        for(const clw::Device& device : devices)
        {
            std::cout << "OpenCL Device:                    (available: " << boolName(device.isAvailable()) << ")\n";
            std::cout << "    Name                        : " << device.name() << std::endl;
            std::cout << "    Version                     : " << device.version() << std::endl;
            std::cout << "    Vendor                      : " << device.vendor() << std::endl;
            std::cout << "    Device type                 : " << deviceTypeName(device.deviceType()) << std::endl;
            std::cout << "    Driver version              : " << device.driverVersion() << std::endl;
            std::cout << "    Language version            : " << device.languageVersion() << std::endl;
            std::cout << "    Is compiler available       : " << boolName(device.isCompilerAvailable()) << std::endl;
            std::cout << "    Supports double             : " << boolName(device.supportsDouble()) << std::endl;
            std::cout << "    Supports half float         : " << boolName(device.supportsHalf()) << std::endl;
            std::cout << "    Supports error correction   : " << boolName(device.supportsErrorCorrection()) << std::endl;
            std::cout << "    Supports native kernel      : " << boolName(device.supportsNativeKernel()) << std::endl;
            std::cout << "    Supports out of order exec. : " << boolName(device.supportsOutOfOrderExecution()) << std::endl;
            std::cout << "    Supports images             : " << boolName(device.supportsImages()) << std::endl;
            std::cout << "    Is unified memory           : " << boolName(device.isUnifiedMemory()) << std::endl;
            std::cout << "    Separate local memory       : " << boolName(device.isLocalMemorySeparate()) << std::endl;
            std::cout << "    Address bitness             : " << device.addressBitness() << std::endl;
            std::cout << "    Endianess                   : " << (device.isLittleEndian() ? "little" : "big") << std::endl;
            std::cout << "    Clock frequency             : " << device.clockFrequency() << " MHz" << std::endl;
            std::cout << "    Compute units               : " << device.computeUnits() << std::endl;
            std::cout << "    Default alignment           : " << device.defaultAlignment() << " bits" << std::endl;
            std::cout << "    Minimum alignment           : " << device.minimumAlignment() << " bytes" << std::endl;
			std::cout << "    Float capabilities          : " << floatCapabilitiesName(device.floatCapabilities()) << std::endl;
            std::cout << "    Double capabilities         : " << floatCapabilitiesName(device.doubleCapabilities()) << std::endl;
            std::cout << "    Half capabilities           : " << floatCapabilitiesName(device.halfCapabilities()) << std::endl;
            std::cout << "    GMEM cache size             : " << memorySizeName(device.globalMemoryCacheSize()) << std::endl;
            std::cout << "    GMEM cache line size        : " << device.globalMemoryCacheLineSize() << " bytes" << std::endl;
            std::cout << "    GMEM cache type             : " << cacheTypeName(device.globalMemoryCacheType()) << std::endl;
            std::cout << "    GMEM size                   : " << memorySizeName(device.globalMemorySize()) << std::endl;
            std::cout << "    LMEM size                   : " << memorySizeName(device.localMemorySize()) << std::endl;
            std::cout << "    Max. single allocation size : " << memorySizeName(device.maximumAllocationSize()) << std::endl;
            std::cout << "    Max. image 2D size          : " << device.maximumImage2DSize() << std::endl;
            std::cout << "    Max. image 3D size          : " << device.maximumImage3DSize() << std::endl;
            std::cout << "    Max. images (read)          : " << device.maximumReadImages() << std::endl;
            std::cout << "    Max. images (write)         : " << device.maximumWriteImages() << std::endl;
            std::cout << "    Max. samplers               : " << device.maximumSamplers() << std::endl;
            std::cout << "    Max. const arguments        : " << device.maximumConstantArguments() << std::endl;
            std::cout << "    Max. constant buffer size   : " << memorySizeName(device.maximumConstantBufferSize()) << std::endl;
            std::cout << "    Max. parameter size         : " << device.maximumParameterBytes() << " bytes" << std::endl;
            std::cout << "    Max. work items             : " << device.maximumWorkItemSize() << std::endl;
            std::cout << "    Max. work items per group   : " << device.maximumWorkItemsPerGroup() << std::endl;
            std::cout << "    Timer resolution            : " << device.profilingTimerResolution() << " nsec" << std::endl;
            std::cout << "    Native vectors width        : char" << device.nativeCharVectorWidth()
                      << " short" << device.nativeShortVectorWidth()
                      << " int" << device.nativeIntVectorWidth()
                      << " long" << device.nativeLongVectorWidth()
                      << " float" << device.nativeFloatVectorWidth()
                      << " double" << device.nativeDoubleVectorWidth()
                      << " half" << device.nativeHalfVectorWidth()
                      << std::endl;
            std::cout << "    Preferred vectors width     : char" << device.preferredCharVectorWidth()
                      << " short" << device.preferredShortVectorWidth()
                      << " int" << device.preferredIntVectorWidth()
                      << " long" << device.preferredLongVectorWidth()
                      << " float" << device.preferredFloatVectorWidth()
                      << " double" << device.preferredDoubleVectorWidth()
                      << " half" << device.preferredHalfVectorWidth()
                      << std::endl;

            // Radeons specific device attributes
            if(device.vendor() == std::string("Advanced Micro Devices, Inc.") &&
               device.deviceType() == clw::Gpu)
            {
                auto gmemFree = device.globalFreeMemory();
                std::cout << "    AMD specific                : " << std::endl;
                std::cout << "      Board name                : " << device.boardName() << std::endl;
                if(gmemFree.size() == 2)
                    std::cout << "      Free GMEM                 : " << memorySizeName(gmemFree[1] * 1024)
                              << "/" << memorySizeName(gmemFree[0] * 1024) << std::endl;
                std::cout << "      SIMD per Compute Unit     : " << device.simdPerComputeUnit() << std::endl;
                std::cout << "      SIMD width                : " << device.simdWidth() << std::endl;
                std::cout << "      SIMD Instruction width    : " << device.simdInstructionWidth() << std::endl;
                std::cout << "      Wavefront width           : " << device.wavefrontWidth() << std::endl;
                std::cout << "      GMEM channels             : " << device.globalMemoryChannels() << std::endl;
                std::cout << "      GMEM channel banks        : " << device.globalMemoryChannelBanks() << std::endl;
                std::cout << "      GMEM channel bank width   : " << device.globalMemoryChannelBankWidth() << std::endl;
                std::cout << "      LMEM size per CU          : " << device.localMemorySizePerComputeUnit() << std::endl;
                std::cout << "      LMEM memory banks         : " << device.localMemoryBanks() << std::endl;
            }
            else if(device.vendor() == std::string("NVIDIA") &&
                    device.deviceType() == clw::Gpu)
            {
                std::cout << "    NVIDIA specific             : " << std::endl;
                std::cout << "      Compute Capability        : " << device.computeCapabilityMajor() << "." << device.computeCapabilityMinor() << std::endl;
                std::cout << "      Registers per Block       : " << device.registersPerBlock() << std::endl;
                std::cout << "      Warp size                 : " << device.warpSize() << std::endl;
                std::cout << "      GPU overlap               : " << device.gpuOverlap() << std::endl;
                std::cout << "      Kernel execution timeout  : " << device.kernelExecutionTimeout() << std::endl;
                std::cout << "      Integrated memory         : " << device.integratedMemory() << std::endl;
            }

            auto exts = device.extensions();
            std::cout << "    Extensions                  : (" << exts.size() << ")\n";
            for(const std::string& extension : exts)
                std::cout << "        " << extension << std::endl;
            std::cout << "\n";
        }
        std::cout << "\n";
    }

    return 0;
}<commit_msg>fixed tabs<commit_after>#include <clw/clw.h>
#include <iostream>
#include <string>

std::string deviceTypeName(clw::EDeviceType type)
{
    switch(type)
    {
    case clw::Cpu: return std::string("Cpu");
    case clw::Gpu: return std::string("Gpu");
    case clw::Accelerator: return std::string("Accelerator");
    case clw::Custom: return std::string("Custom");
    default: return std::string("Undefined");
    }
}

std::string boolName(bool v)
{
    return v ? std::string("yes") : std::string("no");
}

std::string cacheTypeName(clw::ECacheType type)
{
    switch(type)
    {
    case clw::Cache_NoChache: return "No chache";
    case clw::Cache_ReadOnlyCache: return "Read-only cache";
    case clw::Cache_ReadWriteCache: return "Read-write cache";
    default: return std::string("Undefined");
    }
}

std::string floatCapabilitiesName(clw::EFloatCapabilities caps)
{
    std::string accum;
    if(caps & clw::Capability_Denorm)
        accum += "Denorm ";
    if(caps & clw::Capability_InfinityAndNaN)
        accum += "InfinityAndNaN ";
    if(caps & clw::Capability_RoundToNearest)
        accum += "RoundToNearest ";
    if(caps & clw::Capability_RoundToZero)
        accum += "RoundToZero ";
    if(caps & clw::Capability_RoundToInf)
        accum += "RoundToInf ";
    if(caps & clw::Capability_FusedMultiplyAdd)
        accum += "FusedMultiplyAdd ";
    if(caps & clw::Capability_CorrectlyRoundedDivideSqrt)
        accum += "CorrectlyRoundedDivideSqrt ";
    if(caps & clw::Capability_SoftwareFloat)
        accum += "SoftwareFloat ";

    if(accum.empty())
        accum += "Not supported";
    return accum;
}

std::string memorySizeName(uint64_t memSize)
{
#if defined(_MSC_VER)
#  define snprintf _snprintf
#endif
    char buf[64];
    if(memSize >= 1024 * 1024)
        snprintf(buf, sizeof(buf)/sizeof(char), "%d MB", int(memSize / (1024 * 1024)));
    else
        snprintf(buf, sizeof(buf)/sizeof(char), "%d kB", int(memSize / 1024));
    return std::string(buf);
}

int main()
{
    auto platforms = clw::availablePlatforms();
    for(const clw::Platform& platform : platforms)
    {
        std::cout << "OpenCL Platform:\n";
        std::cout << "    Profile          : " << platform.profile() << std::endl;
        std::cout << "    Version          : " << platform.versionString() << std::endl;
        std::cout << "    Name             : " << platform.name() << std::endl;
        std::cout << "    Vendor           : " << platform.vendor() << std::endl;
        std::cout << "    Extension suffix : " << platform.extensionSuffix() << std::endl;

        auto exts = platform.extensions();
        std::cout << "    Extensions       : (" << exts.size() << ")\n";
        for(const std::string& extension : exts)
            std::cout << "        " << extension << std::endl;
        std::cout << "\n";

        auto devices = clw::devices(clw::All, platform);
        for(const clw::Device& device : devices)
        {
            std::cout << "OpenCL Device:                    (available: " << boolName(device.isAvailable()) << ")\n";
            std::cout << "    Name                        : " << device.name() << std::endl;
            std::cout << "    Version                     : " << device.version() << std::endl;
            std::cout << "    Vendor                      : " << device.vendor() << std::endl;
            std::cout << "    Device type                 : " << deviceTypeName(device.deviceType()) << std::endl;
            std::cout << "    Driver version              : " << device.driverVersion() << std::endl;
            std::cout << "    Language version            : " << device.languageVersion() << std::endl;
            std::cout << "    Is compiler available       : " << boolName(device.isCompilerAvailable()) << std::endl;
            std::cout << "    Supports double             : " << boolName(device.supportsDouble()) << std::endl;
            std::cout << "    Supports half float         : " << boolName(device.supportsHalf()) << std::endl;
            std::cout << "    Supports error correction   : " << boolName(device.supportsErrorCorrection()) << std::endl;
            std::cout << "    Supports native kernel      : " << boolName(device.supportsNativeKernel()) << std::endl;
            std::cout << "    Supports out of order exec. : " << boolName(device.supportsOutOfOrderExecution()) << std::endl;
            std::cout << "    Supports images             : " << boolName(device.supportsImages()) << std::endl;
            std::cout << "    Is unified memory           : " << boolName(device.isUnifiedMemory()) << std::endl;
            std::cout << "    Separate local memory       : " << boolName(device.isLocalMemorySeparate()) << std::endl;
            std::cout << "    Address bitness             : " << device.addressBitness() << std::endl;
            std::cout << "    Endianess                   : " << (device.isLittleEndian() ? "little" : "big") << std::endl;
            std::cout << "    Clock frequency             : " << device.clockFrequency() << " MHz" << std::endl;
            std::cout << "    Compute units               : " << device.computeUnits() << std::endl;
            std::cout << "    Default alignment           : " << device.defaultAlignment() << " bits" << std::endl;
            std::cout << "    Minimum alignment           : " << device.minimumAlignment() << " bytes" << std::endl;
            std::cout << "    Float capabilities          : " << floatCapabilitiesName(device.floatCapabilities()) << std::endl;
            std::cout << "    Double capabilities         : " << floatCapabilitiesName(device.doubleCapabilities()) << std::endl;
            std::cout << "    Half capabilities           : " << floatCapabilitiesName(device.halfCapabilities()) << std::endl;
            std::cout << "    GMEM cache size             : " << memorySizeName(device.globalMemoryCacheSize()) << std::endl;
            std::cout << "    GMEM cache line size        : " << device.globalMemoryCacheLineSize() << " bytes" << std::endl;
            std::cout << "    GMEM cache type             : " << cacheTypeName(device.globalMemoryCacheType()) << std::endl;
            std::cout << "    GMEM size                   : " << memorySizeName(device.globalMemorySize()) << std::endl;
            std::cout << "    LMEM size                   : " << memorySizeName(device.localMemorySize()) << std::endl;
            std::cout << "    Max. single allocation size : " << memorySizeName(device.maximumAllocationSize()) << std::endl;
            std::cout << "    Max. image 2D size          : " << device.maximumImage2DSize() << std::endl;
            std::cout << "    Max. image 3D size          : " << device.maximumImage3DSize() << std::endl;
            std::cout << "    Max. images (read)          : " << device.maximumReadImages() << std::endl;
            std::cout << "    Max. images (write)         : " << device.maximumWriteImages() << std::endl;
            std::cout << "    Max. samplers               : " << device.maximumSamplers() << std::endl;
            std::cout << "    Max. const arguments        : " << device.maximumConstantArguments() << std::endl;
            std::cout << "    Max. constant buffer size   : " << memorySizeName(device.maximumConstantBufferSize()) << std::endl;
            std::cout << "    Max. parameter size         : " << device.maximumParameterBytes() << " bytes" << std::endl;
            std::cout << "    Max. work items             : " << device.maximumWorkItemSize() << std::endl;
            std::cout << "    Max. work items per group   : " << device.maximumWorkItemsPerGroup() << std::endl;
            std::cout << "    Timer resolution            : " << device.profilingTimerResolution() << " nsec" << std::endl;
            std::cout << "    Native vectors width        : char" << device.nativeCharVectorWidth()
                      << " short" << device.nativeShortVectorWidth()
                      << " int" << device.nativeIntVectorWidth()
                      << " long" << device.nativeLongVectorWidth()
                      << " float" << device.nativeFloatVectorWidth()
                      << " double" << device.nativeDoubleVectorWidth()
                      << " half" << device.nativeHalfVectorWidth()
                      << std::endl;
            std::cout << "    Preferred vectors width     : char" << device.preferredCharVectorWidth()
                      << " short" << device.preferredShortVectorWidth()
                      << " int" << device.preferredIntVectorWidth()
                      << " long" << device.preferredLongVectorWidth()
                      << " float" << device.preferredFloatVectorWidth()
                      << " double" << device.preferredDoubleVectorWidth()
                      << " half" << device.preferredHalfVectorWidth()
                      << std::endl;

            // Radeons specific device attributes
            if(device.vendor() == std::string("Advanced Micro Devices, Inc.") &&
               device.deviceType() == clw::Gpu)
            {
                auto gmemFree = device.globalFreeMemory();
                std::cout << "    AMD specific                : " << std::endl;
                std::cout << "      Board name                : " << device.boardName() << std::endl;
                if(gmemFree.size() == 2)
                    std::cout << "      Free GMEM                 : " << memorySizeName(gmemFree[1] * 1024)
                              << "/" << memorySizeName(gmemFree[0] * 1024) << std::endl;
                std::cout << "      SIMD per Compute Unit     : " << device.simdPerComputeUnit() << std::endl;
                std::cout << "      SIMD width                : " << device.simdWidth() << std::endl;
                std::cout << "      SIMD Instruction width    : " << device.simdInstructionWidth() << std::endl;
                std::cout << "      Wavefront width           : " << device.wavefrontWidth() << std::endl;
                std::cout << "      GMEM channels             : " << device.globalMemoryChannels() << std::endl;
                std::cout << "      GMEM channel banks        : " << device.globalMemoryChannelBanks() << std::endl;
                std::cout << "      GMEM channel bank width   : " << device.globalMemoryChannelBankWidth() << std::endl;
                std::cout << "      LMEM size per CU          : " << device.localMemorySizePerComputeUnit() << std::endl;
                std::cout << "      LMEM memory banks         : " << device.localMemoryBanks() << std::endl;
            }
            else if(device.vendor() == std::string("NVIDIA") &&
                    device.deviceType() == clw::Gpu)
            {
                std::cout << "    NVIDIA specific             : " << std::endl;
                std::cout << "      Compute Capability        : " << device.computeCapabilityMajor() << "." << device.computeCapabilityMinor() << std::endl;
                std::cout << "      Registers per Block       : " << device.registersPerBlock() << std::endl;
                std::cout << "      Warp size                 : " << device.warpSize() << std::endl;
                std::cout << "      GPU overlap               : " << device.gpuOverlap() << std::endl;
                std::cout << "      Kernel execution timeout  : " << device.kernelExecutionTimeout() << std::endl;
                std::cout << "      Integrated memory         : " << device.integratedMemory() << std::endl;
            }

            auto exts = device.extensions();
            std::cout << "    Extensions                  : (" << exts.size() << ")\n";
            for(const std::string& extension : exts)
                std::cout << "        " << extension << std::endl;
            std::cout << "\n";
        }
        std::cout << "\n";
    }

    return 0;
}<|endoftext|>


<commit_before>/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://opensource.org/licenses/BSD-3-Clause for
   details.  */

#include <algorithm>
#include <cctype>
#include <fstream>
#include <functional>
#include <iostream>
#include <memory>
#include <regex>
#include <string>
#include <utility>
#include <vector>

#include "parser.h"

using namespace std::placeholders;

void replace_all_in_string(std::string &main_string, const std::string &from,
                           const std::string &to) {
	size_t pos = 0;
	while ((pos = main_string.find(from, pos)) != std::string::npos) {
		main_string.replace(pos, from.size(), to);
	}
}

std::string lowerstring(const std::string &val) {
	std::string newval = val;
	std::transform(newval.begin(), newval.end(), newval.begin(),
	               [](char c) { return std::tolower(c); });
	return newval;
}

std::string repeat_string(const std::string &val, size_t n) {
	std::string newval;
	for (size_t i = 0; i < n; i++) {
		newval += val;
	}
	return newval;
}

using FormatterFunction = std::function<void(const std::vector<Command> &, std::vector<Span> &)>;

class Formatter {
  public:
	virtual ~Formatter() = default;
	virtual std::vector<std::pair<std::string, std::string>> describeCommandLine() = 0;
	virtual bool handleCommandLine(const std::string &arg,
	                               std::vector<FormatterFunction> &formatter_functions) = 0;
};

class FormatterIndent : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {{"-indent=STRING", "Use STRING for indentation."}};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatter_functions) override {
		if (arg.find("-indent=") != 0) {
			return false;
		}

		std::string indent_string = arg.substr(std::string{"-indent="}.size());
		replace_all_in_string(indent_string, "\\t", "\t");
		formatter_functions.emplace_back(std::bind(run, _1, _2, indent_string));

		return true;
	};

	static void run(const std::vector<Command> &commands, std::vector<Span> &spans,
	                const std::string &indent_string) {
		int global_indentation_level = 0;
		for (auto c : commands) {
			const std::string ident = lowerstring(spans[c.identifier].data);

			if (ident == "endif" || ident == "endforeach" || ident == "endwhile" ||
			    ident == "endmacro" || ident == "endfunction") {
				global_indentation_level--;
			}

			auto indentation_level = global_indentation_level;
			if (ident == "else" || ident == "elseif") {
				indentation_level--;
			}

			const std::string old_indentation = spans[c.identifier - 1].data;

			// Re-indent the command invocation
			spans[c.identifier - 1].data = repeat_string(indent_string, indentation_level);

			// Walk forwards to fix arguments and the closing paren.
			size_t next_token = c.identifier + 1;
			while (true) {
				if (spans[next_token].type == SpanType::Newline) {
					size_t old_indentation_pos = spans[next_token + 1].data.find(old_indentation);
					if (old_indentation_pos != 0) {
					} else {
						spans[next_token + 1].data =
						    (repeat_string(indent_string, indentation_level) +
						     spans[next_token + 1].data.substr(old_indentation.size()));
					}
					next_token++;
				} else if (spans[next_token].type == SpanType::Lparen) {
					break;
				} else {
					next_token++;
				}
			}

			// Walk backwards to fix comments at the same prior indentation
			// level.
			size_t last_token_on_previous_line = c.identifier - 3;
			while (true) {
				if (spans[last_token_on_previous_line].type == SpanType::Comment &&
				    spans[last_token_on_previous_line - 1].type == SpanType::Space &&
				    spans[last_token_on_previous_line - 2].type == SpanType::Newline) {
					spans[last_token_on_previous_line - 1].data =
					    repeat_string(indent_string, indentation_level);
					last_token_on_previous_line -= 3;
				} else if (spans[last_token_on_previous_line].type == SpanType::Space &&
				           spans[last_token_on_previous_line - 1].type == SpanType::Newline) {
					last_token_on_previous_line -= 2;
				} else if (spans[last_token_on_previous_line].type == SpanType::Newline) {
					last_token_on_previous_line -= 1;
				} else {
					break;
				}
			}

			if (ident == "if" || ident == "foreach" || ident == "while" || ident == "macro" ||
			    ident == "function") {
				global_indentation_level++;
			}
		}
	}
};

class FormatterIndentArgument : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {
		    {"-indent-arguments=align-paren",
		     "Align arguments on continuing lines with the command's left parenthesis."},
		    {"-indent-arguments=STRING", "Use STRING for indenting arguments on continuing lines."},
		};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatter_functions) override {

		if (arg == "-indent-arguments=align-paren") {
			formatter_functions.emplace_back(std::bind(run, _1, _2, true, ""));
			return true;
		}
		if (arg.find("-indent-arguments=") == 0) {
			std::string argument_indent_string =
			    arg.substr(std::string{"-indent-arguments="}.size());
			replace_all_in_string(argument_indent_string, "\\t", "\t");
			formatter_functions.emplace_back(std::bind(run, _1, _2, false, argument_indent_string));
			return true;
		}

		return false;
	}

	static void run(const std::vector<Command> &commands, std::vector<Span> &spans,
	                bool argument_indent_after_lparen, std::string argument_indent_string) {

		(void)argument_indent_after_lparen;

		for (auto c : commands) {
			const std::string ident = lowerstring(spans[c.identifier].data);

			std::string command_indentation;
			if (spans[c.identifier - 1].type == SpanType::Newline) {
				command_indentation = "";
			} else {
				command_indentation = spans[c.identifier - 1].data;
			}

			if (argument_indent_after_lparen) {
				argument_indent_string = repeat_string(" ", ident.size() + 1);
			}

			// Walk forwards to fix argument indents.
			size_t next_token = c.identifier + 1;
			while (true) {
				if (spans[next_token].type == SpanType::Newline) {
					if (spans[next_token + 2].type != SpanType::Rparen) {
						spans[next_token + 1].data = command_indentation + argument_indent_string;
					}
					next_token++;
				} else if (spans[next_token].type == SpanType::Rparen) {
					break;
				} else {
					next_token++;
				}
			}
		}
	}
};

class FormatterIndentRparen : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {{"-indent-rparen=STRING", "Use STRING for indenting hanging right-parens."}};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatter_functions) override {
		if (arg.find("-indent-rparen=") != 0) {
			return false;
		}

		std::string rparen_indent_string = arg.substr(std::string{"-indent-rparen="}.size());
		replace_all_in_string(rparen_indent_string, "\\t", "\t");

		formatter_functions.emplace_back(std::bind(run, _1, _2, rparen_indent_string));

		return true;
	}

	static void run(const std::vector<Command> &commands, std::vector<Span> &spans,
	                const std::string &rparen_indent_string) {
		for (auto c : commands) {
			const std::string ident = lowerstring(spans[c.identifier].data);

			std::string command_indentation;
			if (spans[c.identifier - 1].type == SpanType::Newline) {
				command_indentation = "";
			} else {
				command_indentation = spans[c.identifier - 1].data;
			}

			// Walk forwards to fix continuation indents.
			size_t next_token = c.identifier + 1;
			while (true) {
				if (spans[next_token].type == SpanType::Rparen) {
					if (spans[next_token - 2].type == SpanType::Newline) {
						spans[next_token - 1].data = (command_indentation + rparen_indent_string);
					}
					break;
				} else {
					next_token++;
				}
			}
		}
	}
};

class FormatterLowercaseCommands : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {{"-lowercase-commands", "Lowercase command names in command invocations."}};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatting_functions) override {
		if (arg != "-lowercase-commands")
			return false;
		formatting_functions.emplace_back(formatLowercaseCommands);
		return true;
	}

	static void formatLowercaseCommands(const std::vector<Command> &commands,
	                                    std::vector<Span> &spans) {
		for (auto c : commands) {
			spans[c.identifier].data = lowerstring(spans[c.identifier].data);
		}
	}
};

int main(int argc, char **argv) {

	std::vector<std::unique_ptr<Formatter>> formatters;
	formatters.emplace_back(new FormatterLowercaseCommands());
	formatters.emplace_back(new FormatterIndent());
	formatters.emplace_back(new FormatterIndentArgument());
	formatters.emplace_back(new FormatterIndentRparen());

	bool format_in_place = false;
	std::vector<FormatterFunction> formatting_functions;

	std::vector<std::string> filenames;
	for (int i = 1; i < argc; i++) {
		const std::string arg{argv[i]};
		if (arg[0] == '-') {
			std::smatch reindent_match;

			if ("-help" == arg || "-h" == arg || "--help" == arg) {
				fprintf(stderr,
				        "usage: %s [options] [file ...]\n"
				        "\n"
				        "Re-formats specified files. If -i is specified, formats files\n"
				        "in-place; otherwise, writes results to standard output.\n"
				        "\n",
				        argv[0]);
				fprintf(stderr, "options:\n");

				size_t max_option_size = 0;
				for (auto const &f : formatters) {
					for (auto const p : f->describeCommandLine()) {
						max_option_size = std::max(max_option_size, p.first.size());
					}
				}
				for (auto const &f : formatters) {
					for (auto const p : f->describeCommandLine()) {
						std::string opt;
						std::string description;
						std::tie(opt, description) = p;
						fprintf(stderr, "  %s%s  %s\n", opt.c_str(),
						        repeat_string(" ", max_option_size - opt.size()).c_str(),
						        description.c_str());
					}
				}
				fprintf(stderr, "  %s%s  %s\n", "-i",
				        repeat_string(" ", max_option_size - 2).c_str(),
				        "Re-format files in-place.");
				exit(1);
			} else if (arg == "-i") {
				format_in_place = true;
			} else {
				bool handled_arg = false;
				for (const auto &f : formatters) {
					if ((handled_arg = f->handleCommandLine(arg, formatting_functions))) {
						break;
					}
				}
				if (!handled_arg) {
					fprintf(stderr, "%s: unrecognized option '%s'. Try: %s -help\n", argv[0],
					        arg.c_str(), argv[0]);
					exit(1);
				}
			}
		} else {
			filenames.emplace_back(arg);
		}
	}

	if (filenames.size() == 0) {
		fprintf(stderr, "%s: no filenames specified. Try: %s -help\n", argv[0], argv[0]);
		exit(1);
	}

	if (formatting_functions.size() == 0) {
		fprintf(stderr, "%s: no formatting options specified. Try: %s -help\n", argv[0], argv[0]);
		exit(1);
	}

	for (auto filename : filenames) {
		std::string content;
		{
			std::ifstream file{filename};
			content = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
		}

		std::vector<Span> spans;
		std::vector<Command> commands;
		std::tie(spans, commands) = parse(content);

		for (auto f : formatting_functions) {
			f(commands, spans);
		}

		if (format_in_place) {
			std::ofstream file{filename};
			for (auto s : spans) {
				file << s.data;
			}
		} else {
			for (auto s : spans) {
				std::cout << s.data;
			}
		}
	}
}
<commit_msg>cmake-format: replace size_t with ssize_t in FormatterIndent::run<commit_after>/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://opensource.org/licenses/BSD-3-Clause for
   details.  */

#include <algorithm>
#include <cctype>
#include <fstream>
#include <functional>
#include <iostream>
#include <memory>
#include <regex>
#include <string>
#include <utility>
#include <vector>

#include "parser.h"

using namespace std::placeholders;

void replace_all_in_string(std::string &main_string, const std::string &from,
                           const std::string &to) {
	size_t pos = 0;
	while ((pos = main_string.find(from, pos)) != std::string::npos) {
		main_string.replace(pos, from.size(), to);
	}
}

std::string lowerstring(const std::string &val) {
	std::string newval = val;
	std::transform(newval.begin(), newval.end(), newval.begin(),
	               [](char c) { return std::tolower(c); });
	return newval;
}

std::string repeat_string(const std::string &val, size_t n) {
	std::string newval;
	for (size_t i = 0; i < n; i++) {
		newval += val;
	}
	return newval;
}

using FormatterFunction = std::function<void(const std::vector<Command> &, std::vector<Span> &)>;

class Formatter {
  public:
	virtual ~Formatter() = default;
	virtual std::vector<std::pair<std::string, std::string>> describeCommandLine() = 0;
	virtual bool handleCommandLine(const std::string &arg,
	                               std::vector<FormatterFunction> &formatter_functions) = 0;
};

class FormatterIndent : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {{"-indent=STRING", "Use STRING for indentation."}};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatter_functions) override {
		if (arg.find("-indent=") != 0) {
			return false;
		}

		std::string indent_string = arg.substr(std::string{"-indent="}.size());
		replace_all_in_string(indent_string, "\\t", "\t");
		formatter_functions.emplace_back(std::bind(run, _1, _2, indent_string));

		return true;
	};

	static void run(const std::vector<Command> &commands, std::vector<Span> &spans,
	                const std::string &indent_string) {
		int global_indentation_level = 0;
		for (auto c : commands) {
			const std::string ident = lowerstring(spans[c.identifier].data);

			if (ident == "endif" || ident == "endforeach" || ident == "endwhile" ||
			    ident == "endmacro" || ident == "endfunction") {
				global_indentation_level--;
			}

			auto indentation_level = global_indentation_level;
			if (ident == "else" || ident == "elseif") {
				indentation_level--;
			}

			const std::string old_indentation = spans[c.identifier - 1].data;

			// Re-indent the command invocation
			spans[c.identifier - 1].data = repeat_string(indent_string, indentation_level);

			// Walk forwards to fix arguments and the closing paren.
			size_t next_token = c.identifier + 1;
			while (true) {
				if (spans[next_token].type == SpanType::Newline) {
					size_t old_indentation_pos = spans[next_token + 1].data.find(old_indentation);
					if (old_indentation_pos != 0) {
					} else {
						spans[next_token + 1].data =
						    (repeat_string(indent_string, indentation_level) +
						     spans[next_token + 1].data.substr(old_indentation.size()));
					}
					next_token++;
				} else if (spans[next_token].type == SpanType::Lparen) {
					break;
				} else {
					next_token++;
				}
			}

			// Walk backwards to fix comments at the same prior indentation
			// level.
			ssize_t last_token_on_previous_line = c.identifier - 3;
			while (last_token_on_previous_line >= 0) {
				if (spans[last_token_on_previous_line].type == SpanType::Comment &&
				    spans[last_token_on_previous_line - 1].type == SpanType::Space &&
				    spans[last_token_on_previous_line - 2].type == SpanType::Newline) {
					spans[last_token_on_previous_line - 1].data =
					    repeat_string(indent_string, indentation_level);
					last_token_on_previous_line -= 3;
				} else if (spans[last_token_on_previous_line].type == SpanType::Space &&
				           spans[last_token_on_previous_line - 1].type == SpanType::Newline) {
					last_token_on_previous_line -= 2;
				} else if (spans[last_token_on_previous_line].type == SpanType::Newline) {
					last_token_on_previous_line -= 1;
				} else {
					break;
				}
			}

			if (ident == "if" || ident == "foreach" || ident == "while" || ident == "macro" ||
			    ident == "function") {
				global_indentation_level++;
			}
		}
	}
};

class FormatterIndentArgument : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {
		    {"-indent-arguments=align-paren",
		     "Align arguments on continuing lines with the command's left parenthesis."},
		    {"-indent-arguments=STRING", "Use STRING for indenting arguments on continuing lines."},
		};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatter_functions) override {

		if (arg == "-indent-arguments=align-paren") {
			formatter_functions.emplace_back(std::bind(run, _1, _2, true, ""));
			return true;
		}
		if (arg.find("-indent-arguments=") == 0) {
			std::string argument_indent_string =
			    arg.substr(std::string{"-indent-arguments="}.size());
			replace_all_in_string(argument_indent_string, "\\t", "\t");
			formatter_functions.emplace_back(std::bind(run, _1, _2, false, argument_indent_string));
			return true;
		}

		return false;
	}

	static void run(const std::vector<Command> &commands, std::vector<Span> &spans,
	                bool argument_indent_after_lparen, std::string argument_indent_string) {

		(void)argument_indent_after_lparen;

		for (auto c : commands) {
			const std::string ident = lowerstring(spans[c.identifier].data);

			std::string command_indentation;
			if (spans[c.identifier - 1].type == SpanType::Newline) {
				command_indentation = "";
			} else {
				command_indentation = spans[c.identifier - 1].data;
			}

			if (argument_indent_after_lparen) {
				argument_indent_string = repeat_string(" ", ident.size() + 1);
			}

			// Walk forwards to fix argument indents.
			size_t next_token = c.identifier + 1;
			while (true) {
				if (spans[next_token].type == SpanType::Newline) {
					if (spans[next_token + 2].type != SpanType::Rparen) {
						spans[next_token + 1].data = command_indentation + argument_indent_string;
					}
					next_token++;
				} else if (spans[next_token].type == SpanType::Rparen) {
					break;
				} else {
					next_token++;
				}
			}
		}
	}
};

class FormatterIndentRparen : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {{"-indent-rparen=STRING", "Use STRING for indenting hanging right-parens."}};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatter_functions) override {
		if (arg.find("-indent-rparen=") != 0) {
			return false;
		}

		std::string rparen_indent_string = arg.substr(std::string{"-indent-rparen="}.size());
		replace_all_in_string(rparen_indent_string, "\\t", "\t");

		formatter_functions.emplace_back(std::bind(run, _1, _2, rparen_indent_string));

		return true;
	}

	static void run(const std::vector<Command> &commands, std::vector<Span> &spans,
	                const std::string &rparen_indent_string) {
		for (auto c : commands) {
			const std::string ident = lowerstring(spans[c.identifier].data);

			std::string command_indentation;
			if (spans[c.identifier - 1].type == SpanType::Newline) {
				command_indentation = "";
			} else {
				command_indentation = spans[c.identifier - 1].data;
			}

			// Walk forwards to fix continuation indents.
			size_t next_token = c.identifier + 1;
			while (true) {
				if (spans[next_token].type == SpanType::Rparen) {
					if (spans[next_token - 2].type == SpanType::Newline) {
						spans[next_token - 1].data = (command_indentation + rparen_indent_string);
					}
					break;
				} else {
					next_token++;
				}
			}
		}
	}
};

class FormatterLowercaseCommands : public Formatter {
	std::vector<std::pair<std::string, std::string>> describeCommandLine() override {
		return {{"-lowercase-commands", "Lowercase command names in command invocations."}};
	}

	bool handleCommandLine(const std::string &arg,
	                       std::vector<FormatterFunction> &formatting_functions) override {
		if (arg != "-lowercase-commands")
			return false;
		formatting_functions.emplace_back(formatLowercaseCommands);
		return true;
	}

	static void formatLowercaseCommands(const std::vector<Command> &commands,
	                                    std::vector<Span> &spans) {
		for (auto c : commands) {
			spans[c.identifier].data = lowerstring(spans[c.identifier].data);
		}
	}
};

int main(int argc, char **argv) {

	std::vector<std::unique_ptr<Formatter>> formatters;
	formatters.emplace_back(new FormatterLowercaseCommands());
	formatters.emplace_back(new FormatterIndent());
	formatters.emplace_back(new FormatterIndentArgument());
	formatters.emplace_back(new FormatterIndentRparen());

	bool format_in_place = false;
	std::vector<FormatterFunction> formatting_functions;

	std::vector<std::string> filenames;
	for (int i = 1; i < argc; i++) {
		const std::string arg{argv[i]};
		if (arg[0] == '-') {
			std::smatch reindent_match;

			if ("-help" == arg || "-h" == arg || "--help" == arg) {
				fprintf(stderr,
				        "usage: %s [options] [file ...]\n"
				        "\n"
				        "Re-formats specified files. If -i is specified, formats files\n"
				        "in-place; otherwise, writes results to standard output.\n"
				        "\n",
				        argv[0]);
				fprintf(stderr, "options:\n");

				size_t max_option_size = 0;
				for (auto const &f : formatters) {
					for (auto const p : f->describeCommandLine()) {
						max_option_size = std::max(max_option_size, p.first.size());
					}
				}
				for (auto const &f : formatters) {
					for (auto const p : f->describeCommandLine()) {
						std::string opt;
						std::string description;
						std::tie(opt, description) = p;
						fprintf(stderr, "  %s%s  %s\n", opt.c_str(),
						        repeat_string(" ", max_option_size - opt.size()).c_str(),
						        description.c_str());
					}
				}
				fprintf(stderr, "  %s%s  %s\n", "-i",
				        repeat_string(" ", max_option_size - 2).c_str(),
				        "Re-format files in-place.");
				exit(1);
			} else if (arg == "-i") {
				format_in_place = true;
			} else {
				bool handled_arg = false;
				for (const auto &f : formatters) {
					if ((handled_arg = f->handleCommandLine(arg, formatting_functions))) {
						break;
					}
				}
				if (!handled_arg) {
					fprintf(stderr, "%s: unrecognized option '%s'. Try: %s -help\n", argv[0],
					        arg.c_str(), argv[0]);
					exit(1);
				}
			}
		} else {
			filenames.emplace_back(arg);
		}
	}

	if (filenames.size() == 0) {
		fprintf(stderr, "%s: no filenames specified. Try: %s -help\n", argv[0], argv[0]);
		exit(1);
	}

	if (formatting_functions.size() == 0) {
		fprintf(stderr, "%s: no formatting options specified. Try: %s -help\n", argv[0], argv[0]);
		exit(1);
	}

	for (auto filename : filenames) {
		std::string content;
		{
			std::ifstream file{filename};
			content = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
		}

		std::vector<Span> spans;
		std::vector<Command> commands;
		std::tie(spans, commands) = parse(content);

		for (auto f : formatting_functions) {
			f(commands, spans);
		}

		if (format_in_place) {
			std::ofstream file{filename};
			for (auto s : spans) {
				file << s.data;
			}
		} else {
			for (auto s : spans) {
				std::cout << s.data;
			}
		}
	}
}
<|endoftext|>


<commit_before>#include "Test.h"

void Test::conIntList() {
    bool compStatus = compileChecker("con/conIntList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1, 2, 3, 4]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conFloatList() {
    bool compStatus = compileChecker("con/conFloatList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1.000000, 2.000000, 3.000000, 4.000000]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conBoolList() {
    bool compStatus = compileChecker("con/conBoolList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[True, True, False, False]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conCharList() {
    bool compStatus = compileChecker("con/conCharList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("['c', 'h', 'a', 'r']");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conStringList() {
    bool compStatus = compileChecker("con/conStringList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[\"string\", \"string\", \"string\", \"string\"]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conNestedList() {
    bool compStatus = compileChecker("con/conNestedList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[[1, 2], [3, 4], [5, 6], [7, 8]]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conTupleList() {
    bool compStatus = compileChecker("con/conTupleList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[(1, True), (2, False), (3, True), (4, False)]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conTuple() {
    bool compStatus = compileChecker("con/conTuple.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conInt() {
    bool compStatus = compileChecker("con/conInt.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);

}

void Test::conFloat() {
    bool compStatus = compileChecker("con/conFloat.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conBool() {
    bool compStatus = compileChecker("con/conBool.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conChar() {
    bool compStatus = compileChecker("con/conChar.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conString() {
    bool compStatus = compileChecker("con/conString.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("\"concatstring\"");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conMix() {
    bool compStatus = compileChecker("con/conMix.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conFuncResOne() {
    bool compStatus = compileChecker("con/conFunResOne.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1, 2, 3, 4]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conFuncResTwo() {
    bool compStatus = compileChecker("con/conFunResTwo.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1, 2, 3, 4]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conEmpty() {
    bool compStatus = compileChecker("con/conEmpty.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}<commit_msg>unittests: fixed concat tests<commit_after>#include "Test.h"

void Test::conIntList() {
    bool compStatus = compileChecker("con/conIntList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1, 2, 3, 4]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conFloatList() {
    bool compStatus = compileChecker("con/conFloatList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1.000000, 2.000000, 3.000000, 4.000000]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conBoolList() {
    bool compStatus = compileChecker("con/conBoolList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[True, True, False, False]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conCharList() {
    bool compStatus = compileChecker("con/conCharList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("['c', 'h', 'a', 'r']");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conStringList() {
    bool compStatus = compileChecker("con/conStringList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[\"string\", \"string\", \"string\", \"string\"]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conNestedList() {
    bool compStatus = compileChecker("con/conNestedList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[[1, 2], [3, 4], [5, 6], [7, 8]]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conTupleList() {
    bool compStatus = compileChecker("con/conTupleList.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[(1, True), (2, False), (3, True), (4, False)]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conTuple() {
    bool compStatus = compileChecker("con/conTuple.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conInt() {
    bool compStatus = compileChecker("con/conInt.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);

}

void Test::conFloat() {
    bool compStatus = compileChecker("con/conFloat.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conBool() {
    bool compStatus = compileChecker("con/conBool.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conChar() {
    bool compStatus = compileChecker("con/conChar.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conString() {
    bool compStatus = compileChecker("con/conString.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("\"concatstring\"");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conMix() {
    bool compStatus = compileChecker("con/conMix.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}

void Test::conFuncResOne() {
    bool compStatus = compileChecker("con/conFuncResOne.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1, 2, 3, 4]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conFuncResTwo() {
    bool compStatus = compileChecker("con/conFuncResTwo.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgFail, compStatus);
    bool execStatus = executeChecker("[1, 2, 3, 4]");
    CPPUNIT_ASSERT_MESSAGE(execMsg, execStatus);
}

void Test::conEmpty() {
    bool compStatus = compileChecker("con/conEmpty.sppl");
    CPPUNIT_ASSERT_MESSAGE(compMsgSucc, !compStatus);
}<|endoftext|>


<commit_before>/***********************************************************************
 *    filename:   Element.cpp
 *    created:    28/10/2011
 *    author:     Martin Preisler
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include "CEGUI/Element.h"

#include <boost/test/unit_test.hpp>
#include <boost/timer.hpp>

BOOST_AUTO_TEST_SUITE(Element)

BOOST_AUTO_TEST_CASE(RelativeSizing)
{
    // in this test, everything is top left aligned

    CEGUI::Element* root = new CEGUI::Element();
    root->setSize(CEGUI::USize(100.0f * CEGUI::UDim::px(), 100 * CEGUI::UDim::px()));
    CEGUI::Element* child = new CEGUI::Element();
    child->setSize(CEGUI::USize(50.0f * CEGUI::UDim::percent(), 25.0f * CEGUI::UDim::percent()));
    root->addChild(child);

    BOOST_CHECK_EQUAL(root->getPixelSize(), CEGUI::Sizef(100.0f, 100.0f));
    BOOST_CHECK_EQUAL(child->getPixelSize(), CEGUI::Sizef(50.0f, 25.0f));

    CEGUI::Element* innerChild = new CEGUI::Element();
    child->addChild(innerChild);
    innerChild->setSize(CEGUI::USize(200.0f * CEGUI::UDim::percent(), 100.0f * CEGUI::UDim::percent()));
    BOOST_CHECK_EQUAL(innerChild->getPixelSize(), CEGUI::Sizef(100.0f, 25.0f));

    delete innerChild;
    delete child;
    delete root;
}

BOOST_AUTO_TEST_CASE(TopLeftAlignment)
{
    // in this test, everything is top left aligned

    CEGUI::Element* root = new CEGUI::Element();
    root->setSize(CEGUI::USize(100.0f * CEGUI::UDim::px(), 100 * CEGUI::UDim::px()));
    CEGUI::Element* child = new CEGUI::Element();
    child->setSize(CEGUI::USize(50.0f * CEGUI::UDim::px(), 25.0f * CEGUI::UDim::px()));
    root->addChild(child);

    // even though it is the default at the point of writing the test, we have to make sure this fact doesn't change!
    BOOST_CHECK_EQUAL(root->getHorizontalAlignment(), CEGUI::HA_LEFT);
    BOOST_CHECK_EQUAL(root->getVerticalAlignment(), CEGUI::VA_TOP);
    BOOST_CHECK_EQUAL(child->getHorizontalAlignment(), CEGUI::HA_LEFT);
    BOOST_CHECK_EQUAL(child->getVerticalAlignment(), CEGUI::VA_TOP);

    BOOST_CHECK_EQUAL(root->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 0, 100, 100));
    BOOST_CHECK_EQUAL(child->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 0, 50, 25));

    child->setPosition(CEGUI::UVector2(10.0f * CEGUI::UDim::px(), 5.0f * CEGUI::UDim::px()));

    BOOST_CHECK_EQUAL(child->getUnclippedOuterRect().get(), CEGUI::Rectf(10, 5, 60, 30));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Split Element top left alignment test case into 2<commit_after>/***********************************************************************
 *    filename:   Element.cpp
 *    created:    28/10/2011
 *    author:     Martin Preisler
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include "CEGUI/Element.h"

#include <boost/test/unit_test.hpp>
#include <boost/timer.hpp>

BOOST_AUTO_TEST_SUITE(Element)

BOOST_AUTO_TEST_CASE(RelativeSizing)
{
    // in this test, everything is top left aligned

    CEGUI::Element* root = new CEGUI::Element();
    root->setSize(CEGUI::USize(100.0f * CEGUI::UDim::px(), 100 * CEGUI::UDim::px()));
    CEGUI::Element* child = new CEGUI::Element();
    child->setSize(CEGUI::USize(50.0f * CEGUI::UDim::percent(), 25.0f * CEGUI::UDim::percent()));
    root->addChild(child);

    BOOST_CHECK_EQUAL(root->getPixelSize(), CEGUI::Sizef(100.0f, 100.0f));
    BOOST_CHECK_EQUAL(child->getPixelSize(), CEGUI::Sizef(50.0f, 25.0f));

    CEGUI::Element* innerChild = new CEGUI::Element();
    child->addChild(innerChild);
    innerChild->setSize(CEGUI::USize(200.0f * CEGUI::UDim::percent(), 100.0f * CEGUI::UDim::percent()));
    BOOST_CHECK_EQUAL(innerChild->getPixelSize(), CEGUI::Sizef(100.0f, 25.0f));

    delete innerChild;
    delete child;
    delete root;
}

BOOST_AUTO_TEST_CASE(LeftAlignment)
{
    // in this test, everything is top left aligned

    CEGUI::Element* root = new CEGUI::Element();
    root->setSize(CEGUI::USize(100.0f * CEGUI::UDim::px(), 0.0f * CEGUI::UDim::px()));
    CEGUI::Element* child = new CEGUI::Element();
    child->setSize(CEGUI::USize(50.0f * CEGUI::UDim::px(), 0.0f * CEGUI::UDim::px()));
    root->addChild(child);

    // even though it is the default at the point of writing the test, we have to make sure this fact doesn't change!
    BOOST_CHECK_EQUAL(root->getHorizontalAlignment(), CEGUI::HA_LEFT);
    BOOST_CHECK_EQUAL(child->getHorizontalAlignment(), CEGUI::HA_LEFT);

    BOOST_CHECK_EQUAL(root->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 0, 100, 0));
    BOOST_CHECK_EQUAL(child->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 0, 50, 0));

    child->setPosition(CEGUI::UVector2(10.0f * CEGUI::UDim::px(), 0.0f * CEGUI::UDim::px()));

    BOOST_CHECK_EQUAL(child->getUnclippedOuterRect().get(), CEGUI::Rectf(10, 0, 60, 0));
}

BOOST_AUTO_TEST_CASE(TopAlignment)
{
    // in this test, everything is top left aligned

    CEGUI::Element* root = new CEGUI::Element();
    root->setSize(CEGUI::USize(0.0f * CEGUI::UDim::px(), 100 * CEGUI::UDim::px()));
    CEGUI::Element* child = new CEGUI::Element();
    child->setSize(CEGUI::USize(0.0f * CEGUI::UDim::px(), 25.0f * CEGUI::UDim::px()));
    root->addChild(child);

    // even though it is the default at the point of writing the test, we have to make sure this fact doesn't change!
    BOOST_CHECK_EQUAL(root->getVerticalAlignment(), CEGUI::VA_TOP);
    BOOST_CHECK_EQUAL(child->getVerticalAlignment(), CEGUI::VA_TOP);

    BOOST_CHECK_EQUAL(root->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 0, 0, 100));
    BOOST_CHECK_EQUAL(child->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 0, 0, 25));

    child->setPosition(CEGUI::UVector2(0.0f * CEGUI::UDim::px(), 5.0f * CEGUI::UDim::px()));

    BOOST_CHECK_EQUAL(child->getUnclippedOuterRect().get(), CEGUI::Rectf(0, 5, 0, 30));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//===-- LibCxxList.cpp ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "LibCxx.h"

#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace {

    class ListEntry
    {
    public:
        ListEntry() = default;
        ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
        ListEntry(const ListEntry& rhs) = default;
        ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}

        ListEntry
        next ()
        {
            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildAtIndexPath({0,1}));
        }

        ListEntry
        prev ()
        {
            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildAtIndexPath({0,0}));
        }

        uint64_t
        value () const
        {
            if (!m_entry_sp)
                return 0;
            return m_entry_sp->GetValueAsUnsigned(0);
        }

        bool
        null()
        {
            return (value() == 0);
        }

        explicit operator bool ()
        {
            return GetEntry() && !null();
        }

        ValueObjectSP
        GetEntry ()
        {
            return m_entry_sp;
        }

        void
        SetEntry (ValueObjectSP entry)
        {
            m_entry_sp = entry;
        }

        bool
        operator == (const ListEntry& rhs) const
        {
            return value() == rhs.value();
        }

        bool
        operator != (const ListEntry& rhs) const
        {
            return !(*this == rhs);
        }

    private:
        ValueObjectSP m_entry_sp;
    };

    class ListIterator
    {
    public:
        ListIterator() = default;
        ListIterator (ListEntry entry) : m_entry(entry) {}
        ListIterator (ValueObjectSP entry) : m_entry(entry) {}
        ListIterator(const ListIterator& rhs) = default;
        ListIterator (ValueObject* entry) : m_entry(entry) {}

        ValueObjectSP
        value ()
        {
            return m_entry.GetEntry();
        }

        ValueObjectSP
        advance (size_t count)
        {
            if (count == 0)
                return m_entry.GetEntry();
            if (count == 1)
            {
                next ();
                return m_entry.GetEntry();
            }
            while (count > 0)
            {
                next ();
                count--;
                if (m_entry.null())
                    return lldb::ValueObjectSP();
            }
            return m_entry.GetEntry();
        }

        bool
        operator == (const ListIterator& rhs) const
        {
            return (rhs.m_entry == m_entry);
        }

    protected:
        void
        next ()
        {
            m_entry = m_entry.next();
        }

        void
        prev ()
        {
            m_entry = m_entry.prev();
        }

    private:
        ListEntry m_entry;
    };

} // end anonymous namespace

namespace lldb_private {
    namespace formatters {
        class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
        {
        public:
            LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

            ~LibcxxStdListSyntheticFrontEnd() override = default;

            size_t
            CalculateNumChildren() override;

            lldb::ValueObjectSP
            GetChildAtIndex(size_t idx) override;

            bool
            Update() override;

            bool
            MightHaveChildren() override;

            size_t
            GetIndexOfChildWithName(const ConstString &name) override;

        private:
            bool
            HasLoop(size_t count);

            size_t m_list_capping_size;
            static const bool g_use_loop_detect = true;

            size_t m_loop_detected; // The number of elements that have had loop detection run over them.
            ListEntry m_slow_runner; // Used for loop detection
            ListEntry m_fast_runner; // Used for loop detection

            lldb::addr_t m_node_address;
            ValueObject* m_head;
            ValueObject* m_tail;
            CompilerType m_element_type;
            size_t m_count;
            std::map<size_t, ListIterator> m_iterators;
        };
    } // namespace formatters
} // namespace lldb_private

lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    SyntheticChildrenFrontEnd(*valobj_sp),
    m_list_capping_size(0),
    m_loop_detected(0),
    m_node_address(),
    m_head(nullptr),
    m_tail(nullptr),
    m_element_type(),
    m_count(UINT32_MAX),
    m_iterators()
{
    if (valobj_sp)
        Update();
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count)
{
    if (!g_use_loop_detect)
        return false;
    // don't bother checking for a loop if we won't actually need to jump nodes
    if (m_count < 2)
        return false;

    if (m_loop_detected == 0)
    {
        // This is the first time we are being run (after the last update). Set up the loop
        // invariant for the first element.
        m_slow_runner = ListEntry(m_head).next();
        m_fast_runner = m_slow_runner.next();
        m_loop_detected = 1;
    }

    // Loop invariant:
    // Loop detection has been run over the first m_loop_detected elements. If m_slow_runner ==
    // m_fast_runner then the loop has been detected after m_loop_detected elements.
    const size_t steps_to_run = std::min(count,m_count);
    while (m_loop_detected < steps_to_run
            && m_slow_runner
            && m_fast_runner
            && m_slow_runner != m_fast_runner) {

        m_slow_runner = m_slow_runner.next();
        m_fast_runner = m_fast_runner.next().next();
        m_loop_detected++;
    }
    if (count <= m_loop_detected)
        return false; // No loop in the first m_loop_detected elements.
    if (!m_slow_runner || !m_fast_runner)
        return false; // Reached the end of the list. Definitely no loops.
    return m_slow_runner == m_fast_runner;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
{
    if (m_count != UINT32_MAX)
        return m_count;
    if (!m_head || !m_tail || m_node_address == 0)
        return 0;
    ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
    if (size_alloc)
    {
        ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
        if (first)
        {
            m_count = first->GetValueAsUnsigned(UINT32_MAX);
        }
    }
    if (m_count != UINT32_MAX)
    {
        return m_count;
    }
    else
    {
        uint64_t next_val = m_head->GetValueAsUnsigned(0);
        uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
        if (next_val == 0 || prev_val == 0)
            return 0;
        if (next_val == m_node_address)
            return 0;
        if (next_val == prev_val)
            return 1;
        uint64_t size = 2;
        ListEntry current(m_head);
        while (current.next() && current.next().value() != m_node_address)
        {
            size++;
            current = current.next();
            if (size > m_list_capping_size)
                break;
        }
        return m_count = (size-1);
    }
}

lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
    if (idx >= CalculateNumChildren())
        return lldb::ValueObjectSP();

    if (!m_head || !m_tail || m_node_address == 0)
        return lldb::ValueObjectSP();

    if (HasLoop(idx+1))
        return lldb::ValueObjectSP();

    size_t actual_advance = idx;

    ListIterator current(m_head);
    if (idx > 0)
    {
        auto cached_iterator = m_iterators.find(idx-1);
        if (cached_iterator != m_iterators.end())
        {
            current = cached_iterator->second;
            actual_advance = 1;
        }
    }

    ValueObjectSP current_sp(current.advance(actual_advance));
    if (!current_sp)
        return lldb::ValueObjectSP();

    m_iterators[idx] = current;

    current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
    if (!current_sp)
        return lldb::ValueObjectSP();
    // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
    DataExtractor data;
    Error error;
    current_sp->GetData(data, error);
    if (error.Fail())
        return lldb::ValueObjectSP();

    StreamString name;
    name.Printf("[%" PRIu64 "]", (uint64_t)idx);
    return CreateValueObjectFromData(name.GetData(),
                                     data,
                                     m_backend.GetExecutionContextRef(),
                                     m_element_type);
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
{
    m_iterators.clear();
    m_head = m_tail = nullptr;
    m_node_address = 0;
    m_count = UINT32_MAX;
    m_loop_detected = 0;
    m_slow_runner.SetEntry(nullptr);
    m_fast_runner.SetEntry(nullptr);

    Error err;
    ValueObjectSP backend_addr(m_backend.AddressOf(err));
    m_list_capping_size = 0;
    if (m_backend.GetTargetSP())
        m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
    if (m_list_capping_size == 0)
        m_list_capping_size = 255;
    if (err.Fail() || !backend_addr)
        return false;
    m_node_address = backend_addr->GetValueAsUnsigned(0);
    if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
        return false;
    ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
    if (!impl_sp)
        return false;
    CompilerType list_type = m_backend.GetCompilerType();
    if (list_type.IsReferenceType())
        list_type = list_type.GetNonReferenceType();

    if (list_type.GetNumTemplateArguments() == 0)
        return false;
    lldb::TemplateArgumentKind kind;
    m_element_type = list_type.GetTemplateArgument(0, kind);
    m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
    m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
    return false;
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
{
    return true;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
    return ExtractIndexFromString(name.GetCString());
}

SyntheticChildrenFrontEnd*
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
    return (valobj_sp ? new LibcxxStdListSyntheticFrontEnd(valobj_sp) : nullptr);
}
<commit_msg>Fix an issue where the libc++ std::list formatter wasn't recognizing the new memory layout correctly<commit_after>//===-- LibCxxList.cpp ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "LibCxx.h"

#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace {

    class ListEntry
    {
    public:
        ListEntry() = default;
        ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
        ListEntry(const ListEntry& rhs) = default;
        ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}

        ListEntry
        next ()
        {
            static ConstString g_next("__next_");

            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildMemberWithName(g_next, true));
        }

        ListEntry
        prev ()
        {
            static ConstString g_prev("__prev_");

            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildMemberWithName(g_prev, true));
        }

        uint64_t
        value () const
        {
            if (!m_entry_sp)
                return 0;
            return m_entry_sp->GetValueAsUnsigned(0);
        }

        bool
        null()
        {
            return (value() == 0);
        }

        explicit operator bool ()
        {
            return GetEntry() && !null();
        }

        ValueObjectSP
        GetEntry ()
        {
            return m_entry_sp;
        }

        void
        SetEntry (ValueObjectSP entry)
        {
            m_entry_sp = entry;
        }

        bool
        operator == (const ListEntry& rhs) const
        {
            return value() == rhs.value();
        }

        bool
        operator != (const ListEntry& rhs) const
        {
            return !(*this == rhs);
        }

    private:
        ValueObjectSP m_entry_sp;
    };

    class ListIterator
    {
    public:
        ListIterator() = default;
        ListIterator (ListEntry entry) : m_entry(entry) {}
        ListIterator (ValueObjectSP entry) : m_entry(entry) {}
        ListIterator(const ListIterator& rhs) = default;
        ListIterator (ValueObject* entry) : m_entry(entry) {}

        ValueObjectSP
        value ()
        {
            return m_entry.GetEntry();
        }

        ValueObjectSP
        advance (size_t count)
        {
            if (count == 0)
                return m_entry.GetEntry();
            if (count == 1)
            {
                next ();
                return m_entry.GetEntry();
            }
            while (count > 0)
            {
                next ();
                count--;
                if (m_entry.null())
                    return lldb::ValueObjectSP();
            }
            return m_entry.GetEntry();
        }

        bool
        operator == (const ListIterator& rhs) const
        {
            return (rhs.m_entry == m_entry);
        }

    protected:
        void
        next ()
        {
            m_entry = m_entry.next();
        }

        void
        prev ()
        {
            m_entry = m_entry.prev();
        }

    private:
        ListEntry m_entry;
    };

} // end anonymous namespace

namespace lldb_private {
    namespace formatters {
        class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
        {
        public:
            LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

            ~LibcxxStdListSyntheticFrontEnd() override = default;

            size_t
            CalculateNumChildren() override;

            lldb::ValueObjectSP
            GetChildAtIndex(size_t idx) override;

            bool
            Update() override;

            bool
            MightHaveChildren() override;

            size_t
            GetIndexOfChildWithName(const ConstString &name) override;

        private:
            bool
            HasLoop(size_t count);

            size_t m_list_capping_size;
            static const bool g_use_loop_detect = true;

            size_t m_loop_detected; // The number of elements that have had loop detection run over them.
            ListEntry m_slow_runner; // Used for loop detection
            ListEntry m_fast_runner; // Used for loop detection

            lldb::addr_t m_node_address;
            ValueObject* m_head;
            ValueObject* m_tail;
            CompilerType m_element_type;
            size_t m_count;
            std::map<size_t, ListIterator> m_iterators;
        };
    } // namespace formatters
} // namespace lldb_private

lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    SyntheticChildrenFrontEnd(*valobj_sp),
    m_list_capping_size(0),
    m_loop_detected(0),
    m_node_address(),
    m_head(nullptr),
    m_tail(nullptr),
    m_element_type(),
    m_count(UINT32_MAX),
    m_iterators()
{
    if (valobj_sp)
        Update();
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count)
{
    if (!g_use_loop_detect)
        return false;
    // don't bother checking for a loop if we won't actually need to jump nodes
    if (m_count < 2)
        return false;

    if (m_loop_detected == 0)
    {
        // This is the first time we are being run (after the last update). Set up the loop
        // invariant for the first element.
        m_slow_runner = ListEntry(m_head).next();
        m_fast_runner = m_slow_runner.next();
        m_loop_detected = 1;
    }

    // Loop invariant:
    // Loop detection has been run over the first m_loop_detected elements. If m_slow_runner ==
    // m_fast_runner then the loop has been detected after m_loop_detected elements.
    const size_t steps_to_run = std::min(count,m_count);
    while (m_loop_detected < steps_to_run
            && m_slow_runner
            && m_fast_runner
            && m_slow_runner != m_fast_runner) {

        m_slow_runner = m_slow_runner.next();
        m_fast_runner = m_fast_runner.next().next();
        m_loop_detected++;
    }
    if (count <= m_loop_detected)
        return false; // No loop in the first m_loop_detected elements.
    if (!m_slow_runner || !m_fast_runner)
        return false; // Reached the end of the list. Definitely no loops.
    return m_slow_runner == m_fast_runner;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
{
    if (m_count != UINT32_MAX)
        return m_count;
    if (!m_head || !m_tail || m_node_address == 0)
        return 0;
    ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
    if (size_alloc)
    {
        ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
        if (first)
        {
            m_count = first->GetValueAsUnsigned(UINT32_MAX);
        }
    }
    if (m_count != UINT32_MAX)
    {
        return m_count;
    }
    else
    {
        uint64_t next_val = m_head->GetValueAsUnsigned(0);
        uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
        if (next_val == 0 || prev_val == 0)
            return 0;
        if (next_val == m_node_address)
            return 0;
        if (next_val == prev_val)
            return 1;
        uint64_t size = 2;
        ListEntry current(m_head);
        while (current.next() && current.next().value() != m_node_address)
        {
            size++;
            current = current.next();
            if (size > m_list_capping_size)
                break;
        }
        return m_count = (size-1);
    }
}

lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
    static ConstString g_value("__value_");
    static ConstString g_next("__next_");

    if (idx >= CalculateNumChildren())
        return lldb::ValueObjectSP();

    if (!m_head || !m_tail || m_node_address == 0)
        return lldb::ValueObjectSP();

    if (HasLoop(idx+1))
        return lldb::ValueObjectSP();

    size_t actual_advance = idx;

    ListIterator current(m_head);
    if (idx > 0)
    {
        auto cached_iterator = m_iterators.find(idx-1);
        if (cached_iterator != m_iterators.end())
        {
            current = cached_iterator->second;
            actual_advance = 1;
        }
    }

    ValueObjectSP current_sp(current.advance(actual_advance));
    if (!current_sp)
        return lldb::ValueObjectSP();

    m_iterators[idx] = current;

    current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
    if (!current_sp)
        return lldb::ValueObjectSP();

    if (current_sp->GetName() == g_next)
    {
        ProcessSP process_sp(current_sp->GetProcessSP());
        if (!process_sp)
            return nullptr;

        // if we grabbed the __next_ pointer, then the child is one pointer deep-er
        lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
        addr = addr + 2*process_sp->GetAddressByteSize();
        ExecutionContext exe_ctx(process_sp);
        current_sp = CreateValueObjectFromAddress("__value_",
                                                  addr,
                                                  exe_ctx,
                                                  m_element_type);
    }

    // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
    DataExtractor data;
    Error error;
    current_sp->GetData(data, error);
    if (error.Fail())
        return lldb::ValueObjectSP();

    StreamString name;
    name.Printf("[%" PRIu64 "]", (uint64_t)idx);
    return CreateValueObjectFromData(name.GetData(),
                                     data,
                                     m_backend.GetExecutionContextRef(),
                                     m_element_type);
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
{
    m_iterators.clear();
    m_head = m_tail = nullptr;
    m_node_address = 0;
    m_count = UINT32_MAX;
    m_loop_detected = 0;
    m_slow_runner.SetEntry(nullptr);
    m_fast_runner.SetEntry(nullptr);

    Error err;
    ValueObjectSP backend_addr(m_backend.AddressOf(err));
    m_list_capping_size = 0;
    if (m_backend.GetTargetSP())
        m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
    if (m_list_capping_size == 0)
        m_list_capping_size = 255;
    if (err.Fail() || !backend_addr)
        return false;
    m_node_address = backend_addr->GetValueAsUnsigned(0);
    if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
        return false;
    ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
    if (!impl_sp)
        return false;
    CompilerType list_type = m_backend.GetCompilerType();
    if (list_type.IsReferenceType())
        list_type = list_type.GetNonReferenceType();

    if (list_type.GetNumTemplateArguments() == 0)
        return false;
    lldb::TemplateArgumentKind kind;
    m_element_type = list_type.GetTemplateArgument(0, kind);
    m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
    m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
    return false;
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
{
    return true;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
    return ExtractIndexFromString(name.GetCString());
}

SyntheticChildrenFrontEnd*
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
    return (valobj_sp ? new LibcxxStdListSyntheticFrontEnd(valobj_sp) : nullptr);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dlgexpor.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:36: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
 *
 ************************************************************************/

#ifndef _DLGEXPOR_HXX_
#define _DLGEXPOR_HXX_

#include "fltcall.hxx"
#include <vcl/dialog.hxx>
#include <vcl/button.hxx>
#include <vcl/fixed.hxx>
#include <vcl/field.hxx>
#include <vcl/lstbox.hxx>

/*************************************************************************
|*
|* Dialog zum Einstellen von Filteroptionen bei Pixelformaten
|*
\************************************************************************/

class FilterConfigItem;
class DlgExportPix : public ModalDialog
{
private:

    FltCallDialogParameter& rFltCallPara;

    OKButton            aBtnOK;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;

    ListBox             aLbColors;
    CheckBox            aCbxRLE;
    FixedLine           aGrpColors;

    RadioButton         aRbOriginal;
    RadioButton         aRbRes;
    RadioButton         aRbSize;
    FixedText           aFtSizeX;
    MetricField         aMtfSizeX;
    FixedText           aFtSizeY;
    MetricField         aMtfSizeY;
    FixedLine           aGrpMode;
    ComboBox            aCbbRes;

    FilterConfigItem*   pConfigItem;
    ResMgr*             pMgr;

    String              aExt;

                        DECL_LINK( OK, void* p );
                        DECL_LINK( ClickRbOriginal,void* p );
                        DECL_LINK( ClickRbRes,void* p );
                        DECL_LINK( ClickRbSize,void* p );
                        DECL_LINK( SelectLbColors, void* p );

public:
                        DlgExportPix( FltCallDialogParameter& rPara );
                        ~DlgExportPix();
};

/*************************************************************************
|*
|* Dialog zum Einstellen von Filteroptionen bei Vektorformaten
|*
\************************************************************************/
class DlgExportVec : public ModalDialog
{
private:

    FltCallDialogParameter& rFltCallPara;

    OKButton            aBtnOK;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;

    RadioButton         aRbOriginal;
    RadioButton         aRbSize;
    FixedLine           aGrpMode;

    FixedText           aFtSizeX;
    MetricField         aMtfSizeX;
    FixedText           aFtSizeY;
    MetricField         aMtfSizeY;
    FixedLine           aGrpSize;

    FilterConfigItem*   pConfigItem;
    ResMgr*             pMgr;

    String              aExt;

    DECL_LINK( OK, void* p );
    DECL_LINK( ClickRbOriginal,void* p );
    DECL_LINK( ClickRbSize,void* p );

public:
            DlgExportVec( FltCallDialogParameter& rPara );
            ~DlgExportVec();
};

#endif // _DLGEXPOR_HXX_

<commit_msg>INTEGRATION: CWS vgbugs07 (1.5.526); FILE MERGED 2007/06/04 13:31:37 vg 1.5.526.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dlgexpor.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 21:35:09 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _DLGEXPOR_HXX_
#define _DLGEXPOR_HXX_

#include <svtools/fltcall.hxx>
#include <vcl/dialog.hxx>
#include <vcl/button.hxx>
#include <vcl/fixed.hxx>
#include <vcl/field.hxx>
#include <vcl/lstbox.hxx>

/*************************************************************************
|*
|* Dialog zum Einstellen von Filteroptionen bei Pixelformaten
|*
\************************************************************************/

class FilterConfigItem;
class DlgExportPix : public ModalDialog
{
private:

    FltCallDialogParameter& rFltCallPara;

    OKButton            aBtnOK;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;

    ListBox             aLbColors;
    CheckBox            aCbxRLE;
    FixedLine           aGrpColors;

    RadioButton         aRbOriginal;
    RadioButton         aRbRes;
    RadioButton         aRbSize;
    FixedText           aFtSizeX;
    MetricField         aMtfSizeX;
    FixedText           aFtSizeY;
    MetricField         aMtfSizeY;
    FixedLine           aGrpMode;
    ComboBox            aCbbRes;

    FilterConfigItem*   pConfigItem;
    ResMgr*             pMgr;

    String              aExt;

                        DECL_LINK( OK, void* p );
                        DECL_LINK( ClickRbOriginal,void* p );
                        DECL_LINK( ClickRbRes,void* p );
                        DECL_LINK( ClickRbSize,void* p );
                        DECL_LINK( SelectLbColors, void* p );

public:
                        DlgExportPix( FltCallDialogParameter& rPara );
                        ~DlgExportPix();
};

/*************************************************************************
|*
|* Dialog zum Einstellen von Filteroptionen bei Vektorformaten
|*
\************************************************************************/
class DlgExportVec : public ModalDialog
{
private:

    FltCallDialogParameter& rFltCallPara;

    OKButton            aBtnOK;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;

    RadioButton         aRbOriginal;
    RadioButton         aRbSize;
    FixedLine           aGrpMode;

    FixedText           aFtSizeX;
    MetricField         aMtfSizeX;
    FixedText           aFtSizeY;
    MetricField         aMtfSizeY;
    FixedLine           aGrpSize;

    FilterConfigItem*   pConfigItem;
    ResMgr*             pMgr;

    String              aExt;

    DECL_LINK( OK, void* p );
    DECL_LINK( ClickRbOriginal,void* p );
    DECL_LINK( ClickRbSize,void* p );

public:
            DlgExportVec( FltCallDialogParameter& rPara );
            ~DlgExportVec();
};

#endif // _DLGEXPOR_HXX_

<|endoftext|>