diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d65ed7f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,31 @@ +sudo: false + +language: cpp + +compiler: + - clang + - gcc + +before_install: + - pip install --user cpp-coveralls + +install: + - if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi + - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi + - mkdir build + - cd build + - cmake .. + - make + +script: + - ctest -V + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - gcc-4.9 + - g++-4.9 + - clang-3.7 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cc23c9..7feb669 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,20 @@ -cmake_minimum_required(VERSION 3.3) -project(super_hot_strings) +cmake_minimum_required(VERSION 2.8) +project(CppLab2) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +if (MSVC) + add_definitions(/W4) +else() + add_definitions(-Wall) + add_definitions(-std=c++11) +endif() -set(SOURCE_FILES main.cpp) -add_executable(super_hot_strings ${SOURCE_FILES}) \ No newline at end of file +include_directories(Catch/include) +include_directories(include) + +enable_testing() + +set(SOURCES src/string.cpp) + +add_executable(test_string tests/test_string.cpp ${SOURCES}) + +add_test(NAME ${PROJECT_NAME} COMMAND test_string) \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..5bf4c60 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 sdukshis + +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 OR COPYRIGHT HOLDERS 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. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..2688db3 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Super Hot Strings for U and ME +[![Build Status](https://travis-ci.org/Waaazzzuuup/SHS.svg)](https://travis-ci.org/Waaazzzuuup/SHS) +[![Build status](https://ci.appveyor.com/api/projects/status/o79ympra1gx16ubn?svg=true)](https://ci.appveyor.com/project/Waaazzzuuup/shs) +----------------------------------- +# realisation of non-native strings \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..7ddbd3a --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,20 @@ +version: 1.0.{build} + +clone_folder: c:\dev\complex + +build: + +install: + - git submodule -q update --init --recursive + +build_script: + - cd c:\dev\complex + - md build + - cd build + - cmake .. + - cmake --build . --config debug + +after_build: + +test_script: + - cmd: ctest -C Debug -VV diff --git a/include/MyString.h b/include/MyString.h new file mode 100644 index 0000000..d8e2cd8 --- /dev/null +++ b/include/MyString.h @@ -0,0 +1,55 @@ +#ifndef CPP_STRING_H +#define CPP_STRING_H +//one definition rule + +class String { +private: + size_t length; //length of actual string, w/o EOL symvol + char * string; +public: + static char position; + String(); + String(const char *str); + String(const char *str, unsigned count); + String(char ch, unsigned count); + String(const String &other); + String(String &&other); + ~String(); + String & operator=(const String &other); + String & operator=(String &&other); + + String & operator+=(const String &suffix); + String & operator+=(const char *suffix); + String & operator+=(char suffix); + void swap(String &other); + char & operator[](size_t pos); + const char operator[](size_t pos) const; +/** +throws an exception if pos >= size() +*/ + char & at(size_t pos); + +/** +throws an exception if pos >= size() +*/ + const char at(size_t pos) const; +/** +/return pointer to '\0' terminated C-style string +*/ + const char * data() const; + size_t size() const; + friend bool operator==(const String &lhs, const String &rhs); + friend bool operator<(const String &lhs, const String &rhs); +}; +String operator+(const String &lhs, const String &rhs); +String operator+(const String &lhs, const char *rhs); +String operator+(const char *lhs, const String &rhs); +bool operator!=(const String &lhs, const String &rhs); +bool operator<=(const String &lhs, const String &rhs); +bool operator>(const String &lhs, const String &rhs); +bool operator>=(const String &lhs, const String &rhs); +#endif + + + + diff --git a/src/string.cpp b/src/string.cpp new file mode 100644 index 0000000..4d265e5 --- /dev/null +++ b/src/string.cpp @@ -0,0 +1,282 @@ +#include +#include +#include "MyString.h" + + +String::String() { + length = 0; + string = new char[1]; + string[0] = '\0'; +} + +String::String(const char *str) { + length = 0; + const char *temp = str; + while (*(temp++) != '\0') { + length++; + } + char *strCopy = new char[length + 1]; + for (std::size_t i = 0; i < length; i++) { + strCopy[i] = str[i]; + } + + string = strCopy; + string[length] = '\0'; +} + +//cut from beginning +String::String(const char *str, unsigned count) { + string = new char[count + 1]; + length = count; + for (std::size_t i = 0; i <= length; i++) { + string[i] = str[i]; + } +} + +//repeat symbol count times +String::String(char ch, unsigned count) { + length = count; + string = new char[length + 1]; + char *temp = string; + + for (std::size_t i = 0; i < length; ++i) { + *(temp++) = ch; + } + *(temp) = '\0'; + +} + +//copy constructor +String::String(const String &other) { + string = new char[other.length + 1]; + length = other.length; + for (size_t i = 0; i <= length; ++i) { + string[i] = other.string[i]; + } +} + + +String::String(String &&other) { + string = other.string; + length = other.length; + //other.string[0] = '\0'; //no magic + char nully = '\0'; + other.string = &(nully); //magic + other.length = 0; +} + + +String::~String() { + if (string[0] != '\0') { + delete[] string; + } +} + +//optize +String &String::operator=(const String &other) { + delete[] string; + string = new char[other.length + 1]; + length = other.length; + for (size_t i = 0; i < length; i++) { + string[i] = other.string[i]; + } + string[length] = '\0'; + return *this; +} + +String &String::operator=(String &&other) { + delete[] string; + string = other.string; + length = other.length; + + char nully = '\0'; + other.string = &(nully); //magic #2 + other.length = 0; + return *this; + +} + +String &String::operator+=(const String &suffix) { + char *concat = new char[length + suffix.length + 1]; + for (size_t i = 0; i < length; ++i) { + concat[i] = string[i]; + } + for (size_t j = length; j < length + suffix.length; ++j) { + concat[j] = suffix.string[j - length]; + } + concat[length + suffix.length] = '\0'; + delete[] string; + string = concat; + length += suffix.length; + + return *this; +} + +String &String::operator+=(const char *suffix) { + size_t suffixLength = 0; + const char *temp = suffix; + while (*(temp++) != '\0') { + suffixLength++; + } + + char *concat = new char[length + suffixLength + 1]; + for (size_t i = 0; i < length; ++i) { + concat[i] = string[i]; + } + for (size_t j = length; j < length + suffixLength; ++j) { + concat[j] = suffix[j - length]; + } + concat[length + suffixLength] = '\0'; + delete[] string; + string = concat; + length += suffixLength; + return *this; +} + +String &String::operator+=(char suffix) { + char *concat = new char[length + 2]; + for (size_t i = 0; i < length; ++i) { + concat[i] = string[i]; + } + concat[length] = suffix; + concat[length + 1] = '\0'; + delete[] string; + string = concat; + length++; + return *this; +} + +void String::swap(String &other) { + char *tmp; + size_t tmpLength; + tmp = string; + tmpLength = length; + string = other.string; + length = other.length; + other.string = tmp; + other.length = tmpLength; +} + +char &String::operator[](size_t pos) { + return string[pos]; +} + +const char String::operator[](size_t pos) const { + return string[pos]; +} + +char &String::at(size_t pos) { + if (pos >= length) { + throw std::out_of_range(""); + } + return string[pos]; +} + +//this is the same +const char String::at(size_t pos) const { + if (pos >= length) { + throw std::out_of_range(""); + } + return string[pos]; +} + +const char *String::data() const { + return string; +} + +size_t String::size() const { + return length; +} + +bool operator==(const String &lhs, const String &rhs) { + if (lhs.length == rhs.length) { + for (size_t i = 0; i < lhs.length; ++i) { + if (lhs.string[i] != rhs.string[i]) { + return false; + } + } + return true; + } + return false; +} + +bool operator<(const String &lhs, const String &rhs) { + size_t size; + size = lhs.length <= rhs.length ? lhs.length : rhs.length; + for (size_t i = 0; i < size; ++i) { + if (lhs.string[i] < rhs.string[i]) { + return true; + } else if (lhs.string[i] > rhs.string[i]) { + return false; + } + } + if (rhs.length > lhs.length) { + return true; + } + return false; +} + + +String operator+(const String &lhs, const String &rhs) { + String tmp(lhs); + tmp += rhs; + return tmp; +// return (String(lhs) += rhs); +} + +String operator+(const String &lhs, const char *rhs) { + return String(lhs) += rhs; +} + +String operator+(const char *lhs, const String &rhs) { + return String(rhs) += lhs; +} + +bool operator!=(const String &lhs, const String &rhs) { + return !(lhs == rhs); +} + +bool operator<=(const String &lhs, const String &rhs) { + return (lhs == rhs) || (lhs < rhs); +} + +bool operator>(const String &lhs, const String &rhs) { + return !(lhs <= rhs); +} + +bool operator>=(const String &lhs, const String &rhs) { + return !(lhs < rhs); +} + + +std::ostream &operator<<(std::ostream &stream, const String &A) { + return stream << A.data(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_string.cpp b/tests/test_string.cpp new file mode 100644 index 0000000..89a8e0e --- /dev/null +++ b/tests/test_string.cpp @@ -0,0 +1,252 @@ +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" +#include "MyString.h" + + + +TEST_CASE("TEST 1") { + String s; + REQUIRE(*(s.data()) == '\0'); + REQUIRE(s.size() == 0); +} + +TEST_CASE("TEST 2") { + char B[] = "Test2"; + String A(B); + const char *pt = A.data(); + REQUIRE(A.size() == 5); + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(B[i] == *(pt++)); + } +} + +TEST_CASE("TEST 3") { + char B[] = "Test3"; + String A(B, 5); + const char *pt = A.data(); + REQUIRE(A.size() == 5); + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(B[i] == *(pt++)); + } +} + +TEST_CASE("Test 4") { + char B = 'q'; + String A(B, 10); + const char *pt = A.data(); + REQUIRE(A.size() == 10); + for (unsigned i = 0; i < A.size(); ++i) { + REQUIRE(B == *(pt++)); + } + REQUIRE('\0' == *pt); +} + +TEST_CASE("Test5") { + String B("Test5"); + String A(B); + REQUIRE(A.size() == B.size()); + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(B[i] == A[i]); + } +} + +TEST_CASE("Test6") { + String B("Test6"); + String C(B); + String A(std::move(B)); + REQUIRE(A.size() == C.size()); + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(C[i] == A[i]); + } + REQUIRE(B.size() == 0); + REQUIRE(*(B.data()) == '\0'); +} + +TEST_CASE ("Test_assigment1") { + String A("Test_assigment1"); + String B, C; + C = B = A; + REQUIRE(A.size() == C.size()); + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(C[i] == A[i]); + } +} + +TEST_CASE ("Test_assigment2") { + String B("Test_assigment2"); + String C = B; + String A = std::move(B); + REQUIRE(A.size() == C.size()); + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(C[i] == A[i]); + } + REQUIRE(B.size() == 0); + REQUIRE(*(B.data()) == '\0'); +} + +TEST_CASE ("Test_plus_assigment_1") { + char res[] = "plus_assigment"; + String A("plus_"); + size_t Asize = A.size(); + String B("assigment"); + size_t Bsize = B.size(); + A += B; + REQUIRE(A.size() == (Asize + Bsize)); + for (size_t i = 0; i <= A.size(); ++i) { + REQUIRE(res[i] == A[i]); + } +} + +TEST_CASE ("Test_plus_assigment_2") { + char res[] = "plus_assigment"; + String C("plus_"); + size_t Csize = C.size(); + char A[] = "assigment"; + size_t Asize = 9; + String B("plus_"); + size_t Bsize = B.size(); + C += A; + B += "assigment"; + REQUIRE((Asize + Csize) == C.size()); + REQUIRE(B.size() == (Asize + Bsize)); + REQUIRE(B.size() == C.size()); + for (size_t i = 0; i <= C.size(); ++i) { + REQUIRE(res[i] == C[i]); + REQUIRE(res[i] == B[i]); + } +} + +TEST_CASE ("Test_plus_assigment_3") { + char res[] = "plus_"; + String C("plus"); + size_t Csize = C.size(); + char A = '_'; + size_t Asize = 1; + String B("plus"); + size_t Bsize = B.size(); + C += A; + B += '_'; + REQUIRE((Asize + Csize) == C.size()); + REQUIRE(B.size() == (Asize + Bsize)); + REQUIRE(B.size() == C.size()); + for (size_t i = 0; i <= B.size(); ++i) { + REQUIRE(res[i] == C[i]); + REQUIRE(res[i] == B[i]); + } +} + +TEST_CASE ("Test_index") { + String A("Test"); + A[1] = 'a'; + char res[] = "Tast"; + for (unsigned i = 0; i <= A.size(); ++i) { + REQUIRE(res[i] == A[i]); + } +} + +TEST_CASE ("Test_swap") { + char res1[] = "hgf"; + char res2[] = "lkjhgf"; + String A(res1); + String B(res2); + size_t Asize = A.size(); + size_t Bsize = B.size(); + A.swap(B); + REQUIRE(Bsize == A.size()); + REQUIRE(Asize == B.size()); + for (size_t i = 0; i <= A.size(); ++i) { + REQUIRE(res2[i] == A[i]); + } + for (size_t i = 0; i <= B.size(); ++i) { + REQUIRE(res1[i] == B[i]); + } +} + +TEST_CASE ("Test_at") { + const String A("Test_at"); + REQUIRE(A.at(3) == 't'); + REQUIRE_THROWS(A.at(10)); +} + +TEST_CASE ("Test_equality") { + String A("Test"); + String B(A); + REQUIRE(A.size() == B.size()); + for (size_t i = 0; i < A.size(); ++i) { + REQUIRE(A[i] == B[i]); + } +} + +TEST_CASE ("Test_less") { + String A("Test"); + String B(A); + REQUIRE_FALSE(A < B); + B += "er"; + REQUIRE(A < B); + A+="aa"; + REQUIRE(A < B); +} + +TEST_CASE ("Test_plus_1") { + String A("Test_"); + String B("plus_1"); + String C; + String res("Test_plus_1"); + + C = A + B; + A = A + B; + REQUIRE(C == res); + REQUIRE(A == res); +} + +TEST_CASE ("Test_plus_2") { + String A("Test_"); + char B[] = "plus_1"; + String C; + String res("Test_plus_1"); + C = A + B; + A = A + B; + REQUIRE(C == res); + REQUIRE(A == res); +} + +TEST_CASE ("Test_plus_3") { + String A("Test_"); + char * B = "plus_1"; + String C; + String res("Test_plus_1"); + C = B + A; + A = B + A; + REQUIRE(C == res); + REQUIRE(A == res); +} + +TEST_CASE ("Test_not_equality") { + String A("kjh"); + String B("hgh"); + REQUIRE(!(A == B)); +} + +TEST_CASE ("Test_less_equality") { + String A("less"); + String B("equality"); + String C("less"); + REQUIRE(((B <= A) && (A <= C))); + +} + +TEST_CASE ("Test_more") { + String A("more"); + String B("aaaaa"); + REQUIRE(A > B); + +} + +TEST_CASE ("Test_more_equality") { + String A("more"); + String B("more"); + String C("equality"); + REQUIRE(((B >= A) && (A >= C))); + +}